diff --git a/Cargo.lock b/Cargo.lock index 58d83d8900..2ecb03b907 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "array-bytes" -version = "1.1.0" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d709a11595cecbc902e04927043d6b472a13f65fe3c47bfb89a6d3a7b0a9d5b5" +checksum = "b76542acb2b0012e8bbdc5c6ec96a164b30e1f3aa06fdb17dc86515817ca2776" [[package]] name = "arrayref" @@ -957,8 +957,8 @@ dependencies = [ [[package]] name = "ckb-merkle-mountain-range" -version = "0.3.0" -source = "git+https://github.com/darwinia-network/merkle-mountain-range.git#6ab7d95f407aa345e8f7fd6681a127609ad50e5a" +version = "0.3.1" +source = "git+https://github.com/darwinia-network/merkle-mountain-range.git#b16216f90e3ff143114a9966330b8b42c33a28c5" dependencies = [ "cfg-if 0.1.10", ] @@ -1849,12 +1849,14 @@ dependencies = [ "frame-system", "log", "parity-scale-codec", + "rand 0.8.4", "serde", "serde_json", "sp-core", "sp-io", "sp-runtime", "sp-std", + "sp-tracing", ] [[package]] @@ -1889,15 +1891,18 @@ version = "2.4.0" dependencies = [ "array-bytes", "darwinia-balances", + "darwinia-header-mmr", "darwinia-relay-primitives", "darwinia-support", "frame-support", "frame-system", + "log", "parity-scale-codec", "sp-core", "sp-io", "sp-runtime", "sp-std", + "sp-tracing", ] [[package]] @@ -2294,7 +2299,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "pangolin-runtime", "parity-scale-codec", - "rand 0.8.3", + "rand 0.8.4", "sc-authority-discovery", "sc-basic-authorship", "sc-chain-spec", @@ -2834,7 +2839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" dependencies = [ "byteorder", - "rand 0.8.3", + "rand 0.8.4", "rustc-hex", "static_assertions", ] @@ -4387,7 +4392,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "rand 0.8.3", + "rand 0.8.4", "smallvec 1.6.1", "socket2 0.4.0", "void", @@ -4846,7 +4851,7 @@ dependencies = [ "hashbrown", "hex", "keccak-hash", - "rand 0.8.3", + "rand 0.8.4", "rlp", "sp-std", "uuid", @@ -5850,9 +5855,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495197c078e54b8735181aa35c00a327f7f3a3cc00a1ee8c95926dd010f0ec6b" +checksum = "2e337f62db341435f0da05b8f6b97e984ef4ea5800510cd07c2d624688c40b47" dependencies = [ "blake2-rfc", "crc32fast", @@ -5862,7 +5867,7 @@ dependencies = [ "log", "memmap2", "parking_lot 0.11.1", - "rand 0.8.3", + "rand 0.8.4", ] [[package]] @@ -6513,9 +6518,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha 0.3.0", @@ -9130,7 +9135,7 @@ dependencies = [ "byteorder", "crunchy", "lazy_static", - "rand 0.8.3", + "rand 0.8.4", "rustc-hex", ] @@ -9285,7 +9290,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall 0.2.8", "remove_dir_all", "winapi 0.3.9", @@ -9847,7 +9852,7 @@ dependencies = [ "ipnet", "lazy_static", "log", - "rand 0.8.3", + "rand 0.8.4", "smallvec 1.6.1", "thiserror", "tinyvec", @@ -10627,7 +10632,7 @@ dependencies = [ "log", "nohash-hasher", "parking_lot 0.11.1", - "rand 0.8.3", + "rand 0.8.4", "static_assertions", ] diff --git a/bin/node/runtime/pangolin/polkadot-compatible-types.json b/bin/node/runtime/pangolin/polkadot-compatible-types.json index a57032e421..6dda2ec8ce 100644 --- a/bin/node/runtime/pangolin/polkadot-compatible-types.json +++ b/bin/node/runtime/pangolin/polkadot-compatible-types.json @@ -195,10 +195,16 @@ }, "AddressT": "[u8; 20; AddressT]", "__[pallet.header-mmr]__": {}, + "NodeIndex": "u64", "MerkleMountainRangeRootLog": { "prefix": "[u8; 4; Prefix]", "parent_mmr_root": "Hash" }, + "MmrNodesPruningConfiguration": { + "step": "NodeIndex", + "progress": "NodeIndex", + "last_position": "NodeIndex" + }, "__[primitives.relay]__": {}, "OpCode": "[u8; 4; OpCode]", "Term": "u32", @@ -223,7 +229,7 @@ }, "RelayAuthorityT": { "account_id": "AccountId", - "signer": "Signer", + "signer": "EthereumAddress", "stake": "Balance", "term": "BlockNumber" }, @@ -231,6 +237,10 @@ "next_authorities": "Vec", "deadline": "BlockNumber" }, + "MmrRootToSign": { + "mmr_root": "Hash", + "signatures": "Vec<(EthereumAddress, EcdsaSignature)>" + }, "MMRRoot": "Hash", "__[pangolin.runtime]__": { "ProxyType": { diff --git a/bin/node/runtime/pangolin/src/lib.rs b/bin/node/runtime/pangolin/src/lib.rs index 29c88f8ae7..88a3a656c0 100644 --- a/bin/node/runtime/pangolin/src/lib.rs +++ b/bin/node/runtime/pangolin/src/lib.rs @@ -628,7 +628,7 @@ impl_runtime_apis! { block_number_of_member_leaf: u64, block_number_of_last_leaf: u64 ) -> HeaderMMRRuntimeDispatchInfo { - HeaderMMR::gen_proof_rpc(block_number_of_member_leaf, block_number_of_last_leaf ) + HeaderMMR::gen_proof_rpc(block_number_of_member_leaf, block_number_of_last_leaf) } } @@ -848,6 +848,11 @@ pub struct CustomOnRuntimeUpgrade; impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result<(), &'static str> { + // <--- Hack for local test + use frame_support::traits::Currency; + let _ = Ring::deposit_creating(&BridgeMillauMessages::relayer_fund_account_id(), 1 << 50); + // ---> + Ok(()) } diff --git a/bin/node/runtime/pangolin/src/pallets/header_mmr.rs b/bin/node/runtime/pangolin/src/pallets/header_mmr.rs index 84ff96edcf..516a9700f3 100644 --- a/bin/node/runtime/pangolin/src/pallets/header_mmr.rs +++ b/bin/node/runtime/pangolin/src/pallets/header_mmr.rs @@ -2,4 +2,8 @@ use crate::*; use darwinia_header_mmr::Config; -impl Config for Runtime {} +impl Config for Runtime { + type WeightInfo = (); + + const INDEXING_PREFIX: &'static [u8] = b"header-mmr-"; +} diff --git a/bin/node/runtime/pangolin/types.json b/bin/node/runtime/pangolin/types.json index e5a3381a62..08f58db54a 100644 --- a/bin/node/runtime/pangolin/types.json +++ b/bin/node/runtime/pangolin/types.json @@ -187,10 +187,16 @@ }, "AddressT": "[u8; 20; AddressT]", "__[pallet.header-mmr]__": {}, + "NodeIndex": "u64", "MerkleMountainRangeRootLog": { "prefix": "[u8; 4; Prefix]", "parent_mmr_root": "Hash" }, + "MmrNodesPruningConfiguration": { + "step": "NodeIndex", + "progress": "NodeIndex", + "last_position": "NodeIndex" + }, "__[primitives.relay]__": {}, "OpCode": "[u8; 4; OpCode]", "Term": "u32", @@ -215,7 +221,7 @@ }, "RelayAuthorityT": { "account_id": "AccountId", - "signer": "Signer", + "signer": "EthereumAddress", "stake": "Balance", "term": "BlockNumber" }, @@ -223,6 +229,10 @@ "next_authorities": "Vec", "deadline": "BlockNumber" }, + "MmrRootToSign": { + "mmr_root": "Hash", + "signatures": "Vec<(EthereumAddress, EcdsaSignature)>" + }, "MMRRoot": "Hash", "__[pangolin.runtime]__": { "ProxyType": { diff --git a/frame/bridge/ethereum/backing/src/lib.rs b/frame/bridge/ethereum/backing/src/lib.rs index 8f43b0c715..0d941ebc9f 100644 --- a/frame/bridge/ethereum/backing/src/lib.rs +++ b/frame/bridge/ethereum/backing/src/lib.rs @@ -411,7 +411,7 @@ pub mod pallet { (>::block_number().saturated_into::() / 10 * 10 + 10) .saturated_into(), - ); + )?; } Ok(().into()) diff --git a/frame/bridge/ethereum/backing/src/mock.rs b/frame/bridge/ethereum/backing/src/mock.rs index 21c8e4ae76..719d3c7ca0 100644 --- a/frame/bridge/ethereum/backing/src/mock.rs +++ b/frame/bridge/ethereum/backing/src/mock.rs @@ -186,7 +186,9 @@ macro_rules! decl_tests { impl RelayAuthorityProtocol for EcdsaAuthorities { type Signer = EthereumAddress; - fn schedule_mmr_root(_: BlockNumber) {} + fn schedule_mmr_root(_: BlockNumber) -> DispatchResult { + Ok(()) + } fn check_authorities_change_to_sync(_: Term, _: Vec) -> DispatchResult { Ok(()) diff --git a/frame/bridge/relay-authorities/Cargo.toml b/frame/bridge/relay-authorities/Cargo.toml index 32f819a1b3..749860574e 100644 --- a/frame/bridge/relay-authorities/Cargo.toml +++ b/frame/bridge/relay-authorities/Cargo.toml @@ -12,6 +12,7 @@ version = "2.4.0" [dependencies] # crates codec = { package = "parity-scale-codec", version = "2.1.1", default-features = false, features = ["derive"] } +log = { version = "0.4.14" } # darwinia darwinia-relay-primitives = { default-features = false, path = "../../../primitives/relay" } darwinia-support = { default-features = false, path = "../../support" } @@ -25,11 +26,13 @@ sp-std = { default-features = false, git = "https://github.com/darwinia-n # crates array-bytes = { version = "1.1.0" } # darwinia -darwinia-balances = { path = "../../balances" } -darwinia-support = { path = "../../support" } +darwinia-balances = { path = "../../balances" } +darwinia-header-mmr = { features = ["easy-testing"], path = "../../header-mmr" } +darwinia-support = { path = "../../support" } # substrate -sp-core = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } -sp-io = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +sp-core = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +sp-io = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +sp-tracing = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } [features] default = ["std"] @@ -40,10 +43,10 @@ std = [ "substrate-std", ] -crates-std = [ +crates-std = [ "codec/std", ] -darwinia-std = [ +darwinia-std = [ "darwinia-relay-primitives/std", "darwinia-support/std", ] diff --git a/frame/bridge/relay-authorities/src/lib.rs b/frame/bridge/relay-authorities/src/lib.rs index ff5ae76eb5..ebb1197404 100644 --- a/frame/bridge/relay-authorities/src/lib.rs +++ b/frame/bridge/relay-authorities/src/lib.rs @@ -21,9 +21,18 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod weights; -// --- darwinia --- pub use weights::WeightInfo; +pub mod migration { + pub fn migrate(module: &[u8]) { + // --- paritytech --- + use frame_support::migration; + + migration::remove_storage_prefix(module, b"MMRRootsToSign", &[]); + migration::remove_storage_prefix(module, b"MMRRootsToSignKeys", &[]); + } +} + #[cfg(test)] mod mock; #[cfg(test)] @@ -63,7 +72,7 @@ use frame_support::{ weights::Weight, StorageValue, }; -use frame_system::ensure_signed; +use frame_system::{ensure_signed, pallet_prelude::*}; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, DispatchResult, Perbill, SaturatedConversion, @@ -76,6 +85,8 @@ use darwinia_relay_primitives::relay_authorities::*; use darwinia_support::balance::*; use types::*; +pub const MAX_SCHEDULED_NUM: usize = 10; + pub trait Config: frame_system::Config { type Event: From> + Into<::Event>; type RingCurrency: LockableCurrency; @@ -135,10 +146,10 @@ decl_error! { StakeIns, /// On Authorities Change - DISABLED OnAuthoritiesChangeDis, + /// Scheduled Items - TOO MANY + ScheduledTM, /// Scheduled Sign -NOT EXISTED ScheduledSignNE, - /// Darwinia MMR Root - NOT READY YET - DarwiniaMMRRootNRY, /// Signature - INVALID SignatureInv, /// Term - MISMATCHED @@ -185,10 +196,10 @@ decl_storage! { get(fn authorities_to_sign) : Option<(RelayAuthorityMessage, Vec<(AccountId, RelayAuthoritySignature)>)>; - /// The `MMRRootsToSign` keys cache + /// The `MmrRootsToSign` keys cache /// - /// Only use for update the `MMRRootsToSign` once the authorities changed - pub MMRRootsToSignKeys get(fn mmr_root_to_sign_keys): Vec>; + /// Only use for update the `MmrRootsToSign` once the authorities changed + pub MmrRootsToSignKeys get(fn mmr_root_to_sign_keys): Vec>; /// All the relay requirements from the backing module here /// @@ -198,10 +209,10 @@ decl_storage! { /// /// Params /// 1. collected signatures - pub MMRRootsToSign + pub MmrRootsToSign get(fn mmr_root_to_sign_of) - : map hasher(identity) BlockNumber - => Option, RelayAuthoritySignature)>>; + : map hasher(identity) BlockNumberFor + => Option, AccountId, RelayAuthoritySignature>>; /// The mmr root signature submit duration, will be delayed if on authorities change pub SubmitDuration get(fn submit_duration): BlockNumber = T::SubmitDuration::get(); @@ -252,7 +263,8 @@ decl_module! { fn deposit_event() = default; // Deal with the slash thing. If authority didn't do his job before the deadline - fn on_initialize(now: BlockNumber) -> Weight { + fn on_initialize(now: BlockNumberFor) -> Weight { + Self::prepare_mmr_root_to_sign(now); Self::check_misbehavior(now); 0 @@ -457,11 +469,11 @@ decl_module! { // Not allow to submit during the authority set change ensure!(!Self::on_authorities_change(), >::OnAuthoritiesChangeDis); - let mut signatures = - >::get(block_number).ok_or(>::ScheduledSignNE)?; + let mut to_sign = + >::get(block_number).ok_or(>::ScheduledSignNE)?; // No-op if was already submitted - if signatures.iter().position(|(authority_, _)| authority_ == &authority).is_some() { + if to_sign.signatures.iter().position(|(signer, _)| signer == &authority).is_some() { return Ok(()); } @@ -470,8 +482,6 @@ decl_module! { &authorities, &authority ).ok_or(>::AuthorityNE)?; - let mmr_root = - T::DarwiniaMMR::get_root(block_number).ok_or(>::DarwiniaMMRRootNRY)?; // The message is composed of: // @@ -488,7 +498,7 @@ decl_module! { _1: T::Version::get().spec_name, _2: T::OpCodes::get().0, _3: block_number, - _4: mmr_root + _4: to_sign.mmr_root } .encode() ); @@ -498,17 +508,17 @@ decl_module! { >::SignatureInv ); - signatures.push((authority, signature)); + to_sign.signatures.push((authority, signature)); - if Perbill::from_rational(signatures.len() as u32, authorities.len() as _) + if Perbill::from_rational(to_sign.signatures.len() as u32, authorities.len() as _) >= T::SignThreshold::get() { // TODO: clean the mmr root which was contains in this mmr root? Self::mmr_root_signed(block_number); - Self::deposit_event(RawEvent::MMRRootSigned(block_number, mmr_root, signatures)); + Self::deposit_event(RawEvent::MMRRootSigned(block_number, to_sign.mmr_root, to_sign.signatures)); } else { - >::insert(block_number, signatures); + >::insert(block_number, to_sign); } } @@ -586,12 +596,12 @@ decl_module! { >::kill(); >::kill(); { - >::remove_all(); + >::remove_all(); let schedule = ( >::block_number().saturated_into::() / 10 * 10 + 10 ).saturated_into(); - >::mutate(|schedules| *schedules = vec![schedule]); - Self::schedule_mmr_root(schedule); + >::mutate(|schedules| *schedules = vec![schedule]); + Self::schedule_mmr_root(schedule)?; } >::kill(); } @@ -658,17 +668,18 @@ where } // TODO: optimize DB R/W, but it's ok in real case, since the set won't grow so large - for key in >::get() { - if let Some(mut signatures) = >::get(key) { + for key in >::get() { + if let Some(mut mmr_root_to_sign) = >::get(key) { for account_id in &remove_authorities { - if let Some(position) = signatures + if let Some(position) = mmr_root_to_sign + .signatures .iter() .position(|(authority, _)| &authority == account_id) { - signatures.remove(position); + mmr_root_to_sign.signatures.remove(position); } - >::insert(key, &signatures); + >::insert(key, &mmr_root_to_sign); } } else { // Should never enter this condition @@ -750,9 +761,45 @@ where Ok(()) } - pub fn mmr_root_signed(block_number: BlockNumber) { - >::remove(block_number); - >::mutate(|mmr_roots_to_sign_keys| { + pub fn prepare_mmr_root_to_sign(block_number: BlockNumberFor) { + if let Some(schedule) = >::get() + .into_iter() + // In order to get the schedule block number's MMR root + // 1. MMR root doesn't contain itself(header hash) + // 1. MMR's state change on finalize + // That's why we need to plus `2` to the scheduled block number + .find(|schedule| *schedule + 2_u32.into() == block_number) + { + if let Some(mmr_root) = T::DarwiniaMMR::get_root() { + let _ = >::try_mutate(schedule, |maybe_mmr_root_to_sign| { + if maybe_mmr_root_to_sign.is_none() { + *maybe_mmr_root_to_sign = Some(MmrRootToSign::new(mmr_root)); + + log::trace!( + "Success to `prepare_mmr_root_to_sign` `{:?}` for block `{:?}` at block `{:?}`", + mmr_root, + schedule, + block_number + ); + + Ok(()) + } else { + Err(()) + } + }); + } else { + log::error!( + "Failed to `get_root` while `prepare_mmr_root_to_sign` for block `{:?}` at block `{:?}`", + schedule, + block_number + ); + } + } + } + + pub fn mmr_root_signed(block_number: BlockNumberFor) { + >::remove(block_number); + >::mutate(|mmr_roots_to_sign_keys| { if let Some(position) = mmr_roots_to_sign_keys .iter() .position(|key| key == &block_number) @@ -824,8 +871,8 @@ where } else { let at = now.saturating_sub(>::get()); - if let Some(signatures) = >::take(at) { - let _ = >::try_mutate(|keys| { + if let Some(mmr_root_to_sign) = >::take(at) { + let _ = >::try_mutate(|keys| { if let Some(position) = keys.iter().position(|key| key == &at) { keys.remove(position); @@ -835,7 +882,7 @@ where } }); - find_and_slash_misbehavior(signatures); + find_and_slash_misbehavior(mmr_root_to_sign.signatures); // TODO: schedule a new mmr root (greatest one in the keys) } @@ -850,21 +897,31 @@ where { type Signer = RelayAuthoritySigner; - fn schedule_mmr_root(block_number: BlockNumber) { - let _ = >::try_mutate(block_number, |signed_mmr_root| { + fn schedule_mmr_root(block_number: BlockNumberFor) -> DispatchResult { + if >::exists() { + if let Some(scheduled_num) = >::decode_len() { + if scheduled_num > MAX_SCHEDULED_NUM { + Err(>::ScheduledTM)?; + } + } else { + Err("Failed to get `decode_len`")?; + } + } + + let _ = >::try_mutate(|mmr_roots_to_sign_keys| { // No-op if the sign was already scheduled - if signed_mmr_root.is_some() { + if mmr_roots_to_sign_keys.contains(&block_number) { return Err(()); } - >::append(block_number); - - *signed_mmr_root = Some(, RelayAuthoritySignature)>>::new()); + mmr_roots_to_sign_keys.push(block_number); Self::deposit_event(RawEvent::ScheduleMMRRoot(block_number)); Ok(()) }); + + Ok(()) } fn check_authorities_change_to_sync( diff --git a/frame/bridge/relay-authorities/src/mock.rs b/frame/bridge/relay-authorities/src/mock.rs index c86facf3ee..6999674bad 100644 --- a/frame/bridge/relay-authorities/src/mock.rs +++ b/frame/bridge/relay-authorities/src/mock.rs @@ -21,7 +21,7 @@ // --- crates --- use codec::{Decode, Encode}; // --- substrate --- -use frame_support::traits::{GenesisBuild, OnInitialize}; +use frame_support::traits::{GenesisBuild, OnFinalize, OnInitialize}; use frame_system::{mocking::*, EnsureRoot}; use sp_core::H256; use sp_io::{hashing, TestExternalities}; @@ -37,6 +37,7 @@ use darwinia_relay_primitives::relay_authorities::Sign as SignT; pub type Block = MockBlock; pub type UncheckedExtrinsic = MockUncheckedExtrinsic; +pub type Hash = H256; pub type BlockNumber = u64; pub type AccountId = u64; pub type Index = u64; @@ -44,7 +45,6 @@ pub type Balance = u128; pub type RelayAuthoritiesError = Error; -pub const DEFAULT_MMR_ROOT: H256 = H256([0; 32]); pub const DEFAULT_SIGNATURE: [u8; 65] = [0; 65]; darwinia_support::impl_test_account_data! {} @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type Call = Call; type Index = Index; type BlockNumber = BlockNumber; - type Hash = H256; + type Hash = Hash; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; @@ -90,12 +90,12 @@ impl darwinia_balances::Config for Test { type WeightInfo = (); } -pub struct DarwiniaMMR; -impl MMR for DarwiniaMMR { - fn get_root(_: BlockNumber) -> Option { - Some(Default::default()) - } +impl darwinia_header_mmr::Config for Test { + type WeightInfo = (); + + const INDEXING_PREFIX: &'static [u8] = b""; } + pub struct Sign; impl SignT for Sign { type Signature = [u8; 65]; @@ -126,7 +126,7 @@ impl Config for Test { type AddOrigin = EnsureRoot; type RemoveOrigin = EnsureRoot; type ResetOrigin = EnsureRoot; - type DarwiniaMMR = DarwiniaMMR; + type DarwiniaMMR = HeaderMmr; type Sign = Sign; type OpCodes = (); type SignThreshold = SignThreshold; @@ -143,11 +143,14 @@ frame_support::construct_runtime! { { System: frame_system::{Pallet, Call, Storage, Config, Event}, Ring: darwinia_balances::::{Pallet, Call, Storage, Config, Event}, + HeaderMmr: darwinia_header_mmr::{Pallet, Call, Storage}, RelayAuthorities: darwinia_relay_authorities::{Pallet, Call, Storage, Config, Event} } } pub fn new_test_ext() -> TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = frame_system::GenesisConfig::default() .build_storage::() .unwrap(); @@ -176,6 +179,27 @@ pub fn run_to_block(n: BlockNumber) { } } +pub fn run_to_block_from_genesis(n: BlockNumber) -> Vec
{ + let mut headers = vec![>::finalize()]; + + for block_number in 1..=n { + System::set_block_number(block_number); + + >::initialize( + &block_number, + &headers[headers.len() - 1].hash(), + &Default::default(), + Default::default(), + ); + RelayAuthorities::on_initialize(block_number); + HeaderMmr::on_finalize(block_number); + + headers.push(>::finalize()); + } + + headers +} + pub fn events() -> Vec { let events = System::events() .into_iter() diff --git a/frame/bridge/relay-authorities/src/test.rs b/frame/bridge/relay-authorities/src/test.rs index 2d58d91f86..eec46c74dc 100644 --- a/frame/bridge/relay-authorities/src/test.rs +++ b/frame/bridge/relay-authorities/src/test.rs @@ -17,7 +17,7 @@ // along with Darwinia. If not, see . // --- substrate --- -use frame_support::{assert_err, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok}; // --- darwinia --- use crate::{ mock::{AccountId, BlockNumber, Event, SubmitDuration, *}, @@ -322,6 +322,7 @@ fn authority_term_should_work() { } #[test] +#[ignore] fn encode_message_should_work() { // --- substrate --- use sp_runtime::RuntimeString; @@ -372,46 +373,64 @@ fn encode_message_should_work() { } #[test] -fn mmr_root_signed_event_should_work() { +fn schedule_too_many_should_fail() { new_test_ext().execute_with(|| { - run_to_block(1); - - assert_ok!(request_authority(1)); - assert_ok!(RelayAuthorities::add_authorities(Origin::root(), vec![1])); - assert_ok!(RelayAuthorities::submit_signed_authorities( - Origin::signed(9), - DEFAULT_SIGNATURE - )); + let max_scheduled_num = MAX_SCHEDULED_NUM as BlockNumber; - RelayAuthorities::apply_authorities_change().unwrap(); - RelayAuthorities::sync_authorities_change().unwrap(); - System::reset_events(); - - RelayAuthorities::schedule_mmr_root(10); - System::reset_events(); + for block_number in 0..=max_scheduled_num { + assert_ok!(RelayAuthorities::schedule_mmr_root(block_number)); + } - assert_ok!(RelayAuthorities::submit_signed_mmr_root( - Origin::signed(9), - 10, - DEFAULT_SIGNATURE, - )); - assert!(relay_authorities_events().is_empty()); - assert_ok!(RelayAuthorities::submit_signed_mmr_root( - Origin::signed(1), - 10, - DEFAULT_SIGNATURE, - )); - assert_eq!( - relay_authorities_events(), - vec![Event::darwinia_relay_authorities(RawEvent::MMRRootSigned( - 10, - DEFAULT_MMR_ROOT, - vec![(9, DEFAULT_SIGNATURE), (1, DEFAULT_SIGNATURE)] - ))] + assert_noop!( + RelayAuthorities::schedule_mmr_root(max_scheduled_num + 1), + RelayAuthoritiesError::ScheduledTM ); }); } +#[test] +fn schedule_mmr_root_and_mmr_root_signed_event_should_work() { + for block_number in 4..25 { + new_test_ext().execute_with(|| { + assert_ok!(request_authority(1)); + assert_ok!(RelayAuthorities::add_authorities(Origin::root(), vec![1])); + assert_ok!(RelayAuthorities::submit_signed_authorities( + Origin::signed(9), + DEFAULT_SIGNATURE + )); + + RelayAuthorities::apply_authorities_change().unwrap(); + RelayAuthorities::sync_authorities_change().unwrap(); + RelayAuthorities::schedule_mmr_root(block_number).unwrap(); + + let headers = run_to_block_from_genesis(block_number + 2); + let mmr_root = HeaderMmr::find_parent_mmr_root(&headers[headers.len() - 2]).unwrap(); + + System::reset_events(); + + assert_ok!(RelayAuthorities::submit_signed_mmr_root( + Origin::signed(9), + block_number, + DEFAULT_SIGNATURE, + )); + assert!(relay_authorities_events().is_empty()); + assert_ok!(RelayAuthorities::submit_signed_mmr_root( + Origin::signed(1), + block_number, + DEFAULT_SIGNATURE, + )); + assert_eq!( + relay_authorities_events(), + vec![Event::darwinia_relay_authorities(RawEvent::MMRRootSigned( + block_number, + mmr_root, + vec![(9, DEFAULT_SIGNATURE), (1, DEFAULT_SIGNATURE)] + ))] + ); + }); + } +} + #[test] fn authorities_change_signed_event_should_work() { new_test_ext().execute_with(|| { diff --git a/frame/header-mmr/Cargo.toml b/frame/header-mmr/Cargo.toml index 26730a2025..285a090cb9 100644 --- a/frame/header-mmr/Cargo.toml +++ b/frame/header-mmr/Cargo.toml @@ -20,19 +20,21 @@ darwinia-relay-primitives = { default-features = false, path = "../../ darwinia-support = { default-features = false, path = "../support" } # github mmr = { package = "ckb-merkle-mountain-range", default-features = false, git = "https://github.com/darwinia-network/merkle-mountain-range.git" } -# substrate +# paritytech frame-support = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } frame-system = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +sp-core = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +sp-io = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } sp-runtime = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } sp-std = { default-features = false, git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } [dev-dependencies] # crates -array-bytes = { version = "1.1.0" } +array-bytes = { version = "1.3.3" } +rand = { version = "0.8.4" } serde_json = { version = "1.0.64" } -# substrate -sp-core = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } -sp-io = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } +# paritytech +sp-tracing = { git = "https://github.com/darwinia-network/substrate.git", tag = "darwinia-v0.11.1" } [features] default = ["std"] @@ -41,26 +43,30 @@ std = [ "crates-std", "darwinia-std", "github-std", - "substrate-std", + "paritytech-std", ] -crates-std = [ +crates-std = [ "codec/std", "serde", ] -darwinia-std = [ +darwinia-std = [ "darwinia-header-mmr-rpc-runtime-api/std", "darwinia-relay-primitives/std", "darwinia-support/std", ] -github-std = ["mmr/std"] -substrate-std = [ +github-std = ["mmr/std"] +paritytech-std = [ "frame-support/std", "frame-system/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", ] +easy-testing = [] + try-runtime = [ "frame-support/try-runtime", ] diff --git a/frame/header-mmr/mmr.json b/frame/header-mmr/mmr.json new file mode 100644 index 0000000000..e208d4b950 --- /dev/null +++ b/frame/header-mmr/mmr.json @@ -0,0 +1 @@ +["0x729cb8f2cf428adcf81fe69610edda32c5711b2ff17de747e8604a3587021db8","0xccdfb06966ededa7a15c5bf490190690084f02d6dc35abb79bc8705f4b7e9731","0x5a06da3b3f0c3d73add4513d16a4af9623d4640eb1ba383d2ddb5645074ed868","0x77161d7ee937ffae97f6c23d26791e05f9d08b138eb22b5f43e2cee52ddf50aa","0x58677a31c0f3bff168a2b4d6a181eb7ecd465455045713720672b46d7fed9c40","0x95cc3648965b272a6ced85979bc32e619ee085e73f36f7dbe55a62a59cd98056","0xa2dc16ce3c3b2b05cfc722ba21ecd8a94bb2cc695f6761d1ca87444560ca7316","0x4b858e3d5fd8fdf6f109b145760cb9041c6256fec52871d9b5339e4a6159c1c5","0xb9cf10c067b6cd408149e0430016c91b84b1a5ffddbb6cb7d52c977571db36ed","0xf6e8ce9e7a28cd0469f59ccbd2f1f3899055a64bd57adac73469d29769eb0c03","0x58a7b1064f7db57f5bed34256bd5303db9884818bc8b76096b90f88411577b0f","0xf491c827e06f0f10020e63d16426745794e894032fa31c885b08be8668cab7d9","0x88a01cd72a20cd4584bc3f25484fc5d430980f4779756a2e1019ea6b679ad136","0x6a5b5a1627d3c0063667f00467d14fc7697376cd990e3bd24df0a7cb1b4e9ed6","0xce90f8a4d033368ffa22b61062f1963495922090f25b738248f29d7bd3179747","0xcf0b16a5dde57cf31798b724ac7b05ccc0f88b4667aaec45ea21a5a03466883d","0x554afd5150f0e6e099c7bf03d3a761f0629d1ea55ff35e5c7e1ff1ee733e9eff","0x1a2b4dd145b0f15e4e7d82d7f37f8e812d0111f7e1982b6872b2e79dd209f5e2","0x6da4df675a24df35b0f6e2888954e6dfdc2c1eac75aa94686328cc1889f75f2d","0x902276ac9d6a941151d8a8885e1848c2c747f4043c7e8ae6cb710bbb63db4ea4","0x30744a7c26cdcd363e393ba50d637546300d5e8f7dc90e924ab4fb84ea26078a","0xdc74423b38518438f55c30c3039ea411c1884994164133d20b63f0ac158f693c","0xe05d3314c83d80cc47debf80e3893c9db1545d1d41407e048328aad2dfaf15c0","0xf470e3bc1d1675ae7178241dd2e3a86c9a5eb8069138aec2592f5e5e22e8f7c4","0x9e9af6c7c85c72eca5f6eab91e51f46200d78ac781fce88fd320884af75c1fb0","0x53239551406c7443ba08a8bf3295b5808f1117809fdc941251859764454b6127","0x495d2feb184758389c6000975737ad88c5b67c32fd62b896dbb94aecad50e9bb","0x2176cea5ee7d347933c5b6e59e71868260da55e221c249981daba74140ba9c18","0x2c11f217d771102f017f34aa318f43acfd72cf362232fe4473045f0c7ad5a2ce","0x28de57a1312a90c2b612c0e36ca2aeae72c12192250071372339ed02434d2b14","0x36c09ec03c1a060af7ca69218ea8d33995c45682268ce9b0d0554f1f060bbfba","0xada45bb8291aa143a5521765b92014ca257c2250c03337ffd8743c74ef024521","0x5a437789dd6f702ca201badb1668d4c9ccf2dab6141d77b242db98371525cd63","0xac866402be6bc973c557690a6b45204a559d333df120e5c15211f600e7457822","0x9379b95898096ec5a6facb61caa4b9d575e03c06a95baf5e35f6028c4bde60d0","0x51347a3a249c26ce4d7b8a3559990a80a193f14b0ce38ab3312e69e3ddde0bed","0x6f0f1e4b62edb275a3c3b9200cf1bcd397b63250a16867a8f5442112dcd0bdb3","0xdabb79c55ed4ebd384e78def9db3e4914996524b4361c622e566ffdc728bb31a","0x51621141c6484cef1a93d156f223d6acdba823d7e2bac6877898d4fc83abf1fb","0x74908a29a0eed513b75ca5efbbddaf90b90b7bed8b976c97ed16756287b0cea3","0x1ce7b9d20c2252edd0bd958b76a725699587388cb6bea6bcc24875915b74dfe9","0xa9ca774e9374af2c29b5bfdb03b853a8cd6ef7496b7fa7e7f73cc5f655a9f933","0xe113a472d75bd38f01093f192bb8d4da01b5c67145b2dce44fd87edfd0bf2a5d","0x53698a616be649252b3e5fb21fd46bee9d3cf101a6d6804134d99c07405ef274","0x5554c14a28c815b1a45634d4bc1fb510a10c41f49aa103ad629d5e39ce4b31aa","0x72086c12d876616d729ddf6544bf78083635f63c3557d34384d77a148a7afffc","0x9a4cc4bd521ceb3740ce54adc187c9eee96ad192b7d24bf8506cd72af99d4ba5","0x569d5fb1c7879142f862f324920bac51a45f5fbc05be7532aa779ad2b8546df4","0x7171bc95461f5f9c72f258346cbf9a6a79bd6148dc079ff182438611bc4c549d","0x02b5ee08e93df9615c87729769892cd45ee586334617d1b91dfdcf60f205d718","0x577b38a56146624cec9721d9614555d8b104388a403a776c55d008307393cca2","0xdbfb99a47577df751b25ca414a8a01a459127cc5f72a5fedf3f274fcf4ce0a51","0x47646b5a7b9a9cefd8285881558d8ea79ff75a769f92a5ae11d1a8f8d3d1fbb4","0x62544b57692ff352a457ba1e10920aad8f7090d913f8c5e2a2138f347002f4a5","0x7cb4cdc428e9c10e29378d70e4937044ebfcee123871924c1005c59be0f00f2e","0xdeca8091fd138d8a05f92c39882cae1ec54b5dc5e17ae493dfa8059aec563a7a","0x1695c15879390fad9bfc3e6e132c04f65a7928e71fe787233787c3c4fe5caa82","0x512bc1cd3e0264a96b9019689fc6b8a93c576d0bc322dd5ba5152e670512de0f","0x20d92781bc0684f9702d051ad5cafef9438d9352806cffb388414b55c3a8d238","0xe666253125f63e8ab88aef4b57c7895ac597c58995002103f87ca5cfff219c53","0xcec80920a4ea9e5a82dbf830867acb9516d5db172bfa3ffdfa4775e154b6f685","0xd75b80f04d876c18d00ca3c218a11975b3033efb21eca27053ba0ee0444c4734","0x05d87c7306675244aee90748fb31776b4fbb65fd9082c198944bf03dbace2836","0x7217b9b8a2a6141b31620693ce1b4b5384f8c1d8cbc6dba97fa2d989f66b853c","0x436624db6cc512bd1df0098838cf1a7a3a2f4a236439c84d647e0c42e3b17b04","0x8540dd654307ea5493855a2f73653e6eba8c9910ba13ab86ee3318b8461a44ed","0x4730cb445d2f166df872714b265b477cf1103226899884face2040a3e846c563","0xe34fd08fe9bc839466d8b894e5ba33a39388fad10ecb817d00eeb2e33ea7d4f8","0xa195808d7b511d5b4e84307f2e43db26c91e6df8dc56e71856b7f471442729d6","0xa8717a02ac713ffa6fd004c79a147e26d455fe191f820f7ddb27dc8d7e3e5363","0x7a062e1300c150d114f9ce420bb3fa7bb19e755b2fe0dc3a3a48247f0d3a9ddd","0x9a3b9aabb054d8d988f80b3ff13db64e72b37ce56c3b619c3fb7ff559196ff0b","0x4a16433b901acc953d0dd1ea6385589ac24bf97ebae17639e89f4a768bba2835","0xdb7662db2d8bad7e8123f76c0ac5caf65bdfc22249efbdd631cc5ddea428cd5a","0xd7a54ff6f53f611a0af09a29f0196ca3b8ef8c94c50413f293d31765f2f5fd9a","0x848969388064f6a8e9b94c95f363c7062ea15bc3904e2a61709be545d4aee3ce","0xbe89e3264459ebfd23a2339fdb40cf0d269a5ddc2dfed0558103a7e2b0142ee0","0xf4b231663975fa5df6a7408874996e2b6979998930a3ec3c59db8d61a89b7ed0","0xb4e88a507895345a2bae5784a683a0483cb522fe4f644ea39009fb18fbd8712d","0x8bf5b89dc1719bbb955226572ad6784cf79b6646b020e2a9602ec53e763f3ecf","0x3d935edf987a3fa5d53868bcd904c9307a3c9e4343a170251c118081fdde5790","0x112bf81c8b4cbb957c7cf2f8f924537d10301a90f8eda677fc44747c15baf9dc","0x9957c18d1f96dabc6e26c78b1b9f46b9666406391331b601d00d0bc6bbb3cd2e","0x465b7328d7ab0dd3e6001de1e8f622c3c13690b786fa25e886eb70a94d1bb8ee","0x9657c7b522bd434cf1cc87cd522cd64c5d9d78d79357d56dc3aaa87a65b129aa","0x31b4342df8265035604ce0dbf47139198c283282e778711f53dbb7bc9ce25edc","0xa1a02cfe487c094cfb8882304a54d95ebcd758cb4675296e03c13906a2c3f3d9","0x41c9fd7f223783e38b297d12581b92fab992384c69c0c95e4b23f5bd1dea0535","0x267163759fe9ed779c2c32c2e2374d77431aa85d62a6c5455309f3765e80a3fa","0x1124d0f491686b1fef55abc9a893f4e460a225f00cf5cc07aa484da7e3750419","0x4dc6c6a727193d458355ee0957b6b9aebc53e109255d06021d9ab0d38ea9668d","0x6e1ebdddf05564b0ec94059c09406853d24553f4b7e0530b8e1343297a1f38f4","0x6dceaa827b12cc5251237215fdbfeebed8485f96ffe94c909b1f5795c4faa1f9","0x44cadf7ac096628db0cd3ccb827a31972cbfcef13de9563ca7c643242ff5f982","0x29b35f10866b6daef11db53eab7f4fd827593a3994674fd654434c45654af21d","0xd5eb296cb0242a020770f7bec629830e674100e4b0ca70c04bc1b9173872848b","0x691fa5a6305fdc0c1117cd6eacb9d45d5aed170a98d2143b9e616fc884bd9391","0xf148d3bdcf5950a914ca133ae487e7814e4a80bfca8923de28d0299ca07e66eb","0x6a85080d832bb8c61733c6a1d5205fa2f87514438fa46e9b446917aa8b0f28c7","0xf9ea7a7d98101a5c774ce72e00ed116a8dafbdff8d55c4f6a8d3950ce59839da","0x7446b5ed892a0d0719a9967b64a5e07af1adbc44bdb0818048b192f4b2210596","0xb314ea035941d37974f2312692ce9141af01dff590988ba751ed2e64c71d5ec3","0x676c433fd0ee0320be682e80be71eaef8248694dc13033d40dc1d589269f1914","0x12a6273fdd43e38bd0ec99908cbe94098510c2020497efa1367c78fd03a77a20","0x1fcc7c593c4ceaec4887599de26f736e5d0cfedb3acd8a3c9e597d31f76e20e6","0xf23f365dbff664dae9295a9539a5b5cb724d4b14cd46fd2ec45864509be8250f","0xd22bc6aebda28020a59310de394f91d4802413cec0cfabf2bfffa31d17f70c30","0x13e0e7836729160b07fa9ce24ab44e5bb2d2f25c24f29a604ea70df81c89622d","0xb0a6836b8884c890e013658900774ada2ee30972cdeda5be7a4a7c48515fd05b","0xfcfbd08cde9e4d63ae829b8bccddd65e429b7ff8e7528b446861372e8c5597e1","0xd302e26ad999fbbf9ce1ad635cad302d0e2aa923f87aaf3b1d03a7dcf8131265","0x4fa3439d86a0d1c499ebc5373f2d21e9695902a4e41bbc1ba8382ca1fdee23fc","0x65c07d1590471f52939fa2399d4c5bc13904e3836261c7f42900bfe331d3965e","0xdcf3aee0e048167c6500b008afc4eeaf933f46a089b5b78a7b9a3377b220cf92","0xf445f64faa5c7db088548994818285f7dac62a207b05c892b794961623f30a93","0xedc170190255dd3a6313b1ec4bbdb391a8c7a23e41ed50b161f0130209ee7868","0xf8949e4718b42c8da3495e87c0d6c03da3c7e8450d993ee0015c99663c963973","0x15359464830d20727ebc0eab758f8dfe654825d7430899ae4b2b1647a6cc047e","0x2f94aa633bcf391df87dd8969c930432f27a1008ff3332595197d6b7def3a802","0xbfea6edf1018976a49f414efb15e897abdcd2591cc47e485176dfc944a20583c","0x6b0c94d9af089adb5a031cd10b78a5837ff1d48443190ecd4fb3441027586204","0x325ea871063cf622b78c52791aaf89120e70610bc85ed0e34ec25fbb71dcec5c","0x7c9e3e75950389f6534717a712dace4cb5380e291538d9b65c03991957f5c136","0x6beb56e3af536d5e4837f7469c22db15fa4a7bae0ce3bbfbf35a469e4ea81ba2","0x4e8ec175987134a6e4df7325c6753c330fe2313f45476e6aa2e6b3d6df3b8eea","0x889370a0a23fcb1f5b47c9ed85dd79396fce408e14640a19b897b6defb4685a7","0xc9ccb7b39f660fabdc0f486bffc4d2064681b1987974dd772c85b0a8f94bd63a","0x6940d2909db374ccd2d6554d57aa5f0e160300852f02521cad1311021db3fafa","0x34e9f6b5f48c92f7c70bf8359183c023f0c27d977adacef97a6006b6ceca7482","0xa0b43c738aa51fdda38acf4dd0b529241acf4901108d96e14aa5b9b28af6611b","0xe40087d1b0dc3c54c9fda15543fd56b39d24ffa7adf91ee5ff14a63acffdc50f","0x2182cdec21b4fa47e0d0ee46796d56f89916ba037d77c6d512a54015474eb605","0x3790039abc6037a1db19f62bbc2621779e62573e38281f23c7bb9731830644da","0x3754fbd02e33164724fa56500541da576129a26e2022175be76f16c2cdba3720","0x9b9087c01fd4ab4ee3ad1ece37ec0e45f186d0789ed88d45f8689643606d398a","0x8f6d96a9e5273804df31c0878348357e840ea07d2a366a970d8bd52d3e078749","0xd0a967f81b6db703b9a69d63ee2da76367d93dbc0748a443006b7b9312f56df6","0x369fa4009459e60952808cbe7ffc87b79ddce2313b2abead6996bc8e65bc33f9","0x692b6e1f4fa931c90a66ca61d6a87295e528c42941ac0450e9667c396e093aa9","0x8070c2507f6c83e7f6eba7ebee410073f26761dcc5504ce60db028a5275ae2b9","0xe8ef8d4a4fcf5b63b1b92ed870973b177781c0262c512f374addb6a46f583c3b","0xe183c190a89aa3a1a916e11eee8bbbfb67834010ef8059e373893d59be5fe7ce","0xebf81e4886a9b3aabf34609f176332307535b0e49fc2deffbcfe100f7dfd0fc4","0x9fcd21d31235e2da2b441a6756e3c77832f5013ce289ea89ddbdab1f435a0cf0","0xa1085f9f3a1315e5c086de1569c6add209f7a3594d5fa0384cccf0bc76a1bb5e","0xe35d454fb340f0c788b3eea980f36c2ac5d66f05c03aed4f401ea70bc3e85fdc","0x571075dfd3685742614f6b6b5670762fb523f400ba29be3b854c46441abc6772","0x1545d00d18ed5ac5169f123b08b93253a6cea2086465c9c4b7a40f32a1cf13cb","0x36eefa9740d48a8850a4148039d9a34ff73ef41b8cc99fa51a9e746ed466429c","0x8773ea05ef697da5a2be0e2c33afbc83536eace87160123e2c11b772a72ac6f7","0xe5b6ba68790daeec3cfdfc60fdad28bf1757845d57a9f62ad5277885a06e0331","0xd28ceb6f792edae5dd7b13a4a55107d216e226100d3d568658ceaec965fcae64","0xc2fdfc6bbbf27cd8bde0e4f539d66a17b0cd617f447dad5d16b1dfa3002a1fd6","0xc716b322f220f377233d3d17340dc4046d1ead430750afa1fda1745be358f1b5","0x0513a97a3c6c48542b1b8b7202caf7a436f7d903f626e79a6d053c41904d7f27","0x3fa6c5ce370d615000d45f8ec048b2597212e722e3892cfe9b4c3a84417d082e","0x3e12bfadcde29bff2c130216b5f76dde18223a59812cd451ac37059f64e4e696","0x10be063036eb23530d80c6a08b9849f6becacb91bc25dc56a0e77fdff0768c69","0x70feab559db1a7c614ed50f6ab156e8cf6490c8963a67d059e5d735a6fe8b2c8","0x78738e25bd15cde174803db730fbf64af7a7ced1cab8bc460f7e48ffbe564b66","0x7ee00d52b9fbf0f0e2bd47721e1f77651406e723e01faa2ffc0ce2dcaafb8362","0xa11dcf59782a09ab60d83c60f9bf44581fafc6dd2475f3f2fe84edfa6dae9485","0x8707fd7bad03924d26516dc0d869a0276ab7d55350de005fd5d17324f6c929f7","0x5ab5254e267bfd57b036948f65f25eae21dff0182128b0c42eac744ec6839364","0x1d8f84f8daeed1850a7c5b46698e12e38cac2b0e9e811ec9c73b397c8b746770","0xc17ac10660fd5e2b2027a10b658a5f1060f65751354923005a9ac2dff8112e21","0x9cdd3bfc0e48438f1081e50d6a5e498572c149e6382aeb4ff693d6eb7f32c78f","0x59b0dd906b5366cb82dd1d1358f34a3fc8534d34ff9e3943e2ce40b8ba20eda5","0x2a84c9481280381a84bb0d6ce8600cb686eab44b1aa70ed73586ac2eea158570","0xc43547e34d2ec1ddaed5023e15a752802a523e0936d74a3dba20fe5f5ad9410f","0xee07099a7320bca56a64101a223107468b3a136186b6e6e7974ac14d077524b5","0x129137bd0664c584187809950fd5b39935e5a1601cd3721a5c92c8895282b074","0x50390e55e7b9fab86ce4c3881b1a78be9134298b83b948bd2040765d6c40ee79","0xd279b12835294ba5886ca53daaded1e87823f9247eedd94086c24597d8989a91","0xf3132d97008b8b3b338b2029e057b87f3701e27e1c9ad19a5c3d48ac36b06d32","0xc5acaf96e19b67f29b68326a805df14aa5fa3dfc41b78318c12cd4929da1538b","0x5ddf8338dfc5256335988754e40279555d3f87da147a5b8068231d03dfd68936","0x6e08a72f1bbfd17e92904bd1c0eed2f48e016b5074160cea8c808250ee4c7c75","0xe56a2aa7f069f1476c1d27db20023c9bd1d530f10ce4596c02398c931daef79e","0x6d9bafca4718f327df739339484e09319d12e07dc0f6a9a429a68f162f351332","0x63003559717c04074344c96b2dfd288bbb288f4048fc6edaab74c4616070055d","0xcd7aaf4428e1f04ed76a98bb9ec79af8e462ec54f5d52cb2932d27cc84e7246b","0x7f81412348783f0634530ff35ce7a8b94680ff4d7a06c4150ea338a2ca9b2d2f","0xbd8cf7909e295e947cd3fa3ef97f6bd7d6287b7508de2ecdf2fc703c7ebd83c5","0x99a87cc67911f364251ed5482dd44a3c1759bb799ea91f6752ade87fdc9d176c","0x5335430698a6e67eeecd4d126699b31ad6d35687e41424da0d91733f78208c67","0x7078ea65d7817bed631e7101c6e443b46132f357dc6742110daf9aa5a165da40","0x7c1e3286723b3a5eae4af0045b4d80bd343e08b2a1c1ee7ab5bd10144352d95c","0x7c11881e0debe7e5f75954a5b597afdfefe726fcbf852dea0dd947b9dd06d922","0x455592dad2d9c36758e5e42abb79d3b34f423ed04b0fe873d610a32365f27823","0x94681552098df7f9aa55bdfec1cbcf901b4ac9cf7498ddb37cfebc6a0e1f1983","0xa93efa9be56fb7885f50f0954a10cc7d9552c5996c433a873ac72e3c009ecc73","0xf4e2e3f9a8f3d02ff263efcb54a6af06f44f0b606d52f02fe2b236abea88f81e","0x1b224363a6dae9616d2cd357f36813fabb43e43a34706e9ebf212a7b47705f8f","0x1a4b01ca9060841c46637466a4d1409aec5e360fd5bc323b44b7e3d525539130","0xc4f17bc9c136d1858849b52b76ad21d48fccb8c2c2140019dccc41cc56cecbf0","0x5495788f405dcf2b5994fcd59a43dddec9aac8518b688047925b2fb8a6e40d68","0x2d65a262eb40ea5374ee1073604b80f3cdbbecf99cb64248879ae5a4a84c6aa7","0xb1e5b5b40d844d432ad859be7f9d09f2e9df5dc8451dd3d5445b7a24ef92f545","0x48c8ea2479441b67c0001fc8596065f1441c19121151fdefb1a8428397a247c5","0x95818f7f4cbc166b61e17389dc5760bef0988c0db64167801120731557bf700b","0xec2537e8787228c56dbdc53b2e805f9ec39f61fbceafde31b2caa98ccea7bdb2","0xda7d47dd206b984c62c41f8dc2aa6bbe517f155cc579f0f23b8b5bc3d0826f6e","0x98d8b1129a8cec1575497485cb8ea722743a625fc2bc07a8df02c8d927bacfea","0x8ae27e0d792e48d9de0ef6c271eefe927d2039edc9e9077ebff715b49cf838dc","0x3cb9bf48f8cb108e415f979a21a7c272c3002b73834dbbc5836141c7c997be7e","0x79a236cc03111a4a650ddca61e993897ad7cef996f48d6eb4608316afa96317c","0x1df2c59f317646ae56dbab867e7c45056f7552d5c9d32c13e4e816e15f696fef","0xd8ee95e4d024d20a9fe97e657b44135057aee540387480e14c95225b0e0dad2b","0xce40e4240c115c253971027884a885c1400c85aeaddf7a964f37d2740026950f","0xf436c3ff40068c25a4be61cf96344462fc6d1697b584d27f528fa55ec7d32913","0xed93000d1f4cece84688d8debd66d3d5f89689aa226fd32a46560fc9e5530e64","0x85b442158f3f876e5c807dfafc4554ef8a00d0a706b653a965951aa34591f892","0x6d7d990279f5ee1f958892cbe8f5167090811422c08d45f76896b753edd8bd38","0x6fc5f4dcc8053fadffc1dbeed76e1c997ad3a89fd7edc0b639100beed4ecafe5","0x080b02df1d0906d2ccbd2334ba2a50992cbd923a9f31836f0a6eb8431aba799c","0x74f57098de568eaf31a78b917ae1f80fc5e93270aaf5d72f3700746b42a47050","0x5139f90eb7c7b9e922013171567dcde9f2fd279d6b790e1643799d8449dd5449","0xf3d89ad12666b22759223530d1fd29fe51d991d9034d60653002da102cfd2a49","0xa03b9bc4d8d369575efdbf0677f58a9e8b35b9be1fef880812f48d45853804d0","0x23d3522562dae77a832377b2f6a8af55683dbc59b9ac1565116c4683bb1b9649","0x81828825974309c241c41ebee4b8e86974000a791745c53d8ec31b623b881fef","0x6d40aa6f19d753e8fe1626b02462109fa08970cac05b1576a7a6a562b933066f","0x15bf4347b585a02f8d06c51c97b49eb939a9a3351098a93a4d9a17ef96d65204","0xdd845afa087ef63ae862dc99f4668c47257ca2ec856eec52d2174cc6d270ecf8","0xbef11337864005c798345ceb48fd583a43935c6daf6277ae4847d2fa5a69c204","0xda139cf233e3a1c9866964401e7b6a2754e6cc6af977fc0353815b82702b8226","0x4145e389da959b4eb179c42869eccc38aeba4ca95d728480ed8ec5b2556cf802","0xac2b43bd1e96beba7312f876574254de5ffebd0b50396dabba09558b72fe0921","0xfc834526ee242c137b2b2f143eb479fd4b07eb61f49ca360fb9bdc0dbe1b2b3a","0x7e724bf0524ba1ff5dffdacdd755b274cb7da91e9bc14ad90540c720f9abf3d4","0x32da3503a4dc7c4d64c74596b801f20c14d3efe5dd053f7891326898a9c1320f","0x50a964db42315eeab6a72e02c8657f4bbfaee51f57d6647d2c1f8b88dca02b5e","0x3969d82938a5982839a25ac9fd94c29c76630a54b08bd32f1ef62b9cd42b29d5","0x40385e79fa7ce2f7664d4b0e6af92412e179d5559afe4cb9f37b2be70cfe6437","0x105b8e9c2e377e74df75d9cf639bd90488d2ee2b7a716b4cea75d669db605fc4","0x82f40388abc6b48d1262e0cd1964fb8fb1fb05c248c41f84da7f03b0a5133d77","0x41090b73ea21b1d4dc25e3cc4ccc179dc2cc3c5272aab027c64e247d62fc88ee","0x1c2c10ad296bd0b37d8abca4073b7283846251d6b52d29b12e2fe723eb497088","0x9e97615a04e7c1805bc03744cff859eb5311a8fd036661579fbeac6595176099","0xb6376a667cf8104b2bdde2195611290c43f1d690b64db074c40ee22c5ebf948f","0x4c4850ef5950820ecbfe3c70afac1b13294ed64bb3262536b7f8437bb84e06d6","0xe9f75b6f1212f8e1e8cfac5fd80b17d83f4a5015f242670503615b955b719380","0x955ccf043847ee7ed705aca5af838aa0f2e4d0e776e38c0c3ebdfaafd69cfcca","0x762b0729787603afc23a206bba17dde90ec56d241b12555212009f10876e5ef8","0x9b7cbaee728fa88c90bca0b810e16719d2b43bc7721580b4dbe494974ff2551d","0x4dc5d8aa16aff4d80c64c2d32590cba957aa08ae6c3aa38a9d514b698d870c2e","0x11ca16a2d96065e0703e7337fc65b6484031a3d761c51c29e2f9f7fd329068e8","0xa61c54ef9b4747b2352123d91acf2982b1166f841cfb9db0f9c3dad9fec12b7f","0x270342ca6358e76b8178fdf53c00dddc9ecb32629c5dd68ef6e23154b3e036fd","0xa49633e0b8f26e5ccdde76dd47d74b6771c73669a8fd1e9942758b7b487a4eee","0x5b2ab92a69608cde3336a9cfb6e7a23bd3608aee5596ea84c5c67592b2607fd9","0xa6c2e07b2f3723dcc577d5a753d8c1a09efbdb9f414e24bfcd8ce9d4c8e9024a","0xdfd961454b76255ea5391ba747e64c1993b36df0eef9f70cbdb80f4839bc607f","0xc0abd0792cbd122ba6fb2597c6656c8aad8eac917043d7b5c1255f276243083a","0xa7ff96746cbf7933629ad32efc69a361ee21e30e8d5d0754d119a0e7ea707b66","0xb6a5c750ea82816c5395eff1f5cf3ed05ea127f6b9e9370cd185c41a730f51d2","0x4c8c0a56cdbd785ca0fd76c4ada23786579038cc0f16997461d3c2148171026a","0x42bd375ec2ccbb7221d2f88db644932f3c487630a158f15ee1ad950085ef975c","0xa3b71b79899d191071c88a9059dfb956d7efe638d3c2bded278d42168ede3432","0xd5a19b8e4567faf2aeb6b23d94c9e5e475def43699729bf70b1391dcd89b4e79","0x4499fbb7f2d242ce8e00a87195eb7d07cd4c28a22fc7d4859ec391b219c358a0","0xb4918b07489170a7f8151ebff78f849aa91f1a63bde85bc63fe1ea9d95c0e794","0x148d582a7e389122dd8d06857ef1d1d22f483d6dd87779d53ed0d9e1f212b842","0xb053ff6a878098b8e0a41c65e8ad3bc49e37ce4cfbe2d9401f24028f868b80a0","0x122f619d18d3ee2b781e47603d07472dda19fe4e9915e709def8d39ddce8c0df","0xf90828943cc3893da56b0c0cd18e7889b7148b45b1c9bdcaa00572b300692fa1","0x358c2e8789e3a5b6d2c470fb505c28a29aed1389d517108b1d88722721110541","0x8a0872e35dd7208eca93c32cb417c2062ceff30c2c800144991601fc3ccc8fce","0x14094f5e6e2c4b8c448587d8bea521a5f008f6518799a557cc9012592d524b64","0x9faf50e53af3af4c4a5b9ee68fc238594f0524a5091ce57dccf320672163e890","0xef122992e1e436e3e95cfdec75ff6442f4760ffef128bcc72693ea6bb14fe63f","0x3268b305e67617f9685335d4c2df40e25225e864cbb7a75ae9462562cc234a15","0xecd72e411f769ed3ee353de17762aea0ed4cc2acf57b8a33b4eeebd7f7890201","0xdd26c05d97640e0188ab8040674416a10813016a4c14d6edd64762ae22e71dbc","0xce8a0e5d74728e493d6f9c0fa1c1ba39530ccaa4551617ba4392f8a6650fb7ed","0x5b165e186217d693641ebb5cd5a4e97e44bd4ac56a48da1965b82a8d70f4d58f","0x49aa7b83f1cce3861f4fa4d52bd2e09e75c1ac5345ca15ab5ec37c02fd751990","0xb43919bb35de0ad9595def5104d49640544b2763e06d42d1ef1870cd606b31c2","0x09d19e26e9cb2742b1eaa08280007ad8e6a6d8d2d6793e9532af64089ca185fd","0xd1c4ed6191aa3f71962c7995b420ca4005c592bf749ef98f4aad7689d6f6b239","0xdd5093cfa28f01e875e13cc830809b6ae5046a00bce714447d5ebe1b04b9db46","0x711a3cfd8dd8e1a051633ea5b9c5f39923bfc8c8fca51f541133b5407bf87317","0xd902acd817332ef4824fadd74da8c10015ae22ee24ada65af2cae27f18d05ed5","0xd4503fb1a00467982ecda5196ca15fdce9b595eab87ed775b9f6c3e694dbba65","0x415344b13def4345030ab3cb6033e57f7c5296e448951391e7ef16713b29cb97","0xccd141dfea64862cf2a198b991280ede2290c237569b5e3cbff6f707e8285088","0xd1c9dbafbeb06938f5dc00c77d7f6ec314a0fd5d6f52966bf15845b999ae7ee6","0xb17e261c38c31f7024e033a669842953a397872b293ac4bd7bfb930e85026cd9","0x0555144cc8b961ede491f1d094c58847e11284e0fc7d93cb1c432dcfb27505aa","0x9f95630d227ba849ac02676cc03a1ebab738c6994ac0f6e93d196f7990167b36","0x5c73c7cb944dec848d066b2bc74dd03145b179cca165e8c74245b0916f0efc57","0x4ea0fedbc3fe927b4c751f534e247936ad11dfdb32f85c26b1649c8f790a39dd","0xbcae653c6f24cb91d0619387c1fe5b8ae54c50ed161a8898b8e13a2881ab46e3","0xdd2575509013dab770c1322222cdcc4496f74f91881049ff7f247f85a1341bbe","0x1b829aeacafb8760f4b11e32916fb012e83b3bfb3d5b51603d121e95af12d756","0xcf2ed891be5c76bb26c0a4e2820961ca0686785d8346f812b4ece9f58766cae5","0x288895c3ba1b420cc263e422e9b51c0d2ca66f45463964fcbdd1f359f3a87519","0x149757fc63287fe5e734ced99d9f687dfbf0df4c2b6a064127d124e50834e26f","0x5e9f64af5811a2afc24766bd71c2d9bf81b8d00198afa561c4f151da35a22715","0x14ae92e702ed93da2154b6e9d02beacf863aa18ce347bae17d8cc1b669b7161b","0x8deaef2d75fb73e9a737d718623307a6d936f4df78e0582a9f1afbdc1bab038a","0x49d9f45b877c7a7bae0f24a1734ef557ea24e403dcc48e0f565a237fc59b86de","0x9c6566e2d28be3dd91c2d18537b1c29556e976d1cc45d22de979c06eb0beaaa7","0x38c4f10d992dd99637a53a33b5751f02d9c18aa7d64b9006ecdfc02afca92a5f","0x3d19321542e014ed145e09d15ebc99d9161c57dc4a9a30545b9bfa994568f5de","0xbe0913f45d487e979412f84ffcdcc7ce468fd6b8bae2db146bc826e8b0c2705b","0x1570cd3b212de143603dd23549882909a5a9cd4a5528950c27ecd31e07ec894b","0x403dc53ddd0cbaf7f225c018e4485df7a2bfa7e04aaa1640bbf1392fd245cea5","0xeb4a0608e7c126d3beb8413f68b26c2d43421465388e31e2316039d7150f387a","0xb7bba91711c0507c184568a9435a69313394a1a09ec498ff04068025d7080113","0xbd7f720c52bfb96bd14c5c0fa4a37dc970a96376170ba872ff7bdc72b32aa638","0xc8b5eb235c8d20174703a98baa143cb1f086832717bfea11ae9d5ae82c94bcbf","0xacfc67b39ec2be9939e8176284dd831bf61134f2c4b4056d3f5261aaba6d2696","0x3c0b9c21b856d9f2a042a8501465f7bb5486c606af68983cea34eca3b8e3046f","0x5dd1424577eecacbe259fde6eaddb1a4e8f44f1a94775f436929a7c9d6c5a2e5","0xff195173fa447d40b65b1a6338cf8ccd184997d0c6e0bc21c4c5e596696c4920","0xf02b5eb7fc94d3fcbe0ec16ae30d2d053de66eb9f14fd6a8e6103b7f13262037","0xab129c1049ab926f4e508843ee24c8883c17a23d5fba1ebff935c57ff4e86271","0x4880a428460273e597e04d728b01d6005745051801abd1cee3d89cb645af1b65","0x9e646216bc091bacb3a7b4ec8a171c18f6dbe001c102a35368059445c3e3d1f6","0xbb783558c49f617487b66a5b18907ec33c30fa8764238f8825a1b87e637c34d5","0x459e05825e1509ca3240fd63372fd951219535dab0b68d7ec480ace400cf1562","0x18a6f5e03e2496b486394ab88d7ce90771c35a303647235315207e0776d6f9e6","0x5e2eef34c4b19e0883d5214d5a61f653db6ef46d460c8e9db58f7d979081bcd4","0x53d51e6fba6b6df64d01290fa61e3996a6e81cf28c77bc33e7dbf04c47b6d8f5","0xe9716fabda12f90613d7f1ceb3f35200a0fb255847fadfa9a8a124f5554eaf7f","0x4786b311df403a90caf40bdf3a258d7f208e499de4601a679019113fc3eb1db0","0x953e432e234b7ed3094931a74880414c054cab40773b7a5a508636d22c12829d","0x5d02386ad5768391c0518f1e86dbbbb4bf36d08cea589d1fe291e07e68c209c5","0xb0453b8de1c6de8ae408dc69e876d653569cc0b7981aeb6a8d4818aacd366db0","0x3b4e974866d0d8b8c2c9bff52ef3e3fb0ce2d338ef30120bb5ba59af91486e4a","0x51c0d3cb1bcbe1aeb1db3fa241b18d250aa99173fe8925755460b25c4c06236b","0xb3bdea0100a18ca0f6d62f693c5a3f65c91b6f13228961f3a70241dbdb688a22","0xcbec075c3842b054e8b52cfd8daedc2b1cb68fb7d631874111c0cd82a7ecf40e","0x7e953a3f5d16556da5a0c6e5d54e44ee17d4b40c55cbba5fe6bcbc38d48cb92a","0x1372b826fc9694ac4097484a96f2127f4aacfe813ae20064469b37294fd53c61","0x39653527e491089305e2ba3ae472f623f9c3a5cc85b1ea630a23a7cd0262de82","0x8432b2e73d3866d423b6967d9f9221ad11a9c355c018af2992a82ebaae93a46b","0x95b8f2446d2e7ddde8c6e4ae9b337aef6fd81a73706c2c0d3010687118566610","0x4a90ac88a272003c77f9d71e2438fa05039f25783b4d0c8d46b335459bdb39ac","0xd705d2d40761ccd07ac11c482769b7fefbdfcad605d6bd146f87056ba49e8a1d","0xd0edc43d4a79b76b79c9c1411122210576d29d6746d1d19df505bd9e958ef9a5","0x1466c9af8a5c694b421f2439b94bcdefc102c6aa555c0b17afc54b1168d66486","0xc893ca06022c965455889367ad9fc04544576a06b106199103c010cd399cfc48","0x38b53b6e7c1385a6d06f65d5ef4393db2112b0ef5eeb38fdb68c22b4b67152e6","0xa7a5e8c1da319d39625568368f9d137262819a4c8dba0cf214e10f4bae16e1ce","0x433bd8fd3886ba30ecd14b5c2104a62cb23f85736c5bdd3b556f7937b706f5b6","0xa8deb1cf11beb53ea81df3ef6b3694c1e53f5dc7d0f5dbcf97289b33d3ce4c9c","0xbb5794414b05b489f0b9a3e25fcb0d3c54768304b466cdc976ced4b9fc14f55f","0x271dbf991e7cfc1334fd47357c192bd0ba26e49a8f94d4a2399ebeca730948cd","0x994fda8b921720431a66cfdfc7e494fc42e85977a42de88e1c5bd92261aafaba","0x22545e947956c9d342e4e6239dc149e165ca7fe72e2fbf86312eadd86b1ecb58","0x534f7e5cf1d836f72b3812c90de035bf5c9d4c515b2352a44cd13ed08363015f","0xe13495ed56f7091e0e4a65ae85fa7d24a9d3da88fdc930024db769fbc6297ce3","0x339f2d76ca562814a2de9ab57ce1670751b20263e1c1f28b9440236024bbbbe3","0x5719b125b3a534d29daba8adcb4e2c6f1fbc79d1c1e1d12e6accbe765840b59c","0x5267230a859066f4c105ffbde4fc3a5cec6731683ba26cbcc17da0492c2d7bef","0xe95f476a4df085c2322cfaa6d5dd108400e24e5b62715a82a23ded8257e79635","0xef609eca5adb43daf73dfd18189fa27856b3c48eb6979e1edf362136345553a1","0xfbd07135cb1697a7a6bb4eaf20afe120810157d64886cbcd2e47ad7dcbf7d5ec","0x32d0f0e42640bd8789eebfb17434d43c318139e2e94791e3200ee192dafa0a27","0x80fa1aba23316c082152ad296e13ef128682461b5b9f79c29a3e93f703f76421","0xe2b481c8efe9ebbb1af31a10b56dbb6eab28ad2ad64893b6de8d72e842a78f2d","0x6527e2bba13e74749caa945ac0184cb0bcfb5eafc53c841c8bb4451cc23cfddc","0xd65e0e41762309e91e1057669644f997e5fd196a3e58d935881460c7eb2a8e02","0x9927cf4b29cee7d160940e8d23a4e9bacdd2c7992ea9fea47b8faee4d02bbf2f","0xca9144a88450488f948673a4f787923562fcb8dea8f4b6d51631437c2f346c33","0x253ef533ad76774f7eb8c57f7f51a2265bf237a0075bf914ce9d6d616e01397d","0x0f1bc2e8369998220a91e9478ab8add003ec734dd0c486749a560b7158eaa47d","0x6ce3249d78e0cda7f807a81ece48499f660b3e188f02242f30dc322882a3b6d3","0xce813c8336cc814a23486a448147972322a9c2b9d87077a918a339306fe32e77","0x4f3530da976056d6785cde244b4bcdd89b9f6420ba434bf6caf3a2b4ec613ad9","0xeb9ca6dc615a64e65e4891d601c1c9d9ad2b68b99c93e6d7a434c545f453887e","0xf384abd8247a48d8cf2acc50be99c80da8df576239d5fa505a4008615ce4b57d","0xa8a8f8b3af16d0ced7cd583484522170b16e458ab46f07874699ef5b18399a92","0xb7460b3c877c0160908668cb4695ec227e6334b479f82ee76ad7b8c7940ee59e","0xc3a959dc7c341f709e2f7e441146897eb274e14303f42cac631f9f99100d68b3","0xfa93a4badc29118350f23f7679abb96c697f6087c9c87ec24b33b3df3efb6c62","0x0f2bfeea27fb2dc37022fbf3d4f84d6780e6c6c7073fc05ca66a2cc7858c895b","0xe660f2d170c0ac6281e2cf72bf6289dc72b1f04f2b143fd18474cab8650c02c9","0x2b65d11440ef5ab8c13b541946438cb242ebf41f3e891a3664839a8cbf9d0fe5","0x3d5ddfcd3a67971f9583c166515fd1bf15b9a1866e2f8a989bf8fd429709d560","0x371ee95c765516f718a50d246064fd72887f8d94bc1d062bc81116f6a15766dc","0x699211ea8e3864cbdfbf680bc93327f3854fdfac03d5e3cec42a645f243361b2","0xdc66f262285181ca9c60b25de3fbdd0a0a2eb02ec317b00dc34cd0f585732feb","0xab7afc1a2c3d365fd1ecd9f67a29cdbe5ab18e201571884f69ac49aa2ebead04","0x6008bf51830c85ab21ff628e6a528f2ead9a0e95b84dd78326112890b4ae7c4d","0x629251ea9aa75aa6109db7496412be8a666536a78a7bef262fcf1ecdd13de4e4","0x0241ad0887d8cb575ed3aeab9ec511399407d6907b131c5e4118683607e0cb01","0x8e2b208996c6e39dedb7ceff8aeee0d4a2abac9141b633e524575b82cf887a95","0x17738684d2207840e4b9a2ac390e75b3ef9b50a73d731c4300ee46a9f3a5accd","0x99615557bfb06d865031be6b43efe4d49aeab3c9c49f73a3af74b4062821d0fd","0xa19b9e838bb08fa985ef592c8129e737d945e080ef9f997573230ab82eeadb99","0xb5639d2c4c9227b6c60bf21d09a93ea809bb5ce512bb0ec5f391d934292c1cd4","0x2d3fa718ce717b98e9385090af0f3cad626c55fcf14460b5c0f4af1e0f604fa6","0x43ca8fa3646c8d6f01e25b131f389f7a614b933e8fb927fd937fc3636efee452","0xc0aaef90c70526f5834f28b2780bd2dac1f2224e684e6307c62a627374f1f1fc","0x5d190910c1957fdd25154d7805f500389b3a201a7cdff6f61388b8c40df5718f","0xf794d70564b469f571735a7d598c4dda00909e03f43cf53a786bd4920f16cec0","0xdae83a548c418a8428a2297b783a61ed7ea6fdf9202a67b64b382adc666489c1","0xc7a93950039084988d4633d22f663b7e431fc73ac205263d43922eef36b6d9f6","0xda42e6bf5c31b33c84eaf0ab8fd01307324030658bc7cacbdbffa698b34a17b7","0x90e32cfca4cb99da1f185b68ab7433707beabb66f39c51e2f8fbbad6baccad7a","0x70c7e557eda00354c59088b23dd2b1714cc33b94f40c678d3dedeacb31be53cf","0x1afd4d689dbac6445ab519491fc8de865be4af55d647e1a151ed17095cff125d","0x5e445d31a673f3e21392c4ee8f30c9622354102b6eb1707063f7faf902bcb8aa","0x8a9230e450ceaa5bfddee9703d520ea888af6559775bedd1a500f7269d260321","0x4a3725dd99033b5c62b09d565b8223ab2603c36dfd58d5c8fb01cfb4ec4feed2","0x7a0beb09f07e14b72fda28a5d7f24ee1bcfbc73a73b07b6d97d14eda664aa4cb","0x205edd74cd871d4808d403da4fdf06d6813bf26069f35e243352e78c682eab4b","0xec8dae406e8dba69cebb111c9480566e64b9e7bb2ceffc9d058aa3302c8e37c6","0x14a5ca9af220da1807e66717857c56f32e6c40e461ab43254a773fc4c4a19577","0x07e5474e75ecc8eb458668301c533ba5dfcc2000f4b1e21d827049d0b7af1f29","0x625fb508e976af03d94ac0eeb90f57dcc51252f8f73340ced076b6b326f4928d","0x4f9d0237106f4a225a2d184fb7016789d8b368770a4acb2bd287352118cecb91","0xc53bd63619e6379baf86da113969dff6a44bb2a8cfcf5b77eb737d183afcb6df","0x426d26bddf2d2e6b3ed07f96913919f2aa43dbb9b11945650f3268c01f011695","0x6b7bba57bb4e50a19b7063262247578e0032fbbab29296d7c0e470d1669ce642","0x256c89b10045b42a258f1111703f5afb214f5fd864ce72dd3c3834c929b0460d","0xb38541bb811ae6d1353a75163460d13ba6943d40d5df72609534e50191ab100b","0x7fb6273ae5fd8fe68ba386e742a1d97f0d235eb967142f173178e6881376aeec","0x21a75c94be51f5551b91405ffa36a9357a2a7c9f49afbc4ecfc90418845647fd","0xd87c8a7e87eb9750cf7935a3e6342934b8ed54d16b605139b54deca800a75d96","0x6f54d4fc5cc8f752fc8d3f79e16c4bf347d2d82552942e69bdce348d9f05d1de","0x40ed0c29ee73ff58652e6e4e3157f70284832ff60e38aac52820bed2f723f3a5","0xb86efb70ea031c65ea8ae6b410bf3955389893c9777c5b2ec9aeb6d855816278","0x2508b38b50dc704803328a1e7e4f18fbd56bb1a56899e3236298aa1a0a2f997f","0x6769841ab0765785b771e21f96e4586e8b814700fe05c9a4e5ea1b470c1b55bf","0x4dc7771632630b993808cce0ff52082fdb45f70662e5d3664def2bf09651ef9a","0xf2bcf5d35d8fcefb80dfcaf3b7527ba06a47feaf22dfec2f7791fc9ec15f3afd","0xd73a6bc59b81436e11748f957b26443789472e4e8b321a0d741293ab3c097be9","0x672d2ec20c995381a8340efb120212c78f59f52fd3b7d429d1ac2d11314d0f75","0xd2da61661e2c8902b1832ebb9b5c0be7c7c888aade55eff83497866b037f8452","0x86dd98fb675e990d1f740080113f72cbcc87dca0fe19033ac01a05000aef6473","0x81ba8161012450d4d7fde9becdb88d12398500d82c7c4d3604bc732f659fa034","0x58c095bdf2944224679f217f7917e0194fa79e010e8ed4b6b55c4d42c6e6f008","0x60e10b273830a26adaa49d9d841c79045922e467ecac42948c2620238653e45b","0x8715917bfa442878e5f305ac95b6c6ede63e89ca43da8d3b3c020a6933262a70","0x81d78cf0978ca97f263441603c3c45b4af2bda88337cfa95582fc9d0b53e1a89","0xce133872aa21c5b19baa73b0401b80159ead722956c50eb2081fd081f00305ba","0xf3878d70b10ecf36e6d78013014199600b5c7fde6cc1944697ccb62878707db2","0xc2caab77267ce10ed58edabfb2901f5abe904b61a605f97bf99e90a80dfb07b2","0x05029494074a8a2989b4375e605642f1bc6114fdbcd75d872aab0757126aff74","0x36224e4e9a7f9b8f310233734b687a3a4269103b566bbe58da93c85a72bdf8fb","0xa01b37c414b4cf6b1fc4b31028ea21097e238500d2c90d4f56ad779ce5c31630","0xc23723af17ca43ded974d629535c0e351a7fbdd2591bee7b1cdb39ffe6bb1021","0x13bc2c0c43b0dbc0277115ecb04dc1827a4955957b7029306a61099bd3a7719a","0xb968166c389e6c0f1c1d20a2543f0a6b8eba46e2045025c7d11e21af67841260","0x989cdce7d38361f87e6ab068a69bb8508656f1a54c39b77cb8027d461c6e8333","0xffbc4887b09441c53714411f2fc22e762d190368109bf1622751edeb7502c14d","0x41c25a71667825990afba5bc287d7769a6aeb5aba633060bd2a065af6b2b85a7","0xd0ff142a7d4a37805d9459718918a957a9b671fb6859966f134f59104208b1bb","0xf63abd742ae705ccff218096f92d78cbb0b0834746520dc242e80eaa8e53134e","0xeb667498614a167b09478453ecab8ed1bb6e1d787d3b512f58ad0c9f38c8800e","0x37cbc64b2a722c372c0c0b3c07eede02a60b1152b8d1467fad727718bd5bc301","0xc8ae15e2360bc8a0d50ae70f7cfeb8d6a7dfaf93ed94e6a9c1302fbda204927a","0x1eb466e881f765ba16dc84f472ac43784dd4bb8800f53ee59d6ac91f4549944a","0x715e766887e0b8652fbabaa21bd458f5079d9b25cd57855f6fd14b2d83e44bc5","0xbadc24a8708a9c90f47d876660346c4ffe95ad1a513513767910bb4b5c7703c8","0x3f2ed695e6c862811df4507c43767c17822501d8323ed5eed3012a970109b247","0x234fc62753a410b6384e8a38c343c5958bdb6b1fc51ccd7eb3011fe79a8bd3c7","0xa14dc54fca9209480366030d2455e01f2b1d9fd00a4972b7c645af0eed441db3","0x6e73e5e338883d0b1f9ce8143445f8f793cfd25be289262b02d412a2105371d5","0x3b7b0f118396b1ef5ac81eec4f1b0e8d62e03833865e4b7a65878f79428ca2f5","0x8ef7a5adb680297b57a2de657c25e6de885d981109011226c8a878cfc66099d2","0xeef911b843e5671b1244e80e522a58fe5a0b4a5ef2a09de031fa6046db630cf3","0xeb8bb9caf925bef46ee757252fd1879dfdcc092d70ead472dd5ccc54a8956979","0xe64d4cdf63853cba2c3014028cc1dc8c4c310d8994efbc39b5287549d2e309e9","0xc04c34139e0af6f23d26ef6e47d04164451298a79da951ba235d09fbf4762234","0x55df494b941d5a44329592793f4c4eee96d34dc21d537e1ac95619c87ce9dd1c","0x6e59513cab604657ba3d7064d36161cba09e28bc5b160930ea2ada1566f95b50","0x057085cc0f995b37f12438826b10aca71947e365589d65af22383fa41ea9c5e2","0x22863739467e64e58599872a9665e1b3b3112e1e458b00bd9bbcc8936869c9bc","0x3393dc6b7bdea7922bdc4c106ef67b8459353cd23152809ace6b81654eb41f9a","0x58a98d337a4cfea792dd42573dc6bf4e68438f53af8e9ef7df3d40b32337683e","0xc0afb5596c1f9fd8df001beddca0ae50396f6220dbea61792d5e8e199a0ea799","0x916f3c50d95adfd4833fab229c4a3fa7a39e6e12ea8d109bb2070aaee0511906","0x6d2177dd20dda4c7c29448cf0a2562596ee8902c47f32834cf93dd93c2761b6f","0x87f826d85c4e5d54ed6251cbb6caafd95c867999167827e5745b6c2264731fba","0x837a6508e118e7d3c2de6cb877bf322b33e6b8d93ac837af07cebab5c95f5d4d","0x6f59d1bfae03973ce6c3438147302b387788913a55b22a8790b6a598f19c6c74","0xdabb55875c661078f9670c219b89abe4d78960eaee73503ead15c7bc933891c8","0xeb8ab29f0e91195e02783026e7aab67572394e7ccedd5aa14645e86d0971231a","0x446d6b0ec7dd9e48e74a06780f2dd5d41993f6d84056f12dad124ec4a632dee7","0x32d4946d8c88eed5da2c6d85e89f67b88c7e131209c8fde410bdfc53dd82b6ce","0x62e997edb6846451f83309eebd6b37efccf7d703bffa8827492f9104556232a1","0xc6cf3610d3e1fc608772be93e9665126467cc6e6bea6acb44c0173ec0e411d9c","0x9b77c493fdb0a465f12b538b1e1b4b677b58fa46047b8d68db6d7a42811f438f","0xf851259a4198d8948efb4bcaeb8ad0f6a431acb6c037e9e67a502bdacea56807","0x6575f61be71922906ab6438f10606a65bd4b3a5643d7883497af7a91cf41298c","0x2c10823a1988bbe1ab339b0a9e1ca4cb6b4cd2e05e02ad928c200cc1a7d9b67d","0xeb09cbc61e5da63a49843ff8fe67c91cb8e2c6f63aef3e852322ea137b54b128","0xebeed39296b189922bb5ca61e58cc8f527f3128efafd73892a162a9680a083bc","0xa41e29525e3c97d805fe51cd730ac65af9150904b40424f35a5e9451e10a6351","0x4e7a0d428b9c7190ee6933703e26678d3232e4a0d04150ddb38243cfe053b0ae","0x7b36b47ff5995da022d0412dfb08482fa97efe99ad080155dbb573dbbf32ef14","0x814e1e74bec04c84fc9c1413bf117c6697d47bf41db689b73b997461c2524f8e","0xbac8b6a901699d0ad76dc8101202f3d82580ee3e3238135bf10e0ac15879f4f6","0x3c6ef8891c6bfb45bf50fdcd3efb8b13588a0190e5735cd9b914a95128a05cae","0x01c3e986d55cc8b12fe9cc3287ca9eb57c6c6733948e46d3a52fabd3466972d3","0x535aa9ce70bf43a3de33557eacb89a1aa8ec64f4d59bec6859564c889884dac6","0x8221036c540f750d91d7d1dc567f694277fac30b5cfa7401f8e7a4925475762b","0x7f9ef20906553a7d62996c68e9db652a15b6e200ee3c847e9d034b9a7fa52eda","0xc3aa0fe5084835c37118b6956b5d57e579d29951fc0814201861cc86b709818a","0xd445fa825fb71fa74942f1706e1cafc079ce9f2466659de7679610fffb968fbb","0x41c931e7737eb1bf663b15679851665e17ec42d123f0a8072119bceccc9c462b","0x7d15ec604e47410cbd9e2eeb7fa5f8b2bff8c729fdc7559e2c8831cb61a4e50a","0x107498a62d02871a59c9defc4b4098804645487933aabf6013ecebb42a030317","0x42847d00d10e4ab1097281098bb01f6339ea0faf2f9df08734f471f241bd2067","0x5d091c5a1572190b37066c91ac6c6ef75cd32b0c48a7d9202b44552e8e9e54b1","0x6fff8b382c42069886771dda5cd49869fd41b9af7a2119a067bcf2a0f928fcdf","0x37ffec617403c6cf1ea4da8e77d504cd87925a4ec654682a2d75cc5d49ad3262","0x5c89282b0e938859172e543cceeb42021983f18cc3275fd4dc03b280ba2f9c69","0x49f53a772bb5ac91ad7c97eda2cf8da9593c005da439a2fca6d54cefdd7a1fdb","0xdd35d4855fc44b8df904ee4df61f657f00251f94acee7c16984249f7394334b4","0x2458189f1264a92e36f9b60493c7934e9a0f53dce9565290f7bea96714d883d0","0xd3b229f3ed065fb46f79ad04cef95cadf6a48160d6aad3cd698811a01c3a2bd1","0x52ecb12bef7f249619bac1637de9f73964ad6f197b6236377d5f125ac5998123","0x68df4888876eab6fa02e5bd8f16a29de6ef754dcaa67cd8e1a12ee98c13090c3","0x2d6a9e4bfea15d1e9435431f26a01255b42b9f269f439417297f11e832b639d7","0xa87571dd29d3afbcb5a8e91c9cd37eff51bdbd30b16190a23dc6802003bb870c","0x58a75fb235b621ba4ad2a874b93c728b393e0b1e7be076dec5c93b2a8627ee0f","0x431ef29c900d7aeb5376df7b8cad63e33f8e1f734db195250c5f1e537723e2f5","0x187a03c309c024b6c718f25ec81ed14c7f3cf807c384b202094ec60502eeb910","0x9817e05623248d8042cff8c229be4b6547e16584749f86c5d18f7f490c4bfffc","0xa4b59bf29ddbd97c0ae1513ae2ab3770a6bfcb506ec455bbc9a80f86ed7590db","0x4863fb11f81a90d6002ff271f015269cf0723324dd3b2e0004dc31c2d47e6327","0xc192d46a3c09d542f811411e8dfc6c890195f63456f6290c388de5ef2f69c09c","0xda04ada97c524f45ba2e28da3eae4df6ef73b1b85602d16572275dec359f2a4c","0x5769a1798f1e0a7ee8f97999a4d0d38aa128bd9be69bd01ef363f5ff14a1fdf6","0xafbdceff6c900092057407208ee99ae8bff6d0b529e05722382490c7214d81b9","0xbc32f0dde2b83e38a9c4df5affa78ef939108313da4ca1b202c8cdbe753669b4","0x45afe7c1cf090067a51657f2636ae5742ddd0f19e0674782fd793703273463d5","0xf69cde36cc5638f7a39d3d421c4e59e6f865b0e156add4fb9d9d61f98f36a040","0x46b93b1c55b36a79e6d7fe796869252b53ed739f065e837e6970ba2f3041b5e1","0xcebd68364c42e2266f97b8468020bfae21000d3f994748de9d73ede216053e1a","0x55893860593cd0629f6a27372fc71d4d6a9b1bed300e072541a74e30d4b7eeb9","0xe2868fec3ef8334bf74eab43a3550bb1869c0ae28c3b6dc733b8dd085fc12654","0x23683aaffecf98931d65743b2815eedbaf83a54a1ac8f0a60a73c19c6e6eab7b","0xa1dace082d0d091e16b163be0f4e287a4d2026b0a77409ca9fc589e46bbdceb9","0x6fca388996aef824f604a42a6a5484ce93ab7331429a3736a1db6d2d985847bc","0xf6e4a3a26576a5e2c6d4be364f6fed6364e0fc9802fbad9952f24a9d9f0c7960","0xb6a035e51a683793f4fe1c47193a5fc184287783810e964308ffedf529e5d56d","0xc50295d3ca46fd18e23a41b26fe837e2a1d4dbee0acc589aba3ef7700313deda","0x2d6bf9d5e2f85772e8e27564dda5936cfef2b205bd6b88b669434e6f0700ce37","0xb70e669e0c48d47dccdff46762e183cbc5175c827bb3faca66b40b0adbe8c179","0x31205cc710f9c154484906e816e8e9ef1beaddc351284c2922340006af5702ec","0xe2385425aadb4bcf5c0d305c8c34cf2c9c2b17c58ad426c68b4a6464afe77a46","0x67f40030a12f994c2d362a2e0b7d1aeaffa4c87074eee099740d591771647e33","0x391e768adff003bf7a4c46ae0b45217dccfd904c49f1b7e6efa84e6e06ebb510","0x42b9bc7b8a5c74d617fb59f5fa179819c0dfedf6729a635a0b463b011a207281","0x2b82658390556e134708c50d0fa233f769d7fca3d3cbf6c05fa8e164a33e3d7a","0x92b1574e6d7debef082736f4850072827f821767b26b8c677779a0d48d69454c","0x7a86d9df4e733f3e1cad5d4ec71d5eca92002fac38195e67827f4b375f3825d6","0x6f3422c548467c3f7acf53442c79ebff25bfec644d211a676aa866ad0eb370a8","0x2cc700c7f8a4a527bdf2c4922512871483e22308584b8ec508082bdee3a4f02e","0x3254935d3d686ab395a489aea11e759ae014701d5ff1ee5b89148b81b9545e6e","0x194efc010573f36ba2ba660979f6c306cbfab9637ea5c4c781b7846ed6dd74ef","0x00382fea6c6b7b24754444d222e2592df58f400a98be14c8f12b7da41e6aa6c9","0x44d087788874996e8bd51d29293fce14a507c19ff18cea8ef2563d3b15185e8c","0x13334f9f191e47415f9e8c16de59b104002042557a98e89b66359015bf53aac1","0xf0cb840574347bd3ad9658d1dc21c06acfef211dfa9e8d88768dac5a703db14d","0xbf8c26029038f46c2748b5ab4a1fb1481d4ef31095b51792df22fc67f87b3a0d","0xf4c01c5cb3f51303fffe5de687b130a11440c06648d416c60eee1aa3a34a2e7f","0xf41d847a135bb692bec5df8cef8a33121ee561dac804d1f43147a0362d494bcc","0xfd0e25f1bae126ef867c9243a0cc5ff9336540ae81bbfc21a4c582ad901eb744","0xd8d1e5a9d9941a2b5164ab102d7c47218d5f74b5eb39928417b28f6e5609bab8","0x9ae9d8965c95ed4386a9efd93ff6a69536a4e742bafc419407a0036cc6cdd4ad","0x269b905b313bf468f2d30a831df5d6b606a64cd5b722f8a9d6b71eb7e3b3608c","0x347b179a9ea9b1ec902c76504339fdda954681277a3cd731a8d40077f19ebf5e","0x2b28f40a772cbf72a000a14e2a57428bf3d896caf139734fdaf3c9701935bd6f","0x5bd9aa96fd0ef9b021309a6e8692e1441ad24c6c151ce4a9ad4240828a27249b","0xb0138272c28cdf5b99e931847965dc65fbef4030ed547f02475df2db32a717c1","0x0b9387b1ce909bfa447ebf244f7d946176343c13f31b18e34e9f19a8f4fd4d62","0x22823791f567b30eba2029390b3f9ae00db8109317d9406f701bf2aa377bfef4","0x3596c06dc9c52dc5ebdc51f389fcef3fdef94da4c3b4aca5ab23a114cc72468d","0x8582c6302189fc96a639464599d34bf596b342030467a09e7db438346f3dfe40","0x5e3de28ac838272d026d4491f83926376957c9236032717deb4d7d04e4091652","0x46d08e706b42dc5fa244c017a4ac3afa09cdcb3ade223112eff43db0bcc67595","0xacf6a3336c57c8f96da35fca91fff68c0bf830e7fe60ea2b5bb674b5c484ae2b","0x1dc4c88e7568c8df62b58a1667cf24858a86c37e25e47f4f7876b0d29fc72a25","0x9b8d191e0dbef4f144cf020c585d9f1a5239864a305f8b8a165784873430956b","0xa416dfe91e306844aa13e5625f13e93d07ae25ce5c33a1da43cd0b1e577c3717","0x99225d4eba115ce52cf703cef48cb48711a4ca2e8370c85ffd356af43e3b9205","0x57f6aed1af1fbb90d8ef31a04e7478caace143ee45d61056d0d8c8c431b78691","0x8c398aa48e1c3733596ede5a64d2a6f41d34e6317bf1956ccbe450065d532459","0x1517ab0b77d69c6499ee22a8996590fae6ed48c36ce954c466f5a3cfe68ec7b6","0x81aa9becacb70d747129e7b5af2460e989eb4988919572be7a9fd087b18a003c","0x9b5bf9561d467455754ed9c720ec2d1c3084cb676d2f8433ac82441a58ca441e","0x63334b05fe56277d601156130cdec2e7a560ab20f6c13b81bda5d692a5952c52","0x4303a214a5f23fdd88a480d6696fb39edb51dabd0196a076643437ada0448d51","0x90ba1e47a9fe3a90996d0a230510aac712868c89fc29f59586b67cdd1242c564","0xa3a2b3d7ee68b487d43d3888d0a3319cf0f294aecd7c29416cc4180a81f357c4","0xe41434807b2e15543cf7f749aee889a97fa8f7ad5f683c63cf61192769c04a7c","0x41b852650e7ca755addc9585080052e0f732377a65448019f40fd2dfc3c5f5c1","0xcc595b1ff1604f3059e42ca9b667cd62290fb6ca35da8f7843ec4710bbd2b1ee","0xe6e3f1ab99a3fea76acebccd1e3652ea1dd64bdd94806c8c9ef910ab41b43207","0x0022cae4d260e8b8d7d9b74b4f6fba5369b6ff0577f947e939b982e6e3b530d1","0xff4bb36a7b9bfdc1e88dc2e30d921ff05940d878f5e67a07fa34702eec26afd2","0x8a8ee706d158420e5c1705eefb5503229a5332140ee14ee9d293d73ffd7d6b9b","0x1d8fcc0ed67d6b2e79816de7a0da4fb381599ee013bf419f1ebb09b42f7f5810","0x8a497352aaedad63b9c6be73ed35e104048f78589b914561757bdf2929022f87","0xd03bfda282e175f077d77683f54126ea32a3eab163dac6a20463655bbb046a33","0x685b87b2c1b325513672898f94a47d44218ee31aeefb87aa20bc880a804dbbb8","0x98eac2de29f8a76fc1a6d376f0499ee33314c49aaf89d8693937c2cbea8424b6","0x3bd73125e76ca5116ba850f612be8a0c930199ebc7fa653f9d630b7a30580106","0x87848299cb9ee0c6009d0c851b16555f061440db1436a6afed856e4888fefdb9","0x133e4177e03d9197dba8265955b59f9e1f8f68e13ffd53b7f6ca836aaa899608","0xe61a333de66098c8a7e8af72f25b9b6e9fc3016cbd5953efa1ac23695a3e2dbf","0x400dc565f031f4c69a8b143a7540466e0d2b3c4a9eb90ce113b210005d3d17a4","0xd748266489ea679d34ddfe8bb1357b6e133968bc667781a20ff6ee201388d8a9","0x5f63098bdb29cb8db6349840452313aae303778b6d1aaf551ead656e50a3e854","0xd18cebf6d22c33732afa032b8b069e3229acbfb6956e71906b6b369856a253e2","0xa824daa44b006aac05a86663a20ef5faf497bbeb51c317a733a5d0af8232496c","0x47bac940de9e43b28331a34366d2cec5c01fad17d7efeb71671a7f09e37c8973","0x7e27b295dfbee7015e406c6ff26b3f50748185a739f5a9455e1fc293ab98128f","0xca449d29a71aef50cdad5473f5ebac2cd337957289743abd1baaa20d6898ad15","0xddfa62292f54d342cbd3d0e191842ee137a0ab1070291f0a7d99b92021d61170","0xc3d104f5f89d9d3cd91a1a6ddc632d100dbaf17a3db394e8cebad1c4fb90fe2a","0x3ccb7ed2ff685222e206171329eed624c581942726f4723cc7ce928593723720","0x56ab09142f66fc2c900172b2941cac628378099fa16a7391397df21379a326ad","0xb8fe7ea94e02fe1ef3b6c4831f7a4fa7972255b88639da38b4a88714a3a8421b","0x9dccf3fe14043658ca72ead1b51a74301ea294a8a3668a3d554b7375a5a1b912","0xc18f870212df5012e0eb4d959bda7d898394e6fad494608cc2f9fe21eb5a9fe9","0xa189eed68643a897bb5f2c1391c59182faed10b800d8ca41ac00de1151acd883","0x03b3df0fc71f8c1539451531cb83f84a22872fa57e20c0bd83b722447e439d06","0xe850dbf3cf767887209dbb5a63d06a138dac0fe8714efeb131ae5c489c97f228","0x41f45eef18872e55400075a7f7c96212639e9911851aa7070af07773dcbb4fd4","0xb45275523aaeef5d65e93c53998c3af7fc75ac8201c0e3131b870aac2aa941d7","0x048cd6ed31dc7b492512e996defe7bc1d7c396300ff8fd96dbf7a8d488b7d52a","0x7c4296483b57426e092f818d145daea468a9f1061b030d807b7fddcb53e9f0b5","0x0b7d0d7e47f6dc821a187d7ca3f82b21a052f0716915b9c2da6e9547b1617852","0xc042443a71018aa13cf032c8417cb8e586e5299b41b1fabf0f9584b4f022c666","0x84dbb7c5fd68524defcacb16104dd4005e80a78026a0bc86adffc647ce150cfb","0x9308db9e208f5067cd345fe37c705e12cdd83f08de924b9df981ee75556010a5","0xbec60adf54858db1b4f9555bf0d7d80d4df029bab5054b59ee33e8516eb53139","0xeee1cda75bf3734ee03d1ebe6076c22572616aa0a3a3abc7fc0ced3fd0f00e01","0xdc262da1847682b77fa010260601abdd874de057115cd7865925f35054a8d99b","0x19ca7ee1a1a0aed1c208a9043ffb3d9e4e5fc7a79f374dcfd618cfc9848bae28","0x19cced8ddc29171436eb1aa41cc5e90a4b86b8164206810026077b9ccf64f67c","0x78bc17183eb80eee18f40a4eff4cb3c62da82f4c71429c6af89b42130fa59ea3","0xa0b52b9ad294c496e76a0df6e6aa62d0edb9fae8b14c41beaa3bf26d51edfded","0xb95d23dae69fae8ec82322b254cc3a50487270f696fc5abfd73666cb888fc08e","0x89ba92c1a7fa6a04248aadea2b741a56e42922f630f724230ddc572360e99033","0xc007ae7e4fc4b9512ae1467c403d4b9e9ac4df84b8697ff6f2ae436d092ed9bb","0x6c4a17e99265a3485197f4ba9a6d6d47f1bbc0ed947d99a992ab208aa69f9ae9","0xaa68104ee4c93b7a15ddb8c69ad127a9e034439d0b0b9bb17b38c55339419ff2","0x2b48a2c25058751daf0ee1a9b501d923d2c6069a50818b78703800b8e5efbbe5","0xc1dcf91b89d259b42de293bd0df131cbdda5b4081134c69b85e9be006a27c0a2","0x6b47a27dbb84b845fb968b1f68833610142b67e21d3e9ccd7458b411fe380cf9","0x58a1520f1e29313e1baf470bd8093e8e438ae678f9d6e0caa8d8c4f320cca37a","0x90e20278c0e7adea7fffa6dee2e88d61d8598163354f113227a4d750cb9f479a","0xcfc586925fa0c72b3dde3998ac4f9c199b7c2e3ef72919239e305764774002aa","0x54e90e2ecc5d0230178f5feeff8c933fdf3e961ed93facbc9b93db18efe9b676","0xadf91ec2e67b6b2259b6b8ec48a8f6e2f7a82a7e4f50c9da09227883afe02f36","0x23b401fc41362f7dc25a27b6475f1973629e6ba895794ef6eb1ff3ea3bbb88dc","0x8a8bf80bc6f637dff73cec46e7400601b95ddf4ca33f8eb12c3be0e9e99403d2","0x84bad4ab36bc007a04e26c77dfd6729c9ab49a74ec3f2192f52e466acf25310c","0xc2dc8304deab1b2694086dab36eda1172e0dbc21a5243cacde317a238b9f3d43","0x2ba0f1f384a031bf7bccd5ef3ea4424ea452ed55ee3fc652a9c8d141d5379c61","0xfd167ff1635852c1883a66c7de706348ee02ede685f3577de2ea75637d07b124","0xca5b87480cf9aefcc5b3d0ecff4906fe49d543f03f6215866a9f700b872bf031","0xc346fa212dbf3d83f6596fa93cf836b258faf29fa67c499bea8c3a5c3523c7ec","0xa3eb87aad3e77823a3714ebdf12b9a78c8dc00085921c89f19ccdd4efe37431b","0x3c899f9f5e7414eadf3ae438f974d9352b4ed8c5e7387c32be2c29ffab224b4a","0xd7f41f4d9aa950a6539f372acbd0d3c7f20216213155d8aa0169797160de7970","0xfa9183ff44e92c70f1a3ad83156c0f7ad6c1322687cdaea4f79db16262b79494","0x1285a378bbc3b7fd5608e00b8f061920b9d8d4a0c3d3e860e59b68dd5f811b08","0x70ec43ebf116be7276e6f450c06f6fc6259c6d9ee8d39ec09db8f7c0b6e5ddc4","0x4eb221e37d89b3cb6c3c880abc645546e9e4ddb2204cd9df92af5a93e1978a23","0x057278620b834cce04bb4d341a5256b8099dd90a4d1b787e710fa68614c57f74","0x10520cc8eb31479cf8e9cf5de575d20c1cefbd6a1e02440f9676f318a4baffc8","0xe7d71c0f6cee4338d11b545f95ab44f492404bc367aa4a4d31ce406f892c011e","0x4f37fbf62c7cb73f1915938f3f4af84f6f60b42e252e55a9c27a7b25f08705dd","0x53b03486d91b6cc0413d09711af62244a756f4d12039b9580894bc512a53917a","0x4dc66682063a21d7ceec3ed9cf27372abc4348a895e3527eb7cda1e94662bbb1","0xce3a45dacdb62f6ac595a599fdbc222836e236c204ce001f261f3bcd01e7c9c5","0x4fd91b4ee448079ef6aefab08ca0091914400b58eb60460cdf9ef6c91436afb5","0xf590895ff8825948936a30baf3f2674d4397c72a00cd247612a522ccb5e6d90a","0x521aac66c1a45fdc211ef02a3a155239fc838ba38f8f239f1ea332c81b787c73","0xa36303de09f95a9f91945c1babc75f230053b9b946c784b78ceee8edcd145d06","0x38e607127de7a7984342f9dc488c05c4932f0a85ead9d197d4a9a8885fe20134","0xb63cd09005a8c17c1946b1527dc66a2f7dac47da8d9717dcaea1f234ae6de16f","0x612c8cf2b354297a19f36786299bad3cd246b53be3b5fef01f339bca6d15404c","0x11f9a7cfbbbafe9236004d1c333851209e20174d3d6b0408fd04530664b0a689","0xfa1e5746b8798dbb5dba3df802ce295a07f031d44bde46c7b694adca92223da1","0xb28d3cfd3651ee731fadab0b82678e14f347ec2c3449d4324b9d70f3627de346","0xfc605a96e2ec5885104ac5595d05cd7b33b1a6e689bb4a15e180caa89a97df19","0x186a8c21123cd5e38a38c3df9ebda9e00cf9db3c98616dbcfc0da0c4694dba28","0xa988d85720c7d48eab2825f35c222dd7c317a9d1629c31c92014b506d53660b0","0x246763f6ea89a8fa33fb44e18df0d354b1ba3d8a3906d37ae35e3d1195321280","0x166759316bbc1b3581cd96a26a11a7c2dee2d4ab1a8f4afa60713ba8c01fb47b","0x16e597e70968c1d9f2790c89341266b7f0c90b789d0047728cc1c5931bca4ff6","0x4d88525476930888ed24fe98b42272ffaf5f2cad7ec53909cefd767988e64c3b","0x5b3fcdf22c78c4f9b9994fbbd7f3fa33e240a8f91e2e02dd5e282b485d144b62","0xe97428cfb91616187f37b819fd06e7ad14471e099ef0995a024fea718ceb8ea7","0xa35064fa12d1d1f1f5d39e09d8ef192742c1c4c69476b7bb1085ba608438a4e9","0x7d5c7b393619c87cd55631d3288f4a212e2467daa74ca562c4e58dbd4a81512b","0xbf8678aac64e955c45c0c26b84c56485ae9edaabd43ce2c4485146788472db5f","0xdc348c07977e5487268e99a302d0c29a1d1a7e712e4062299135dfbef08ccc85","0x55951ca3a9768b6b76a4b988f1e445e0e5502a19915f38e8d18fc6407050021a","0x85a541711a001cc9ba2b26600ef81bb3bb7fffd9acaed179233f2406d90a69da","0xf380690a0ed3b54a8bf58d5538c4e831257f9ef3469c95b5b9c9871ec14e73e7","0x03730289ad9a483159ead47d796dc9ee3bf6cb7de3ae8adeffe8b975a413499e","0x313cab7cf41074f4bf654fd91de2aa39d2ede269de9a794300c8580324af45ab","0xaee665428667bbe9857c08e0779e253265b3f1dadd650bb7134bb2db9563616c","0xca400f8b5549b2557a15f6ae616c4203a8872c8c3e9ce44c0c90a4ad75ddeb4f","0xb8f4222878bce0125dd4db1c5b2e802e24a6645142411d79be32cfca2b0f474c","0x351ab83b101948b5516070bc4d20b3b7e2307b1d20036cb8ee7689642d75eb16","0xe50012f19c4cd137448c9e1e1c66439890d52bdeee5cbbeabbc9932cdb5841e5","0xc7f7072007f64cc54b57391854b540c3d890ffa8167f79a030365a842e4f8108","0xbdcb966f10d6d8d092b804551799934033e698121b08a636ab972bfa86deaf25","0xe199112c4be31cc0dc98540de9245b0d5fa20fbe2dd65399b7f9ce6629fd89a0","0xa850c4e85a20b575aef2285e91dab89c7eb766b6f2d9cc33be5bb5713c9326c8","0x5318a520053a59f8f1fdd50df81abdebe15dbe991bd78acc14a1698ae46b9530","0xff5d5b543a3cc1de6d1a81e7b298c7df469eea150920d183516b24159541a9fd","0x4cc0d4b8e9e3b32de9e5b1fdcd4eb529baf5e81895e1fc842d4eee54f0f15083","0xe7474078b9bf03f4615267769b304b47e51cec06e20e347cfa72b7eb89462891","0x2098e8b5b4d6b48802e91802e70d346a74953479f9319e9924f256b05c310a15","0xedb250d789263c5a7aa697ea3c2b2409f9d04e678a3547ac4815a19f41cfa55f","0xed905dc4fb4192c9d70105c74f454e806a3b8b345b5ee7b15044e95c83f3ba3a","0x16651725b017940d175a7fb7af6d5cff4064c0c29b2d8053868bcff26fa2942e","0x6d834f0a6744afada54f7a3671420eae248ed2226abd554201731785fc5cc9db","0x2a1cfd41dc09c8b7cc7ffc5e5fcc67a238ad1c1a311058376b469fc3f14ce4c3","0x1c73e0efe60ec6011abf2b7bb06ab4e8409f502e46af7ce64acac10769ee04fd","0xdf0a3094112e05d57daa9343e6e31a46fbe924a482d08ef01f68fb5bf108ed2f","0x51b4ba7a6c0e1300ec9f3fd357ab64c48d5f021d42f6c7ce0a124badcb8135b3","0xd16e94fc8714a3ba4bfc0e3967bdf0a8b7397288836e4015c8b56d4c7d29be3a","0x00de3e52f1aa3e2b66320fada2a6f430eaf7c978e54eb41b6372989be564fc77","0x158c2c94b64d060eb71399b6865e4b45ee8906a083d4489be0c1edfc1095229a","0x172f8e89525f39b4716e456a0162bd763d863fb4c78ec15d6c5a609017b71029","0x218dece1f85992cb21bd3f636b1c305590799fe0b40b808c7dc4d7479806a140","0x5e5365e332b4a1fb8412b839d57025781252089a2204bb65e07bc7aeb8415b9b","0xe4aa9d148ae4cdd20d41ea8e6688ceeda2cc8e8d111db8701aa34129a6b28550","0xc49425ee3edecc09482236013b9c497cf29d7f978e5b23f7987f43aa21bf6e51","0x4f5162eaa309243b288ba8e4e83a8719703ba85b77ffbef12339692646b1aff8","0x4328e51d5b943b0cc2810a518a4d9c6bc19f645bb1962dc2557ffa0dc34cfb35","0x5599a7ff9bb230b354ffa20d58a80b5cc9369c2492ff9a82d7cedfcfda44bb54","0x4befa9fcd4befb20b77a384b1484af3a455102396542377089039df35dc1d072","0x7b03868a0f5f912004c5fe2e6a26747fecb65bebea3849f96a01f49634bcb06c","0x3850bf8163b5859075180fe0e199877c351a9569936c061cf816bf8f063ad931","0x4e003e924a3bbac6055f614779ebddf0c3c2c9e309269d3fcfdace1161384e6e","0x01d11abc4e25d4ff1eaeaeec22f142d08f2f74e5a96b8b9507c272363ac4e875","0x64c61db7547d65f27a592204de316a897e772ad12b979722a797d4be0830cd6f","0x39cc2e74f1a64607714c4e6b6d030b5b12e7786345ded0ee15905a2d8531af1b","0xe7e572643bff6c1025aa3e3c8d6511c71b8b5b81b00b3f9bf643a9e0688047c7","0xfa3d6c0db7475aad9089ac0ece79453677ed683599fd8300823cd626b5ff6735","0x025521e2529b5b800a1b21c535b65d7d727804c76436ff6255b9ba20db2d9866","0x46ee5265c45ad98de4a43c1681699c06a2db5bdb23e8fe474de638747b8517ba","0x4dc26da6ac2ba573a6f5015243975d12efa033bb799eb12b64f4ead7cfd50cf6","0x5e807936336a9f3c525a1b6cf15906376e039f5a9f1848865fe33e7c1b7a7108","0x1037887a6b84384058d378041218d28cf20cd8a3c14ee750d8a0e375b8c69f2e","0x326f3e040e28b1b4949682c6007b0a2ddf30027c75edb921c21760d9e78a0455","0xb28cc7d06a41e35218928c78d7b241f0f3d3852d5eca12bbc7351796288ccbb8","0x8f332265421af6d5c413a05356f9660e5221af13ec85a2a3f647ecae207fa8ec","0xe0616a1600e6ebc2d459ddc6a269810298f4e1782e8baafd0595d734404f5cd2","0x09ff58709d0cf21ab651d28578348329b8e5bda9257dad0d1028194e9051a68a","0x6fbf1baff4bc4255ba73bd01c99f8422f0812eac08fcd6de22ff5e0d86eceb7d","0xe58aa24b0f33754b93b5ce73e6bd0794f5723ed9f2ad8ce63040fe10b0ce023d","0xb73f8525976786e3726d7f0266725c271c65a50bee13e1953e725c69c11f5631","0x6f2a656dd2bb8831a22f9c267df3732abbeee712b34f052a13f81f1b85427b87","0xd6032fbfe528c26362d1fa4663441667b22eb1bc7a5d8f09cd6266ea24101584","0x3b5a7818bd20044dd9c2b02b1687de57b0ab6fee7149ef3d8ac5e2ce42063fbb","0x6b5346804c8a6cce7c25d80eb9821f1458bd4f8b5a727837e1dcfc755b70f6e6","0xff29abd8c51c721f774b11200f594b9e6a8d444822641e15ea0a6f4e92a25dcd","0x9837df82f2f4877058d9076665ac534735dc4c0a845d490232c2b76685d2cf99","0x50c0269348d2d05fcd6262df79b1be3f89871160a960e90fc6d264219a0e1995","0xc39ec0adf6cf7186bc7948a7e3c1fc30616a175f6414aa34381801c5fd0846a9","0x974b67705484c45c341b2c5ce036b2b1e985a767609728d5e9ee3c1e089ea8c2","0x6ecf1477c1c84d78ca21a712eb101c5545bbd9347d8fc780d410f2610f74976c","0xad911e1d322f8cbf9edc52798b1c0efe1414fc8c8e0da674a00f86518a2ff751","0xb777d903ff2aad5483f0c329c43ec3d28b563b2b4e4f518ea8443a268e3caa34","0x4a3e9bedbb8735f26df4af402cf02f9b60dd4e5a5a3ad383cfc4a906ca5b45fe","0xeaadf2d53187e86e9e376aee5df83fecd1559450968b39206dc42613e4a7402d","0x93eb6fb3d7c9b36cb340a69f0d2d5b35e8a53def1a57f26868bf1e342a14e5a3","0x3b1a653ab929a1aa9d13d92f13e3564ccfc8b79eca170bc9a0c631282c51c9b1","0xb8d7e787a2cbc90ead2f3b02b18b7b973863ad3202527c3cb89290b0181498f8","0x3fbddfe17f4a5605df163bfa93479befe7c745342d1100655996503a459f80c9","0x7769f403155bc75d784b319b567d6596d7fc297a03ca68b9e82e00e1de13dd10","0x285df417dcf715812cda831b6d533f399fe3e333ea4fb914ae5521747acb4229","0x30f8c12efac3343b3dfe6d8e44ed3c7c78a77e3a3068db85435cac898450ef6e","0x9bb62f996d0ea7e52945b09e41a871075480bb371d19d14f5e544696ffd8d3eb","0x81204a59b4ca714a2410e1d3f10c5243f5a70351747cf783e508c3d3eef8c753","0x72f180d40aa1407118b19c8c36b99b0697026bea18cbe10ab431f3b848a2e316","0xd09e428eca2c6c50f0757a8cfa4a8cc010c8ba7ff16bda0615d1cd4da25d6f70","0xf0d3a99ef1c45127dea6d9609d7f2d9fd114d7436390e92788f66628635de0af","0x4ebeb2aa39eb0a9438dee17d1f6c06c01cf0502593e087a20d254bf832554823","0x04114a35b67f8905a1ef95f41444fb0982b87b1b76ed7d07dbe1e59dd98812c5","0xfc70ce0dde26037b8d2b0137b3e010c404ddbcf070e8f4c33efce6b7e779fd45","0x7dd803d2ddea710a05ff4e623dddd7665097789de1690927e2ac2fbfc70afe70","0xbe15eceead65102946475032e9606fb7fe9357698b71fa11785277d17d78f45d","0x9793669da1f8d9ccf04d4d1a24a3c2038ef95d5c14701dd8d541d163a7a1ae66","0x0c34395b3d60ebef511c1a1a578ff31f155dbfdb43fb20aedb9ae02351f6b2f6","0x42a07640504354180daad30fd6808e0e3251bf6af17f800001ef0a3123773d00","0x0cedf5f49b38d4331402483f0f68e6af26793e03a6c6b2dbf8aed37e2d8b9548","0x839cee91693d2990130632152d8c626f1fa9a83073608b48e987fc54ab9a5994","0xe6cc36154002e3e8182463cfdd74587c07611010831db9ece61be4b457bf9fea","0xfe0b5e66290e2162a6e31b9278be6c2e89d577a55641434d9c519fafac4d4f80","0xa176dd7dc80a345488e8a7ba57b5b95a3e996696bc0f9f9832fa602f79c62365","0x09ec9e50d9e79abb2fc82c1fc67d6569f8056b2841a51b8f574157761603d39f","0x0c66d7323cd78496fb646fb14ff4160ce70005dd05c89411a3eb90d8ca658109","0x6d0dec8c124811dd712174fbcf0c95ad50a480f25737d5fef86d0270c186ae8b","0x8410452af6533bd3b3ecff906ac9154ef2e0bd1fcfa6bf25ebe6f650280bb543","0xe582a42995b34dbd8b01bd32a12d145c9b3b5c999753481caee4baeb5a7bd259","0x5f4c792f34276e0e6ca976c44e508bfaa90ee29e89de1f10dc2672256020bde6","0xc99e103e86d5baea0bd8c89c13379ffa9c6936c0a0e5197d7c4a73a3131d6bb6","0x946a61733da29437d323791c4ca22ce45507e07365ee06a5f65bbbd76388083c","0xf4d161caa9fb3d9e874b422457a0102b5c2ada46c715295ad17ff1a406295e12","0x58d06f2d54f6a3625f5030527e3bac1b21c9ea13c4dd07b96d7d886700f213ca","0x84f08a20d45b471665abe734af1e9a3129a23c2e54c752fe641e6d4427498ca0","0x2f264cb0bd0eef6f2fcf4176a49fc587f366b5de28632502fc0c17b52c532b72","0xfe68dc8becfbf3d4b1ee1fe5822032159faa5b39ca92d7aeaa1d995127f8cdf1","0x67486544af8c647e47e6520301c699587b8e0798e1684c256c24d88a167a30b7","0xe174233fe0d9fe60fbba178dbf4a7fede5e72c9b8448e75f2f8d809d8aff1648","0x08e5bb9c52f5b170a5e68c3c08b69b41401dd3801ef1f894ca1c67532d1dcdde","0x5c2a29d208a4cfc4e7de22766e29af557a4f5bb1c8592e1f422cfc361b30bb4a","0x5ca84c078aeaf4ffe9de994a4ef47cd63be7b41f32f4a100c95dc6ec08b09ed5","0x0cab8a773c255a1ffe1e5417ba81681fa2d0ed78f593dc4f0d1950ed2ef2e6b1","0xef7bc184965b032ae3ed4a0f77d1ce8b1136e07fe7bb433bde513ee8d5ee78f6","0x0241a8539899c7270c63c9d67638541b9dc5b1174781e45df0464358b3628e6b","0xb2da1b4233ea58ba6db4e3e29ca1e2484dd2abc42de015edf3d0723917c2c073","0xe329f23e0dcbee8c578fdd5a887b41f9831e7eee38bb41eceb5e74eb810ed79a","0xd9507aea1d16227d3250bbee7ae43cde007e2506c634a955aed9d967c405a200","0xcf856eed199b7b4dd7fcc503b028a2285155f93797996b8cc80eb71e6dd1fef7","0x38b4048d6f752961f0d89ea24d8534003411a97b998d15de1eafa92ad81ff504","0x488b2cd0a8e979928d4b38f0b1799006fce606e8f0e7b6d3b085c18b34023cbc","0x421571cd42948d3719c5a7d9529774f906e02a638b7e6dc5d5f7436bbc5bf5f1","0xb5314cec807c833ee2475aa5450ad3e45b3d9ec8ed0b6585428456988a4d378a","0xb76ef6770e380c9bd5e92e67686eff568e27bfdaa49ba0b5bd8ff1e462b0623b","0x478804fea528ec3f85d2a8e90cb54f9e372528b0304eacc8e85596e157af6f00","0x7fce7bfa65547165c5f2ce2a7a300f9d09573f5244ec19c7cc1f328e2ae278f0","0x64c7077c2ea52e5f4c46b18201ed78a86bba8759180b6e05d98ab224fd6c7bc0","0x6dea960b1f37de233fcf1bbeb2f8d0ec6a6f301dfa1b3c02c242a82d34dff1c5","0xd085d8a96cd10c4c6fb3da3571dc8bd3d9e74b3350d94c419d50fdebae7ad5e1","0x581450f63c2151372363e08e8ec8d5d86adfd44cfe71f39cd37b0acef1d822fe","0xbedeeee9eeb745c8437f3319588f40e27a6008103600fe05b003bee75b5089fc","0x0e4318f13c0e3951038f57f342db19f7909ac8e278b1888810799c6fd7c4c491","0xfd98e2fd4ba93da6004ae60bdc113e0cd8f79280a0b1eaecf01cab2a318d9ac4","0x84d164d762843baa2096c386ef7a7ecf7a976324aa54a2cd5984fae88edb7ba7","0xb17f08e8de8b7725167be90217e46c528951e1fafad624a62428a02a967fa721","0x5cbb487a86ee5496eab3bd751999a16b8528c7a8985e778b2e1ade6c8ac8300d","0xde01fa7a739442b74dd6d99012bd568bfe8d7fc2ca5c207ca0ce6abb69bd50f0","0x4743809e9b644ef153ef90a1d06e75f17c70d2c7b4f6d3761468da6621927ae5","0x71b534d43090ce9fccce686b7c209b27147abd7ecb9a07bab79e591dc112c7ec","0x436307250c46f9125c823be4ce0c6bfc5d7bdd1fe009dc4c86daf189ad850926","0x1265922e2ba60e723e335c66993808040acb083d4e679a6e2317edcb2c3917ca","0xe95a1503419fcd2276d2122f3947926f4a19df84409ac5c6fc1c99348994190d","0x886ac7ff684c372802a06becb3c1f1b29456f7ae2008e59b8f5ab5f40cc836c8","0x79609ddd9f12d535b30cd617fa9fce99d48cd5ee906455d05e703a658bb531b7","0xfcbaf8bbf943004a4a49ecaf018264730371ad7c16dc470275f8f1d7c0cadbe6","0x10874622c4c8399364e17afd9c4c3e07a642a3960397c4ae4348174ed2a47238","0xbce30aad3a2eca68d40457690cdf8b3c73f3b74139a9ee01c2be51f29b95a25a","0xe3427c0fa5b3640f6411abf88eb024fb67ea4f2eb31a564d8054899f6ac95cd4","0x3e56fe6245112252d46878499c9ac663e5849260189cd2618b3cd9a5f24b6f99","0xa002a7dbeeefdc81a9daa53fda838ae96e14c8d54efb5ef7619977efd5110fdb","0x4492820a93dd3d1f5f596c98cfcc1e4beb2ef40e32a275fd36fdf9948d13a6ae","0xf3e9adc6ea71035a4ae4bb9d8d3c3cd026544f96c354ed358b2082739b0dfff9","0x0aff1a2675b9f442b5b84ebbe04441c70a7e385721e1e5502d602cd3e19da50e","0xa32d738436a3831809f8ae9bc2cee74ec125ff14f54577eaeae52b74dae02899","0xc55b45b65bc255f9391de0e32c082cba575128023525135830a9b273fa60ee07","0x8f8955098b1ea15ebe86a8856a9fb268672b41ea9ae7e5109de74360d08ee1c7","0xa7a41352ea80b954a4ac722a9ccd1b4b8962c6e0a8e708dab8ee0d6718baa9b2","0x3a5bce87fe8b24500919283fc9a4c5a928b82d2dcb8a8bcc9bbeff70ebfa0664","0x69af50ed519e9d124a011b08592de1ad7d22787f277a3e27ed64a182bf02588b","0x27487653ead369afd1833e84070cbc70de12d97ce6812dbd4265d1211b2c18f6","0x7a479f75247d442c0bd70d33640722687e3efbe4a224f25e22a8c3b263898a03","0x01771c6ffd899f64b279bb6a4af3c0a308efe19bf9e6f0f6dcf10516ad7c1a8e","0x9a4646afaf480dededf346285ed82f32c914eb2090ca8d91649aa5eccc9455a3","0xfaf116826a02d9dc5cafbb17022f3ea5fb2d9100b7181144ff5aa9ee0d8bd1c3","0x83f70d23b7face6e912a30eefdfcdbc248196979f1b0403668c8a3c09f511667","0x419d4c339cf01e2deaa6f0dce1aa59ecd4000f9e2924d99a83170ea0bfed6a69","0x922f59271bdb41a4cc21ead68a10a34376562fa4f316db1ccbc84d42f5906b03","0x543248b0a6c0c80ad88b57472af1cf951da3e6f0dd024928268a87dc237ee995","0xea1d0889d0440bd1f08ddf106a7fc895856fce5e8832403af42083617ea6227f","0x09c15cbd2bf989f6657de4e71dbe1326b426524fe563883cac30e01e070fd5d9","0xd1273aac3261555389ffca48fbc02ecaae35833b96ce71fa8ee5710e5e6aecb8","0x98ae6d42c55dfa3543b3eb30efd144c633fd8067d8c5411d9652edb85a5ebb35","0x57fae2d800206704ef5e9318ba7e006febe866f64ce7e5f7bfc5408dbf8c0063","0x6f9c63fbf6d1bcb7657d4a7ca7ec9ea1af594e4e00421310515fda2a7e96dae6","0xe9a69e93bdb46d8c84a23cbc9b736d7f32514675399db4ab0ae049146dde30dd","0x28feaebd7648670c2987b150d8ba586ffc88a13d6833f99c8f2420bae8bfa3b2","0xf0b7a6986bafdb3590c1ad691edf7727bd1ec7fbd2a4d0b78e3f9085a32e4b3d","0xcd753f2a6e6a283affe680516c3b45b38b691b82f5ae1b7e95bb16eaac2724b7","0x8a27a6394c891c20e601cbe5abd6a036e9c55763f1acfd254e39a0c94cd1dc38","0xf434fe11a069caa27aac50c6c742e3761070ab0200c2da1e7f93cb1a251b6876","0xd26e4f7fb1bf3062fc379b00ccb972296055f4b9cd4c47408e3c38af613e5f5c","0xffda9f53653f8f50fbb681033fa0593034d188f905d8cc67de268dee7bdf1898","0x8f415d41ae00bb676b470fe2f32fb1d5d7c03985a8171ede4198e3399c7b401e","0xf24693e4987d7ac3b749c9c29d5a44361fc5226b48c057c8653c25d75c4c8cb7","0xafee0571cbb86403c1993265b5f61dd18f42dd004ee521d172174c6736227b4b","0x9e125ffd42cb7a2974f58587097c447b19f21359103bc632a0e36a06d7935f13","0x10fdc39799525494eae851e735b7e423afcfd665ec2b591556b4a1957f8ddb18","0xc82e63b18ef106a8d5ee377a411706c9b10e52239e367ba9e72a26e9b337630e","0x79c3cce50eb9f90b49ab4d9cd72b3ee31c45f61b780590252c9574cf9793c611","0x4c2b16a63ff0b599d49ebb48eb0def6460f1948a4d1a994836a13b7e4909c47e","0x88268cad1395e653d226dca9e15cb64f80a76dfffdd3c642bc1eae4deb9a88f9","0x9ffa4c10078b21d9dfd4198098f23f791e7235b2ecd095ca681d96c46e3e4635","0xd35b01efcecf5d7dacfe7d0264166ceed4f1c0aa7627e5e10b8647dbdd5f52e0","0xa23b37fef41a8a8c3fedad5c0f47e0a6f582c8819d0696700144b177a11bfc1d","0xef5d96f7e47432c00fbcad0c56c89c30248d869d738923dc65912fa212858f0b","0x34b35e40b20d27ae9ccb45dafe4ca57ee709bbc8dbf57085cff53f698c79bdb8","0xeaae1aa5ce93e1d1f87293d5398c5e139dfa029a561c094d6457a0c0064b5a6d","0xde458d755c5f63f02f804945750a6279f425242d131c1bbba6bc82e0dc67996a","0x10e54616b9aa17c79b0b7720d7cf04c7b08e2ded74301d909e98ce914406f211","0x6e666f1a853ca21b096066265f5d7787a3f1ff2402ca0cc9b45ecabf3b96ed20","0x766da0f2020c23beffdbc592c63e1ecf418c89d685b220be1219a8f48b78694b","0x31acdeb11e5da22dddbfc36f456ab1dcb7c300baa6e8c649693dfd5dfc5583b4","0x7eb8cefb2af7bed15567803366b292eb395448d9499bc4f7eb6de2cb49158737","0xb97a355212973399b631035b1cd0706a4f381dcea1d7b8a8fe9c07ae5f504f09","0xbaa788abd1efcdc167350bde6abdd0f5500c276e50748dd451b4fdbceeb5aa7b","0xb7997f2427077d2565196e5de2b5ebed14a9894db6dc893c803e3c198befac7b","0x86c70cbb74ac50c076297eb5de9369e528a5ef789b55a27e2f12403e53013543","0x18cf2a8e62ad752b47d6b2d26e8392e96ee83665970e19ddf8351469afd98edb","0x3f1e58fe3fb25d7d1d4e192add269f80a385ba4c60bbdefe5090e6a862094714","0x167893936a827755942483fd12841cbc41300fdd7d4df8f32c557e4ed7ba485a","0x18818b3dfd4b96beadeb42aaa7c535c0b393e739d1c277444622bbe606c0c8bc","0x2c7361e9b142f763a623ee8bc697e54301b657ac6f4f4ea2fde04d8f58a8a6fd","0x08a63d889e1fb7eb2107151b450c01bae8e4474be3faacdd65ae81e3573a6d97","0x283098f43af5b04328885f74a818699f43a62115d67a2ce37e768a4c9b7025eb","0x401e46f10e4480dfba64fd18ffe73f1677e35190cdb1928d91ae1311a1b38dba","0xa0729b5de3fb9d14b8faf945a6b7bf1401e4c17a9b6a8328fe52031c33d22300","0x6a22d00f0cd35d47a5978c7f5a81f4596cf3443baa1d162bfbdc5926697a39ad","0x67ffab3e3702559749ea8dc5e9d7a0727f6f42510e0b8f6f27dcf8cf4d0e35bf","0x2d4b29569af2c4de56cde06fef9f9c72b5f73077810467f1e48b26c0c808deff","0x347dbfaa9f56c5678d239284d598eb75e8d0c921f2a5c50547b1e7cda948a3a9","0x394f27ef1c8d1cebbdd1d9bc5dbbd74419aba070f95d3697f813c25ab50a392e","0x8b599a3367a3872a1acc48642dd551f1a2963cbf7df66284c4bd7a3dc35d1648","0xc639cedd33fba526de9efbe60f1ac0186d5dcd4a00352ef0bd5d928f87519ba5","0xe18b7292beda36cbffb8e882f3f63a838634e6667827e9611f22bffb8b8ace72","0x3b4b628df2aee2f01e7ce128c1fe4bb891bc12be3fd77d328f49a8c15c8b9c09","0x6bf880585c58bc92dddc3049c72c20c45bc683976653f22899d5ade10300740e","0xf8d800f057a7e548e29f73a58a421bfd36564b70bd263ce838e4bc548af240ec","0x1504ec8f00371a7fe2af6b741f666b2e53471675dcd7d99a8c7e6a87908248db","0xfdef5be3a88e1bf5ad9551de493dd0246ca1845443ede1b898d18c9740334c9e","0xe5c615f37330c8fb6d81540e1172174a108cb1dd98a0755ec10086070525eb1b","0xfc7c16a2e2c29b9c48834eb869f95eb78aecdb9ecc38019b3ac31ac2c6c520af","0x478af7073135df36c8191d9a87911d39df422ec13ea0c5d01840354b1e989bfb","0x55f1307d33513d8132f2c06cbb455980c16ef81e6acad87976a09866fde9f973","0xda4decf8202ef7991e9a605787f46d092c5db2b8d61dbba020ac9f5cc52bf94b","0xa2a8f0adc3c64e0b268178205fdf1c9ed1c08ce968e3e0c9edf8ecd880bf5130","0xa1ebcc6447dbc7bc94f014117a75428fce83a75300f71a42e8902d82cded4bc5","0xb24331d9b3cf842d0c142711b8eb19cba881dafa47a1a34f0977ce8cdd167d83","0x989d59c5a28be139b4571d1cc4fe41284788366009dbfe269845363b78772083","0xeb79dd54fb4a96142c6eb021d587b33f199aa067ce19893f29ef187eb1e11ac7","0x088e920ee6924348dd75350f1cfc889a6ac8a57fd358c9b0dbdbbcfcda0e1247","0xeec7a1382f44a5faa20033097ea47bb30674f5097ed691f4cf3e7992f044331d","0x64347d9cb486f178d12ceb9ec474f11740a32a77a56b6dfdc129bec220278171","0x6adf105b778bf98e8dfbcbd91b8a5ffec24c6c8847cfcfda4d375d4971a086d1","0x32e7ecb8ce1be68fa9aad8b3638402c96713fdcb85c7669a335eddd3f44f2815","0xd4a27b44bc733276b37ba90437391010fe50691fb4b23a74f9a65c719b45b4ea","0xb9d25436913bbd87c0f8ace88081591a629a7ea428cf9a90b6d85674d6fe0faf","0x5d56751bd4ed29592c7d466c8ae5c614e25903e853bde2da44d5c7eff1558b62","0x0e3de4a455bb373d9ab87570f50bc83ec0b1acd5592abc76e2b9630cd6fbd276","0x95c614601ab16edef2ec573c1b74bc71cba7158b5f73370bcf8f24024412bbe1","0xdf1bfac1212679d07d1c8f812b7dd8cefd54e2a503fc6ec8d30a13713c181ec4","0x2d23f87e00c5ddc554f1dcc15a7431709af35f712a92ac306051b200f082e7be","0xdb10f2ffe456b4b9fa42fbee116b24d538327aec82aed403e4911ce7221f3f84","0xeb7e8d29ed2f8051c2b867619821bb6ad4d40eba931d34817d03a8f3850c804b","0xec43cddce047c19ad9a5e85a2917195c8a00baf00a8a8b632035b8ad479fdeb8","0x1a58cab8338e8a3a9ad6a7cf65b8b3be602eb72216daf40f7ee8a66382966993","0xcc62a7d68db0975cbf186d4afc1963cdbc9f4a0fe7055704d2cbc517ffa2642d","0xe4ca3c08a4512bf370bc96f91e47a3417f305164c9b8cea08a1ff08346c20f3c","0xb6cc60bdd9dde883bffba95b305e5630f700949cfd82b7039dc28c9884127b44","0x60541f40a7e40302b1e8b6f3cf9d4a12f3b4b13a63581e4602369c0d4ac2e8d1","0x17852145b016d8e3edd55785045c28bcdc5bfbd2a68aacba7017543708dbc167","0x27ea22951e567d2d0a91b92447f243671e4d8bd9a517aa219d0915ff4a91aaf8","0xb3fbeffbf23ba29fe0f97b06c1d7f05b8e15fc6ac7c5f3ba9e946cb499baa2d8","0xd31e9d82598134d768ada7a34481e8df6753a3d9a0474c7e47f834c3ccdc84f7","0x87e36d8ec805e50c4a9950c88b9c15a875208ed11d99dfa903ebbddaa62efcd7","0x8a04ca23e400c8d5d216a9d22517eaaf1cbe8cd8b22ed7fedf43bedcd8e014cc","0xc18cb0dfdffc5c3ac0291f96a0f1504d053a6551e2fb9c30ea8ace05a2f04c23","0x9253123fc8490f41da7336c6d74c27b9c14d8b29909fb509ee07b880c873a483","0x5c6cfc5fb7a2c55bc91a089b281b16f8901c5e6130116fcfcd62287305e2f650","0x430ddcdc4454580d24d0c882c6e9ebfa01ffc940e32d1c979420d57fcdd1d4e4","0x40ae905859dcc17f9d4696304fbf8502e501ad2ef7282c43b5aa6555b77edc78","0xb013376bd2ddbf5f8402919ee783ae90bb91b55b1d273ab6ee19c1ba74b2a5b7","0xc2465b1a2a998856d7991dedf79526e892ce33c04ffe45a7d91ae74fdf67289c","0xdbd73f538c899280b7f206821338a0930104620c4dac0b8a787e585deff925cf","0x6e4c1a987897d3d8a33e4402842900c881dfcbaf644ff52943e28bc2046c64e9","0x7a468f820ace91436aaf71e2b3c92794b7d41b077a2bb4e8c1d5e090f195453e","0x0ea83e75a11e841fe623ccd00a00f3b22a506afa7e5b89a41e84a069205d3e4b","0x6b97d9691bdec69c873b1827d7d789b8672a04440039ae0d208dca1abc38c19c","0xc0eee58515ea32894f87581f50ac8cc4b2872093832ec2c72d136d5d340fc063","0xb66faa6e92efe1589b5960e9ce2123cdd3a609a4bac8ca5c56987b57ac68a89c","0xdcdd9027cbf2b389ec1a516b4cb8092401c5665acabf23d61171cb3d5bd366bc","0x5a3817213ce1fc15bf893858a00b4f4937618d5afae266fa0353dbb01842a79b","0x90a7f574bd39d2a4ed748821b3d5377129a8b202731d1a66862edc60da7c142c","0xbdc5b8c21a0c58369d999aa1eebf43c836c118f20083018c5c6836ab56625d49","0xd4b80e2a6678e139c165131cb78a4545b7c25a2659e34842f678afc842375d09","0x755daf3cd841a2dfcc52c1dec9ac8356648b02918f7a408822d32866388750e8","0xd3fb29c1e27d4dd539c6b5a27f425b1a0a2071a0e8376d60dda9dd5ff565c988","0xcb4dc1f79f09ace275c4e7dab6c00063cad4582cf21f3e4a9c6cb58b5e5defbb","0x5435159f65b5668299013eec84b1ede7b2993787fa3c6ffd9b0dc16c73635ce3","0x9dc696c325fdac1ab9fbfef7e9e6852e6fcdc7fb351eff22b81759d480048a52","0x7ffe5e86a2ba57faa68e75147409f677108813e4514339eb4a09076f18acfdf7","0xf4a3eb5b14d5bb292d59698f8f78ed9bb4b33209c85fc72cd15baf6936c7ae2b","0x679edb4f951105637458657c0c8867be82fb01093d91e4a72cf2919d54a0c99f","0x6a55e66565604f3eaf044eeff522d5d7dffd1aaedc6965e6ef71ddf1f06d6d66","0x0f43b52116fbbbaed37eb6cac5e28eaca7505c032096e8edaf6eb0683ba19468"] \ No newline at end of file diff --git a/frame/header-mmr/rpc/runtime-api/src/lib.rs b/frame/header-mmr/rpc/runtime-api/src/lib.rs index 2d30a7cf2e..1a5124edcf 100644 --- a/frame/header-mmr/rpc/runtime-api/src/lib.rs +++ b/frame/header-mmr/rpc/runtime-api/src/lib.rs @@ -28,7 +28,7 @@ use core::fmt::{self, Debug, Display}; // --- crates --- use codec::{Codec, Decode, Encode}; -// --- substrate --- +// --- paritytech --- use sp_api::decl_runtime_apis; use sp_runtime::traits::{MaybeDisplay, MaybeFromStr}; use sp_std::prelude::*; diff --git a/frame/header-mmr/rpc/src/lib.rs b/frame/header-mmr/rpc/src/lib.rs index 58294cdd1a..d590205b8a 100644 --- a/frame/header-mmr/rpc/src/lib.rs +++ b/frame/header-mmr/rpc/src/lib.rs @@ -21,13 +21,15 @@ // --- darwinia --- pub use darwinia_header_mmr_rpc_runtime_api::HeaderMMRApi as HeaderMMRRuntimeApi; +// --- core --- +use core::fmt::Debug; // --- std --- use std::sync::Arc; // --- crates --- use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -// --- substrate --- +// --- paritytech --- use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_runtime::{ @@ -53,7 +55,6 @@ pub struct HeaderMMR { client: Arc, _marker: std::marker::PhantomData, } - impl HeaderMMR { pub fn new(client: Arc) -> Self { Self { @@ -62,13 +63,12 @@ impl HeaderMMR { } } } - impl HeaderMMRApi> for HeaderMMR where Client: 'static + Send + Sync + ProvideRuntimeApi + HeaderBackend, Client::Api: HeaderMMRRuntimeApi, Block: BlockT, - Hash: core::fmt::Debug + Codec + MaybeDisplay + MaybeFromStr, + Hash: Debug + Codec + MaybeDisplay + MaybeFromStr, { fn gen_proof( &self, @@ -82,7 +82,7 @@ where api.gen_proof(&at, block_number_of_member_leaf, block_number_of_last_leaf) .map_err(|e| Error { code: ErrorCode::ServerError(RUNTIME_ERROR), - message: "Unable to query power.".into(), + message: "Unable to generate mmr proof.".into(), data: Some(format!("{:?}", e).into()), }) } diff --git a/frame/header-mmr/src/lib.rs b/frame/header-mmr/src/lib.rs index e4328aedd4..966853cec6 100644 --- a/frame/header-mmr/src/lib.rs +++ b/frame/header-mmr/src/lib.rs @@ -62,83 +62,165 @@ mod tests; #[frame_support::pallet] pub mod pallet { + pub mod types { + /// The type use for indexing a node + pub type NodeIndex = u64; + } + pub use types::*; + // --- crates.io --- #[cfg(feature = "std")] use serde::Serialize; - // --- github.com --- - use mmr::{Error, MMRStore, Merge, Result as MMRResult, MMR}; - // --- substrate --- - use frame_support::pallet_prelude::*; + // --- paritytech --- + use frame_support::{pallet_prelude::*, weights::Weight}; use frame_system::pallet_prelude::*; - use sp_runtime::{ - generic::{DigestItem, OpaqueDigestItemId}, - traits::{Hash, Header, SaturatedConversion}, - }; + use sp_io::offchain_index; + use sp_runtime::generic::DigestItem; + #[cfg(any(test, feature = "easy-testing"))] + use sp_runtime::{generic::OpaqueDigestItemId, traits::Header}; use sp_std::prelude::*; // --- darwinia --- + use crate::{primitives::*, weights::WeightInfo}; use darwinia_header_mmr_rpc_runtime_api::{Proof, RuntimeDispatchInfo}; use darwinia_relay_primitives::MMR as MMRT; - pub const PARENT_MMR_ROOT_LOG_ID: [u8; 4] = *b"MMRR"; + /// The prefix of [`MerkleMountainRangeRootLog`] + pub const LOG_PREFIX: [u8; 4] = *b"MMRR"; #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: frame_system::Config { + type WeightInfo: WeightInfo; - /// The MMR size and length of the mmr node list + /// The offchain-indexing prefix + const INDEXING_PREFIX: &'static [u8]; + } + + /// Size of the MMR #[pallet::storage] - #[pallet::getter(fn mmr_counter)] - pub type MMRCounter = StorageValue<_, u64, ValueQuery>; + #[pallet::getter(fn mmr_size)] + pub type MmrSize = StorageValue<_, NodeIndex, ValueQuery>; /// MMR struct of the previous blocks, from first(genesis) to parent hash. #[pallet::storage] #[pallet::getter(fn mmr_node_list)] - pub type MMRNodeList = StorageMap<_, Identity, u64, T::Hash, OptionQuery>; + pub type MMRNodeList = StorageMap<_, Identity, NodeIndex, T::Hash, OptionQuery>; + + /// Peaks of the MMR + #[pallet::storage] + #[pallet::getter(fn peak_of)] + pub type Peaks = StorageMap<_, Identity, NodeIndex, T::Hash, OptionQuery>; + + /// The num of nodes that should be pruned each block + #[pallet::storage] + #[pallet::getter(fn pruning_configuration)] + pub type PruningConfiguration = StorageValue<_, MmrNodesPruningConfiguration, ValueQuery>; #[pallet::pallet] pub struct Pallet(_); #[pallet::hooks] impl Hooks> for Pallet { - fn on_finalize(_: T::BlockNumber) { - let store = >::default(); - let parent_hash = >::parent_hash(); - let mut mmr = , _>>::new(>::get(), store); + fn on_initialize(_: BlockNumberFor) -> Weight { + >::try_mutate( + |MmrNodesPruningConfiguration { + step, + progress, + last_position, + }| { + if *progress > *last_position { + return Err(T::DbWeight::get().reads(1)); + } + + for position in *progress..progress.saturating_add(*step) { + if let Some(hash) = >::take(position) { + hash.using_encoded(|hash| { + offchain_index::set(&>::offchain_key(position), hash) + }); + + log::trace!("Pruned node `{:?}` at position `{}`", hash, position); + } + } - // Update MMR and add mmr root to digest of block header + *progress = progress.saturating_add(*step); + + Ok(T::DbWeight::get().reads_writes(1, *step * 2)) + }, + ) + .map_or_else(|weight| weight, |weight| weight) + } + + fn on_finalize(_: BlockNumberFor) { + let parent_hash = >::parent_hash(); + let mut mmr = >::new(); let _ = mmr.push(parent_hash); - if let Ok(parent_mmr_root) = mmr.get_root() { - if mmr.commit().is_ok() { + match mmr.finalize() { + Ok(parent_mmr_root) => { let mmr_root_log = MerkleMountainRangeRootLog:: { - prefix: PARENT_MMR_ROOT_LOG_ID, - parent_mmr_root: parent_mmr_root.into(), + prefix: LOG_PREFIX, + parent_mmr_root, }; let mmr_item = DigestItem::Other(mmr_root_log.encode()); >::deposit_log(mmr_item.into()); - } else { - log::error!("Commit MMR - FAILED"); } - } else { - log::error!("Calculate MMR - FAILED"); + Err(e) => { + log::error!("Failed to finalize MMR due to {}", e); + } } } } #[pallet::call] - impl Pallet {} impl Pallet { + #[pallet::weight(T::DbWeight::get().writes(1))] + pub fn config_pruning( + origin: OriginFor, + step: Option, + progress: Option, + last_position: Option, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + + >::try_mutate(|c| { + let mut modified = false; + + if let Some(step) = step { + c.step = step; + modified = true; + } + if let Some(progress) = progress { + c.progress = progress; + modified = true; + } + if let Some(last_position) = last_position { + c.last_position = last_position; + modified = true; + } + + if modified { + Ok(().into()) + } else { + Err("No changes".into()) + } + }) + } + } + impl Pallet { + pub fn offchain_key(position: NodeIndex) -> Vec { + (T::INDEXING_PREFIX, position).encode() + } + darwinia_support::impl_rpc! { pub fn gen_proof_rpc( - block_number_of_member_leaf: u64, - block_number_of_last_leaf: u64, + block_number_of_member_leaf: NodeIndex, + block_number_of_last_leaf: NodeIndex, ) -> RuntimeDispatchInfo { if block_number_of_member_leaf <= block_number_of_last_leaf { - let store = >::default(); let mmr_size = mmr::leaf_index_to_mmr_size(block_number_of_last_leaf); - if mmr_size <= >::get() { - let mmr = , _>>::new(mmr_size, store); - let pos = mmr::leaf_index_to_pos(block_number_of_member_leaf); - if let Ok(merkle_proof) = mmr.gen_proof(vec![pos]) { + if mmr_size <= >::get() { + let mmr = >::with_size(mmr_size); + + if let Ok(merkle_proof) = mmr.gen_proof(block_number_of_member_leaf) { return RuntimeDispatchInfo { mmr_size, proof: Proof(merkle_proof.proof_items().to_vec()), @@ -147,84 +229,31 @@ pub mod pallet { } } - RuntimeDispatchInfo { - mmr_size: 0, - proof: Proof(vec![]), - } + Default::default() } } - // TODO: For future rpc calls - pub fn _find_parent_mmr_root(header: T::Header) -> Option { - let id = OpaqueDigestItemId::Other; - - let filter_log = |MerkleMountainRangeRootLog { - prefix, - parent_mmr_root, - }: MerkleMountainRangeRootLog| match prefix - { - PARENT_MMR_ROOT_LOG_ID => Some(parent_mmr_root), + // Remove the cfg, once there's a requirement from runtime usage + #[cfg(any(test, feature = "easy-testing"))] + pub fn find_parent_mmr_root(header: &T::Header) -> Option { + let find_parent_mmr_root = |m: MerkleMountainRangeRootLog<_>| match m.prefix { + LOG_PREFIX => Some(m.parent_mmr_root), _ => None, }; // find the first other digest with the right prefix which converts to // the right kind of mmr root log. - header - .digest() - .convert_first(|l| l.try_to(id).and_then(filter_log)) + header.digest().convert_first(|d| { + d.try_to(OpaqueDigestItemId::Other) + .and_then(find_parent_mmr_root) + }) } } - impl MMRT for Pallet { - fn get_root(block_number: T::BlockNumber) -> Option { - let store = >::default(); - let mmr_size = mmr::leaf_index_to_mmr_size(block_number.saturated_into::() as _); - let mmr = , _>>::new(mmr_size, store); - - if let Ok(mmr_root) = mmr.get_root() { - Some(mmr_root) - } else { - None - } - } - } - - pub struct ModuleMMRStore(PhantomData); - impl Default for ModuleMMRStore { - fn default() -> Self { - ModuleMMRStore(sp_std::marker::PhantomData) - } - } - impl MMRStore for ModuleMMRStore { - fn get_elem(&self, pos: u64) -> MMRResult> { - Ok(>::mmr_node_list(pos)) - } - - fn append(&mut self, pos: u64, elems: Vec) -> MMRResult<()> { - let mmr_count = >::get(); - if pos != mmr_count { - // Must be append only. - Err(Error::InconsistentStore)?; - } - let elems_len = elems.len() as u64; - - for (i, elem) in elems.into_iter().enumerate() { - >::insert(mmr_count + i as u64, elem); - } - - // increment counter - >::put(mmr_count + elems_len); - - Ok(()) - } - } - - pub struct MMRMerge(PhantomData); - impl Merge for MMRMerge { - type Item = ::Hash; - - fn merge(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item { - let encodable = (lhs, rhs); - ::Hashing::hash_of(&encodable) + impl MMRT, T::Hash> for Pallet { + fn get_root() -> Option { + >::with_size(>::get()) + .get_root() + .ok() } } @@ -236,10 +265,29 @@ pub mod pallet { /// The merkle mountain range root hash. pub parent_mmr_root: Hash, } + + #[derive(Clone, Default, Eq, PartialEq, Encode, Decode, RuntimeDebug)] + pub struct MmrNodesPruningConfiguration { + /// The nodes num that should be pruned each block + pub step: NodeIndex, + /// The progress of last time pruning + pub progress: NodeIndex, + /// Should stop pruning after reach the last node's position + pub last_position: NodeIndex, + } } pub use pallet::*; +pub mod primitives; + +pub mod weights; + pub mod migration { + // --- paritytech --- + use frame_support::migration; + // --- darwinia --- + use crate::*; + const OLD_PALLET_NAME: &[u8] = b"DarwiniaHeaderMMR"; #[cfg(feature = "try-runtime")] @@ -253,6 +301,51 @@ pub mod migration { } pub fn migrate(new_pallet_name: &[u8]) { - frame_support::migration::move_pallet(OLD_PALLET_NAME, new_pallet_name); + migration::move_pallet(OLD_PALLET_NAME, new_pallet_name); + } + + #[cfg(test)] + pub fn initialize_new_mmr_state(size: NodeIndex, mmr: Vec, pruning_step: NodeIndex) + where + T: Config, + { + >::put(size); + >::put(MmrNodesPruningConfiguration { + step: pruning_step, + progress: 0, + last_position: size, + }); + + for position in mmr::helper::get_peaks(size) { + >::insert(position, mmr[position as usize]); + } + for (position, hash) in mmr.into_iter().enumerate() { + >::insert(position as NodeIndex, hash); + } + } + + #[cfg(not(test))] + pub fn initialize_new_mmr_state(module: &[u8], pruning_step: NodeIndex) + where + T: Config, + { + let size = migration::take_storage_value::(module, b"MMRCounter", &[]) + .expect("`MMRCounter` MUST be existed; qed"); + + migration::remove_storage_prefix(module, b"MMRCounter", &[]); + + >::put(size); + >::put(MmrNodesPruningConfiguration { + step: pruning_step, + progress: 0, + last_position: size, + }); + + for position in mmr::helper::get_peaks(size) { + >::insert( + position, + >::get(position).expect("Node MUST be existed; qed"), + ); + } } } diff --git a/frame/header-mmr/src/mock.rs b/frame/header-mmr/src/mock.rs index ad9789d10f..2cd282337c 100644 --- a/frame/header-mmr/src/mock.rs +++ b/frame/header-mmr/src/mock.rs @@ -20,16 +20,26 @@ // --- crates --- use codec::Encode; -// --- substrate --- +// --- github.com --- +use mmr::MMRStore; +// --- paritytech --- +use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::mocking::*; -use sp_core::H256; +use sp_core::{ + offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt}, + H256, +}; +use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, DigestItem, }; // --- darwinia --- -use crate::{self as darwinia_header_mmr, *}; +use crate::{self as darwinia_header_mmr, primitives::*, *}; + +pub type BlockNumber = u64; +pub type Hash = H256; type Block = MockBlock; type UncheckedExtrinsic = MockUncheckedExtrinsic; @@ -42,8 +52,8 @@ impl frame_system::Config for Test { type Origin = Origin; type Call = Call; type Index = u64; - type BlockNumber = u64; - type Hash = H256; + type BlockNumber = BlockNumber; + type Hash = Hash; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; @@ -60,7 +70,11 @@ impl frame_system::Config for Test { type OnSetCode = (); } -impl Config for Test {} +impl Config for Test { + type WeightInfo = (); + + const INDEXING_PREFIX: &'static [u8] = b"header-mmr-"; +} frame_support::construct_runtime! { pub enum Test @@ -70,75 +84,80 @@ frame_support::construct_runtime! { UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Storage, Config}, - HeaderMMR: darwinia_header_mmr::{Pallet, Call, Storage}, + HeaderMmr: darwinia_header_mmr::{Pallet, Call, Storage}, } } -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestExternalities { + sp_tracing::try_init_simple(); + frame_system::GenesisConfig::default() .build_storage::() .unwrap() .into() } -pub fn header_mmr_log(hash: H256) -> DigestItem { - let mmr_root_log = MerkleMountainRangeRootLog:: { - prefix: PARENT_MMR_ROOT_LOG_ID, +pub fn register_offchain_ext(ext: &mut TestExternalities) { + ext.persist_offchain_overlay(); + + let (offchain, _) = TestOffchainExt::with_offchain_db(ext.offchain_db()); + + ext.register_extension(OffchainDbExt::new(offchain.clone())); + ext.register_extension(OffchainWorkerExt::new(offchain)); +} + +pub fn header_parent_mmr_log(hash: Hash) -> DigestItem { + let mmr_root_log = MerkleMountainRangeRootLog:: { + prefix: LOG_PREFIX, parent_mmr_root: hash, }; DigestItem::Other(mmr_root_log.encode()) } -pub fn initialize_block(number: u64, parent_hash: H256) { - System::initialize( +pub fn mmr_with_size(size: NodeIndex) -> Mmr +where + Storage: MMRStore, +{ + >::with_size(size) +} + +pub fn mmr() -> Mmr +where + Storage: MMRStore, +{ + mmr_with_size(HeaderMmr::mmr_size()) +} + +pub fn new_block_with_parent_hash(parent_hash: Hash) -> Header { + let number = >::block_number() + 1; + + >::initialize( &number, &parent_hash, &Default::default(), Default::default(), ); + HeaderMmr::on_initialize(number); + HeaderMmr::on_finalize(number); + >::finalize() +} + +pub fn new_block() -> Header { + let number = >::block_number() + 1; + let parent_hash = Hash::repeat_byte(number as _); + + new_block_with_parent_hash(parent_hash) } -// -- helpers --- -pub const HEADERS_N_ROOTS: [(&str, &str); 10] = [ - ( - "34f61bfda344b3fad3c3e38832a91448b3c613b199eb23e5110a635d71c13c65", - "34f61bfda344b3fad3c3e38832a91448b3c613b199eb23e5110a635d71c13c65", - ), - ( - "70d641860d40937920de1eae29530cdc956be830f145128ebb2b496f151c1afb", - "3aafcc7fe12cb8fad62c261458f1c19dba0a3756647fa4e8bff6e248883938be", - ), - ( - "12e69454d992b9b1e00ea79a7fa1227c889c84d04b7cd47e37938d6f69ece45d", - "7ddf10d67045173e3a59efafb304495d9a7c84b84f0bc0235470a5345e32535d", - ), - ( - "3733bd06905e128d38b9b336207f301133ba1d0a4be8eaaff6810941f0ad3b1a", - "488e9565547fec8bd36911dc805a7ed9f3d8d1eacabe429c67c6456933c8e0a6", - ), - ( - "3d7572be1599b488862a1b35051c3ef081ba334d1686f9957dbc2afd52bd2028", - "6e0c4ab56e0919a7d45867fcd1216e2891e06994699eb838386189e9abda55f1", - ), - ( - "2a04add3ecc3979741afad967dfedf807e07b136e05f9c670a274334d74892cf", - "293b49420345b185a1180e165c76f76d8cc28fe46c1f6eb4a96959253b571ccd", - ), - ( - "c58e247ea35c51586de2ea40ac6daf90eac7ac7b2f5c88bbc7829280db7890f1", - "2dee5b87a481a9105cb4b2db212a1d8031d65e9e6e68dc5859bef5e0fdd934b2", - ), - ( - "2cf0262f0a8b00cad22afa04d70fb0c1dbb2eb4a783beb7c5e27bd89015ff573", - "54be644b5b3291dd9ae9598b49d1f986e4ebd8171d5e89561b2a921764c7b17c", - ), - ( - "05370d06def89f11486c994c459721b4bd023ff8c2347f3187e9f42ef39bddab", - "620dbc3a28888da8b17ebf5b18dba53794621463e2bbabcf88b8cbc97508ab38", - ), - ( - "c0c8c3f7dc9cdfa87d2433bcd72a744d634524a5ff76e019e44ea450476bac99", - "a94bf2a4e0437c236c68675403d980697cf7c9b0f818a622cb40199db5e12cf8", - ), -]; +pub fn run_to_block_from_genesis(n: BlockNumber) -> Vec
{ + let mut headers = vec![new_block()]; + + for _ in 2..=n { + headers.push(new_block_with_parent_hash( + headers[headers.len() - 1].hash(), + )); + } + + headers +} diff --git a/frame/header-mmr/src/primitives.rs b/frame/header-mmr/src/primitives.rs new file mode 100644 index 0000000000..a00d92d494 --- /dev/null +++ b/frame/header-mmr/src/primitives.rs @@ -0,0 +1,190 @@ +pub use mmr::MMR; + +// --- crates.io --- +use codec::{Decode, Encode}; +// --- github.com --- +use mmr::{Error, MMRStore, Merge, MerkleProof, Result as MMRResult}; +// --- paritytech --- +use sp_core::offchain::StorageKind; +use sp_io::{offchain, offchain_index}; +use sp_runtime::traits::Hash; +use sp_std::{marker::PhantomData, prelude::*}; +// --- darwinia --- +use crate::*; + +pub struct Hasher(PhantomData); +impl Merge for Hasher { + type Item = T::Hash; + + fn merge(lhs: &Self::Item, rhs: &Self::Item) -> Self::Item { + T::Hashing::hash_of(&(lhs, rhs)) + } +} + +pub struct OffchainStorage; +pub struct RuntimeStorage; +pub struct Storage(PhantomData<(StorageType, T)>); +impl Default for Storage { + fn default() -> Self { + Self(Default::default()) + } +} +impl MMRStore for Storage +where + T: Config, +{ + fn get_elem(&self, position: NodeIndex) -> MMRResult> { + let key = >::offchain_key(position); + + if let Some(v) = offchain::local_storage_get(StorageKind::PERSISTENT, &key) { + Ok(Decode::decode(&mut &*v).ok()) + } else { + Ok(>::get(position)) + } + + // TODO: once the pruning finish, restore this + // Ok(offchain::local_storage_get(StorageKind::PERSISTENT, &key) + // .and_then(|v| Decode::decode(&mut &*v).ok())) + } + + fn append(&mut self, _: NodeIndex, _: Vec) -> MMRResult<()> { + log::error!("Not allow to append elem(s) in the off-chain context!"); + + Err(Error::InconsistentStore) + } +} +impl MMRStore for Storage +where + T: Config, +{ + fn get_elem(&self, position: NodeIndex) -> MMRResult> { + Ok(>::peak_of(position)) + } + + // ? Actually we can move this pruning logic outside + // ? and perform the pruning every X blocks + // ? + // ? commented by Xavier + fn append(&mut self, position: NodeIndex, elems: Vec) -> MMRResult<()> { + let mmr_size = >::get(); + + if position != mmr_size { + Err(Error::InconsistentStore)?; + } + + let diff = |a: &[NodeIndex], b: &[NodeIndex]| -> Vec { + b.iter().filter(|x| !a.contains(x)).cloned().collect() + }; + let peaks_before = if mmr_size == 0 { + vec![] + } else { + mmr::helper::get_peaks(mmr_size) + }; + let elems = elems + .into_iter() + .enumerate() + .map(|(i, elem)| (mmr_size + i as NodeIndex, elem)) + .collect::>(); + let mmr_size = mmr_size + elems.len() as NodeIndex; + + >::put(mmr_size); + + for (position, elem) in elems.iter() { + elem.using_encoded(|elem| { + offchain_index::set(&>::offchain_key(*position), elem) + }); + } + + let peaks_after = mmr::helper::get_peaks(mmr_size); + let nodes_to_prune = diff(&peaks_after, &peaks_before); + let peaks_to_store = diff(&peaks_before, &peaks_after); + + { + log::trace!("elems: {:?}\n", elems); + log::trace!("peaks_before: {:?}", peaks_before); + log::trace!("peaks_after: {:?}", peaks_after); + log::trace!("nodes_to_prune: {:?}", nodes_to_prune); + log::trace!("peaks_to_store: {:?}\n", peaks_to_store); + } + + for position in nodes_to_prune { + >::remove(position); + } + for position in peaks_to_store { + if let Some(i) = elems + .iter() + .position(|(position_, _)| *position_ == position) + { + if let Some((_, elem)) = elems.get(i) { + >::insert(position, elem); + + log::trace!("position: {}, elem: {:?}", position, elem); + } else { + log::error!("The different must existed in `elems`; qed"); + } + } else { + log::error!("The different must existed in `elems`; qed"); + } + } + + Ok(()) + } +} + +pub struct Mmr +where + Storage: MMRStore, + T: Config, +{ + pub mmr: MMR, Storage>, +} +impl Mmr +where + T: Config, + Storage: MMRStore, +{ + pub fn new() -> Self { + Self { + mmr: MMR::new(>::get(), Default::default()), + } + } + + pub fn with_size(size: NodeIndex) -> Self { + Self { + mmr: MMR::new(size, Default::default()), + } + } + + pub fn get_root(&self) -> MMRResult { + self.mmr.get_root() + } + + // TODO + pub fn verify(&self) -> MMRResult { + todo!() + } +} +impl Mmr +where + T: Config, +{ + pub fn gen_proof(&self, index: NodeIndex) -> MMRResult>> { + self.mmr.gen_proof(vec![mmr::leaf_index_to_pos(index)]) + } +} +impl Mmr +where + T: Config, +{ + pub fn push(&mut self, leaf: T::Hash) -> Option { + self.mmr.push(leaf).ok() + } + + pub fn finalize(self) -> MMRResult { + let root = self.mmr.get_root()?; + + self.mmr.commit()?; + + Ok(root) + } +} diff --git a/frame/header-mmr/src/tests.rs b/frame/header-mmr/src/tests.rs index e296df3e08..2c09ab2ab1 100644 --- a/frame/header-mmr/src/tests.rs +++ b/frame/header-mmr/src/tests.rs @@ -18,139 +18,374 @@ //! Tests for the module. +mod data { + // --- std --- + use std::fs::File; + // --- darwinia --- + use crate::mock::*; + + pub struct Hashes { + pub hash: Hash, + pub parent_mmr_root: Hash, + } + impl Hashes { + // Data source: https://crab.subscan.io/block/1?tab=log + pub const CRAB: &'static [(&'static str, &'static str)] = &[ + ( + "0x34f61bfda344b3fad3c3e38832a91448b3c613b199eb23e5110a635d71c13c65", + "0x34f61bfda344b3fad3c3e38832a91448b3c613b199eb23e5110a635d71c13c65", + ), + ( + "0x70d641860d40937920de1eae29530cdc956be830f145128ebb2b496f151c1afb", + "0x3aafcc7fe12cb8fad62c261458f1c19dba0a3756647fa4e8bff6e248883938be", + ), + ( + "0x12e69454d992b9b1e00ea79a7fa1227c889c84d04b7cd47e37938d6f69ece45d", + "0x7ddf10d67045173e3a59efafb304495d9a7c84b84f0bc0235470a5345e32535d", + ), + ( + "0x3733bd06905e128d38b9b336207f301133ba1d0a4be8eaaff6810941f0ad3b1a", + "0x488e9565547fec8bd36911dc805a7ed9f3d8d1eacabe429c67c6456933c8e0a6", + ), + ( + "0x3d7572be1599b488862a1b35051c3ef081ba334d1686f9957dbc2afd52bd2028", + "0x6e0c4ab56e0919a7d45867fcd1216e2891e06994699eb838386189e9abda55f1", + ), + ( + "0x2a04add3ecc3979741afad967dfedf807e07b136e05f9c670a274334d74892cf", + "0x293b49420345b185a1180e165c76f76d8cc28fe46c1f6eb4a96959253b571ccd", + ), + ( + "0xc58e247ea35c51586de2ea40ac6daf90eac7ac7b2f5c88bbc7829280db7890f1", + "0x2dee5b87a481a9105cb4b2db212a1d8031d65e9e6e68dc5859bef5e0fdd934b2", + ), + ( + "0x2cf0262f0a8b00cad22afa04d70fb0c1dbb2eb4a783beb7c5e27bd89015ff573", + "0x54be644b5b3291dd9ae9598b49d1f986e4ebd8171d5e89561b2a921764c7b17c", + ), + ( + "0x05370d06def89f11486c994c459721b4bd023ff8c2347f3187e9f42ef39bddab", + "0x620dbc3a28888da8b17ebf5b18dba53794621463e2bbabcf88b8cbc97508ab38", + ), + ( + "0xc0c8c3f7dc9cdfa87d2433bcd72a744d634524a5ff76e019e44ea450476bac99", + "0xa94bf2a4e0437c236c68675403d980697cf7c9b0f818a622cb40199db5e12cf8", + ), + ]; + // Data source: https://darwinia.subscan.io/block/1?tab=log + pub const DARWINIA: &'static [(&'static str, &'static str)] = &[ + ( + "0x729cb8f2cf428adcf81fe69610edda32c5711b2ff17de747e8604a3587021db8", + "0x729cb8f2cf428adcf81fe69610edda32c5711b2ff17de747e8604a3587021db8", + ), + ( + "0xccdfb06966ededa7a15c5bf490190690084f02d6dc35abb79bc8705f4b7e9731", + "0x5a06da3b3f0c3d73add4513d16a4af9623d4640eb1ba383d2ddb5645074ed868", + ), + ( + "0x77161d7ee937ffae97f6c23d26791e05f9d08b138eb22b5f43e2cee52ddf50aa", + "0xe9b8cec5c6b0b8efec21ce632228e94911b5030b85d8f314fbbfc5010fadbe33", + ), + ( + "0x58677a31c0f3bff168a2b4d6a181eb7ecd465455045713720672b46d7fed9c40", + "0xa2dc16ce3c3b2b05cfc722ba21ecd8a94bb2cc695f6761d1ca87444560ca7316", + ), + ( + "0x4b858e3d5fd8fdf6f109b145760cb9041c6256fec52871d9b5339e4a6159c1c5", + "0xef71dca09a2e683d487c1a143c1fd7ce0cf9f23ded4ecdbd526e6e9439d09535", + ), + ( + "0xb9cf10c067b6cd408149e0430016c91b84b1a5ffddbb6cb7d52c977571db36ed", + "0xd0e4d61572226255f6f42ceee6a9152110a6e1a7926108d2af75a675c5460af3", + ), + ( + "0x58a7b1064f7db57f5bed34256bd5303db9884818bc8b76096b90f88411577b0f", + "0x0dbfd31ea7601e25f5b8bc82b1eb82ff0f532826b12eb0f9cd8910ddcf56adf9", + ), + ( + "0xf491c827e06f0f10020e63d16426745794e894032fa31c885b08be8668cab7d9", + "0xce90f8a4d033368ffa22b61062f1963495922090f25b738248f29d7bd3179747", + ), + ( + "0xcf0b16a5dde57cf31798b724ac7b05ccc0f88b4667aaec45ea21a5a03466883d", + "0x05d87a9f7d4c85a48fc18286446e10740513354cb42827414795e4ac6cd7829f", + ), + ( + "0x554afd5150f0e6e099c7bf03d3a761f0629d1ea55ff35e5c7e1ff1ee733e9eff", + "0x768c6230e2fd46f3b4805ea036d0d6079fa3a15822d24f6832ef7cb4549500d6", + ), + ]; + + pub fn from_raw(raw_hashes: &[(&str, &str)]) -> Vec { + raw_hashes + .iter() + .map(|(raw_hash, raw_parent_mmr_root)| Hashes { + hash: array_bytes::hex_into_unchecked(raw_hash), + parent_mmr_root: array_bytes::hex_into_unchecked(raw_parent_mmr_root), + }) + .collect() + } + } + + // 0~10000 MMR nodes from Darwinia + pub fn darwinia_mmr() -> Vec { + serde_json::from_reader::<_, Vec>(File::open("mmr.json").unwrap()).unwrap() + } +} +use data::*; + // --- crates.io --- -use codec::{Decode, Encode}; +use codec::Encode; +use rand::prelude::*; +use serde_json::Value; // --- github.com --- -use mmr::{Merge, MMR}; +use mmr::MMRStore; // --- substrate --- -use frame_support::traits::OnFinalize; -use sp_runtime::{ - generic::DigestItem, - testing::{Digest, H256}, -}; +use sp_runtime::testing::Digest; // --- darwinia --- -use crate::{mock::*, pallet::*}; +use crate::{mock::*, primitives::*, *}; +use darwinia_header_mmr_rpc_runtime_api::*; + +#[test] +fn codec_digest_should_work() { + assert_eq!( + header_parent_mmr_log(Default::default()).encode(), + vec![ + // DigestItemType::Other + vec![0], + // Vector length + vec![0x90], + // Prefix *b"MMRR" + vec![77, 77, 82, 82], + // MMR root + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 + ], + ] + .concat() + ); +} + +#[test] +fn serialize_digest_should_work() { + assert_eq!( + serde_json::to_string(&Digest { + logs: vec![header_parent_mmr_log(Default::default())], + }) + .unwrap(), + // 0x90 is compact codec of the length 36, 0x4d4d5252 is prefix "MMRR" + r#"{"logs":["0x00904d4d52520000000000000000000000000000000000000000000000000000000000000000"]}"# + ); +} + +#[test] +fn hasher_should_work() { + fn assert_hashes(raw_hashes: &[(&str, &str)]) { + let hashes = Hashes::from_raw(raw_hashes); + let mut mmr = >::with_size(0); + + for i in 0..hashes.len() { + mmr.push(hashes[i].hash).unwrap(); + + assert_eq!(mmr.get_root().unwrap(), hashes[i].parent_mmr_root); + } + } + + assert_hashes(Hashes::CRAB); + assert_hashes(Hashes::DARWINIA); +} #[test] -fn first_header_mmr() { +fn header_digest_should_work() { new_test_ext().execute_with(|| { - let parent_hash: H256 = Default::default(); - initialize_block(1, parent_hash); + let mut header = new_block(); + let mut parent_mmr_root = header.parent_hash; - System::note_finished_extrinsics(); - HeaderMMR::on_finalize(1); + for _ in 0..10 { + assert_eq!( + header.digest, + Digest { + logs: vec![header_parent_mmr_log(parent_mmr_root)] + } + ); - let header = System::finalize(); - assert_eq!( - header.digest, - Digest { - logs: vec![header_mmr_log(parent_hash)] - } - ); + header = new_block(); + parent_mmr_root = mmr::().get_root().unwrap(); + } }); } #[test] -fn test_insert_header() { - new_test_ext().execute_with(|| { - initialize_block(1, Default::default()); +fn integration_testing_should_work() { + let mut rng = rand::thread_rng(); + let mut leaves = (1..30).collect::>(); + let mut last_leaves = (1..30).collect::>(); + + leaves.shuffle(&mut rng); + last_leaves.shuffle(&mut rng); - HeaderMMR::on_finalize(1); + let data = leaves + .into_iter() + .zip(last_leaves.into_iter()) + .filter(|(a, b)| a < b) + .collect::>(); + for (leaf, last_leaf) in data { let mut headers = vec![]; + let mut ext = new_test_ext(); - let mut header = System::finalize(); - headers.push(header.clone()); + ext.execute_with(|| { + headers = run_to_block_from_genesis(last_leaf); + }); - for i in 2..30 { - initialize_block(i, header.hash()); + register_offchain_ext(&mut ext); - HeaderMMR::on_finalize(i); - header = System::finalize(); - headers.push(header.clone()); - } + ext.execute_with(|| { + let on_chain = + >::with_size(mmr::leaf_index_to_mmr_size(last_leaf - 1)); + let off_chain = + >::with_size(mmr::leaf_index_to_mmr_size(last_leaf - 1)); - let h1 = 11 as u64; - let h2 = 19 as u64; + assert_eq!( + headers[leaf as usize - 1].hash(), + >::default() + .get_elem(mmr::leaf_index_to_pos(leaf)) + .unwrap() + .unwrap() + ); + assert_eq!( + on_chain.get_root().unwrap(), + HeaderMmr::find_parent_mmr_root(&headers[last_leaf as usize - 1]).unwrap() + ); + assert!(off_chain + .gen_proof(leaf) + .unwrap() + .verify( + HeaderMmr::find_parent_mmr_root(&headers[last_leaf as usize - 1]).unwrap(), + vec![( + mmr::leaf_index_to_pos(leaf), + headers[leaf as usize - 1].hash() + )] + ) + .unwrap()); + }); + } +} - let prove_elem = headers[h1 as usize - 1].hash(); +#[test] +fn prune_darwinia_should_work() { + // Perform `set_code` at block `500` + // + // The new runtime logic will be applied at block `501` + const BLOCK_NUMBER: NodeIndex = 500; + const PRUNING_STEP: NodeIndex = 10; - let pos = 19; - assert_eq!(pos, mmr::leaf_index_to_pos(h1)); - assert_eq!(prove_elem, HeaderMMR::mmr_node_list(pos).unwrap()); + // The `500` leaves' MMR size is `995` the last position is `994` + // So, the pruning will stop at `994` + let size = mmr::leaf_index_to_mmr_size(BLOCK_NUMBER); + let mmr = darwinia_mmr()[..size as usize].to_vec(); + let mut ext = new_test_ext(); - let parent_mmr_root = HeaderMMR::_find_parent_mmr_root(headers[h2 as usize - 1].clone()) - .expect("Header mmr get failed"); + register_offchain_ext(&mut ext); - let store = >::default(); - let mmr = MMR::<_, MMRMerge, _>::new(mmr::leaf_index_to_mmr_size(h2 - 1), store); + ext.execute_with(|| { + System::set_block_number(BLOCK_NUMBER); - assert_eq!(mmr.get_root().expect("Get Root Failed"), parent_mmr_root); + migration::initialize_new_mmr_state::(size, mmr, PRUNING_STEP); - let proof = mmr.gen_proof(vec![pos]).expect("gen proof"); + // Able to `gen_proof` from for runtime DB `MMRNodeList`, during pruning + { + let block_number = System::block_number(); + let off_chain = + >::with_size(mmr::leaf_index_to_mmr_size(block_number)); - let result = proof - .verify(parent_mmr_root, vec![(pos, prove_elem)]) - .expect("verify"); - assert!(result); + for index in 0..block_number { + assert!(off_chain.gen_proof(index).is_ok()); + } + } + + // A single pruning step + { + for position in (0 as NodeIndex)..PRUNING_STEP { + assert!(>::contains_key(position)); + } + // Ignore parent hash here, just pruning testing + new_block(); + for position in (0 as NodeIndex)..PRUNING_STEP { + assert!(!>::contains_key(position)); + } + for position in PRUNING_STEP..size { + assert!(>::contains_key(position)); + } + } + + // Pruning `MMRNodeList` to empty + { + for _ in 0..size / PRUNING_STEP { + new_block(); + } + for position in 0..size { + assert!(!>::contains_key(position)); + } + } }); -} -#[test] -fn should_serialize_mmr_digest() { - let digest = Digest { - logs: vec![header_mmr_log(Default::default())], - }; + register_offchain_ext(&mut ext); - assert_eq!( - serde_json::to_string(&digest).unwrap(), - // 0x90 is compact codec of the length 36, 0x4d4d5252 is prefix "MMRR" - r#"{"logs":["0x00904d4d52520000000000000000000000000000000000000000000000000000000000000000"]}"# - ); -} + // `gen_proof` only works in off-chain context now + ext.execute_with(|| { + let block_number = System::block_number(); + let off_chain = + >::with_size(mmr::leaf_index_to_mmr_size(block_number)); -#[test] -fn non_system_mmr_digest_item_encoding() { - let item = header_mmr_log(Default::default()); - let encoded = item.encode(); - assert_eq!( - encoded, - vec![ - 0, // type = DigestItemType::Other - 0x90, // vec length - 77, 77, 82, 82, // Prefix, *b"MMRR" - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, // mmr root - ] - ); + for index in 0..block_number { + assert!(off_chain.gen_proof(index).is_ok()); + } - let decoded: DigestItem = Decode::decode(&mut &encoded[..]).unwrap(); - assert_eq!(item, decoded); -} + fn assert_rpc_result(rpc: &str, params: [NodeIndex; 2]) { + let json = serde_json::from_str::(rpc).unwrap(); -#[test] -fn test_mmr_root() { - let store = >::default(); - let mut mmr = , _>>::new(0, store); - (0..10).for_each(|i| { - let cur = HEADERS_N_ROOTS[i]; - mmr.push(array_bytes::hex2array_unchecked!(cur.0, 32).into()) - .unwrap(); - assert_eq!( - &format!("{:?}", mmr.get_root().expect("get root failed"))[2..], - cur.1 + assert_eq!( + RuntimeDispatchInfo { + mmr_size: json["mmrSize"].as_str().unwrap().parse().unwrap(), + proof: Proof( + json["proof"] + .as_str() + .unwrap() + .trim_matches(&['[', ']'] as &[_]) + .split(',') + .map(|hex| array_bytes::hex_into_unchecked(hex.trim())) + .collect() + ), + }, + HeaderMmr::gen_proof_rpc(params[0], params[1]) + ); + } + + // λ subalfred send-rpc --method headerMMR_genProof --params '[15, 27]' --uri https://rpc.darwinia.network + assert_rpc_result( + r#"{ + "mmrSize": "53", + "proof": "[0x53239551406c7443ba08a8bf3295b5808f1117809fdc941251859764454b6127,0x9e9af6c7c85c72eca5f6eab91e51f46200d78ac781fce88fd320884af75c1fb0,0xdc74423b38518438f55c30c3039ea411c1884994164133d20b63f0ac158f693c,0xce90f8a4d033368ffa22b61062f1963495922090f25b738248f29d7bd3179747,0x9ef94a314854595c579175bf8a50c377ac674c7daab1b7ce73cd479585bf2243]" + }"#, + [15, 27], + ); + // λ subalfred send-rpc --method headerMMR_genProof --params '[12, 345]' --uri https://rpc.darwinia.network + assert_rpc_result( + r#"{ + "mmrSize": "687", + "proof": "[0xf470e3bc1d1675ae7178241dd2e3a86c9a5eb8069138aec2592f5e5e22e8f7c4,0x2176cea5ee7d347933c5b6e59e71868260da55e221c249981daba74140ba9c18,0xdc74423b38518438f55c30c3039ea411c1884994164133d20b63f0ac158f693c,0xce90f8a4d033368ffa22b61062f1963495922090f25b738248f29d7bd3179747,0xd75b80f04d876c18d00ca3c218a11975b3033efb21eca27053ba0ee0444c4734,0x889370a0a23fcb1f5b47c9ed85dd79396fce408e14640a19b897b6defb4685a7,0xdfd961454b76255ea5391ba747e64c1993b36df0eef9f70cbdb80f4839bc607f,0x42847d00d10e4ab1097281098bb01f6339ea0faf2f9df08734f471f241bd2067,0x969c918e8525124ffd0d93a29135b9420e898f277dfc67385900d8e872a9ea19]" + }"#, + [12, 345], + ); + // λ subalfred send-rpc --method headerMMR_genProof --params '[50, 500]' --uri https://rpc.darwinia.network + assert_rpc_result( + r#"{ + "mmrSize": "995", + "proof": "[0x6a85080d832bb8c61733c6a1d5205fa2f87514438fa46e9b446917aa8b0f28c7,0x691fa5a6305fdc0c1117cd6eacb9d45d5aed170a98d2143b9e616fc884bd9391,0x13e0e7836729160b07fa9ce24ab44e5bb2d2f25c24f29a604ea70df81c89622d,0x6beb56e3af536d5e4837f7469c22db15fa4a7bae0ce3bbfbf35a469e4ea81ba2,0x44cadf7ac096628db0cd3ccb827a31972cbfcef13de9563ca7c643242ff5f982,0x05d87c7306675244aee90748fb31776b4fbb65fd9082c198944bf03dbace2836,0xdfd961454b76255ea5391ba747e64c1993b36df0eef9f70cbdb80f4839bc607f,0x42847d00d10e4ab1097281098bb01f6339ea0faf2f9df08734f471f241bd2067,0xdf3d2d2278ae5a93db21bcbfcbc3dad584729044afab8b5450ed8d571c151ce7]" + }"#, + [50, 500], ); }); } - -#[test] -fn test_mmr_merge() { - let res = MMRMerge::::merge( - &array_bytes::hex2array_unchecked!(HEADERS_N_ROOTS[0].0, 32).into(), - &array_bytes::hex2array_unchecked!(HEADERS_N_ROOTS[1].0, 32).into(), - ); - assert_eq!( - format!("{:?}", res), - "0x3aafcc7fe12cb8fad62c261458f1c19dba0a3756647fa4e8bff6e248883938be" - ); -} diff --git a/frame/header-mmr/src/weights.rs b/frame/header-mmr/src/weights.rs new file mode 100644 index 0000000000..fc3918c3d7 --- /dev/null +++ b/frame/header-mmr/src/weights.rs @@ -0,0 +1,11 @@ +// --- paritytech --- +use frame_support::weights::Weight; + +pub trait WeightInfo { + fn on_initialize() -> Weight; +} +impl WeightInfo for () { + fn on_initialize() -> Weight { + 0 + } +} diff --git a/primitives/relay/src/relay_authorities.rs b/primitives/relay/src/relay_authorities.rs index b7193ef0f1..6b10eb43ef 100644 --- a/primitives/relay/src/relay_authorities.rs +++ b/primitives/relay/src/relay_authorities.rs @@ -46,7 +46,7 @@ pub trait Sign { pub trait RelayAuthorityProtocol { type Signer; - fn schedule_mmr_root(block_number: BlockNumber); + fn schedule_mmr_root(block_number: BlockNumber) -> DispatchResult; fn check_authorities_change_to_sync( term: Term, @@ -57,11 +57,11 @@ pub trait RelayAuthorityProtocol { } pub trait MMR { - fn get_root(block_number: BlockNumber) -> Option; + fn get_root() -> Option; } // Only for test impl MMR for () { - fn get_root(_: BlockNumber) -> Option { + fn get_root() -> Option { None } } @@ -117,3 +117,17 @@ pub struct ScheduledAuthoritiesChange { + pub mmr_root: MmrRoot, + pub signatures: Vec<(Signer, Signature)>, +} +impl MmrRootToSign { + pub fn new(mmr_root: MmrRoot) -> Self { + Self { + mmr_root, + signatures: vec![], + } + } +}