From 1b80152d964809978be786fb89c735ec1a468f4d Mon Sep 17 00:00:00 2001 From: Marcio Diaz Date: Mon, 9 Mar 2020 10:12:20 +0100 Subject: [PATCH 001/220] Benchmark Vesting (#5048) * Init macro * Refactor function. * Add feature * vested transfer benchmark * Fix features * Forgot to push this fix * bump impl * Nits. Co-authored-by: Shawn Tabrizi --- Cargo.lock | 1 + bin/node/runtime/Cargo.toml | 1 + bin/node/runtime/src/lib.rs | 9 ++- frame/vesting/Cargo.toml | 2 + frame/vesting/src/benchmarking.rs | 111 ++++++++++++++++++++++++++++++ frame/vesting/src/lib.rs | 3 + 6 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 frame/vesting/src/benchmarking.rs diff --git a/Cargo.lock b/Cargo.lock index 2bed3b2bb5f..4b170d90826 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4545,6 +4545,7 @@ name = "pallet-vesting" version = "2.0.0-alpha.3" dependencies = [ "enumflags2", + "frame-benchmarking", "frame-support", "frame-system", "hex-literal", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 0d65cf53395..15672715a41 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -137,4 +137,5 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-vesting/runtime-benchmarks", ] diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 064132e61cc..796782a102b 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. spec_version: 233, - impl_version: 0, + impl_version: 1, apis: RUNTIME_API_VERSIONS, }; @@ -864,6 +864,13 @@ impl_runtime_apis! { steps, repeat, ), + b"pallet-vesting" | b"vesting" => Vesting::run_benchmark( + extrinsic, + lowest_range_values, + highest_range_values, + steps, + repeat, + ), _ => Err("Benchmark not found for this pallet."), }; diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index f01a0f6bf22..882c062c438 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -17,6 +17,7 @@ sp-io = { version = "2.0.0-alpha.2", default-features = false, path = "../../pri sp-runtime = { version = "2.0.0-alpha.2", default-features = false, path = "../../primitives/runtime" } frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" } frame-system = { version = "2.0.0-alpha.2", default-features = false, path = "../system" } +frame-benchmarking = { version = "2.0.0-alpha.2", default-features = false, path = "../benchmarking", optional = true } [dev-dependencies] sp-core = { version = "2.0.0-alpha.2", path = "../../primitives/core" } @@ -35,3 +36,4 @@ std = [ "frame-support/std", "frame-system/std", ] +runtime-benchmarks = ["frame-benchmarking", "frame-system/runtime-benchmarks"] diff --git a/frame/vesting/src/benchmarking.rs b/frame/vesting/src/benchmarking.rs new file mode 100644 index 00000000000..79ab0cb6e32 --- /dev/null +++ b/frame/vesting/src/benchmarking.rs @@ -0,0 +1,111 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Vesting pallet benchmarking. + +use super::*; + +use frame_system::{RawOrigin, Module as System}; +use sp_io::hashing::blake2_256; +use frame_benchmarking::{benchmarks, account}; + +use crate::Module as Vesting; + +const SEED: u32 = 0; +const MAX_LOCKS: u32 = 20; + +fn add_locks(l: u32) { + for id in 0..l { + let lock_id = <[u8; 8]>::decode(&mut &id.using_encoded(blake2_256)[..]) + .unwrap_or_default(); + let locker = account("locker", 0, SEED); + let locked = 1; + let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; + T::Currency::set_lock(lock_id, &locker, locked.into(), reasons); + } +} + +fn setup(b: u32) -> T::AccountId { + let locked = 1; + let per_block = 1; + let starting_block = 0; + + let caller = account("caller", 0, SEED); + + // Add schedule to avoid `NotVesting` error. + let _ = Vesting::::add_vesting_schedule( + &caller, + locked.into(), + per_block.into(), + starting_block.into(), + ); + + // Set lock and block number to take different code paths. + let reasons = WithdrawReason::Transfer | WithdrawReason::Reserve; + T::Currency::set_lock(VESTING_ID, &caller, locked.into(), reasons); + System::::set_block_number(b.into()); + + caller +} + +benchmarks! { + _ { + // Current block. It allows to hit different paths of `update_lock`. + // It doesn't seems to influence the timings which branch is taken. + let b in 0 .. 1 => (); + // Number of previous locks. + // It doesn't seems to influence the timings for lower values. + let l in 0 .. MAX_LOCKS => add_locks::(l); + } + + vest { + let b in ...; + let l in ...; + + let caller = setup::(b); + + }: _(RawOrigin::Signed(caller)) + + vest_other { + let b in ...; + let l in ...; + + let other: T::AccountId = setup::(b); + let other_lookup: ::Source = T::Lookup::unlookup(other.clone()); + + let caller = account("caller", 0, SEED); + + }: _(RawOrigin::Signed(caller), other_lookup) + + vested_transfer { + let u in 0 .. 1000; + + let from = account("from", u, SEED); + let to = account("to", u, SEED); + let to_lookup: ::Source = T::Lookup::unlookup(to); + + let transfer_amount = T::MinVestedTransfer::get(); + + let vesting_schedule = VestingInfo { + locked: transfer_amount, + per_block: 1.into(), + starting_block: 0.into(), + }; + + let _ = T::Currency::make_free_balance_be(&from, transfer_amount * 10.into()); + + }: _(RawOrigin::Signed(from), to_lookup, vesting_schedule) +} diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 02d5bebfd2c..223b8406786 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -60,6 +60,9 @@ use frame_support::traits::{ use frame_support::weights::SimpleDispatchInfo; use frame_system::{self as system, ensure_signed}; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; pub trait Trait: frame_system::Trait { -- GitLab From 0a5bd0bc79eed723529f6b37dfa26d89bb242ff4 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 9 Mar 2020 13:39:05 +0200 Subject: [PATCH 002/220] Update logic to cancel_deferred_slash (#5186) * Update logic to cancel_deferred_slash * More idiomatic * bump spec Co-authored-by: Gavin Wood --- bin/node/runtime/src/lib.rs | 4 +-- frame/staking/src/lib.rs | 27 ++++++++++--------- frame/staking/src/tests.rs | 54 +++++++++++++++++++++++++++++++++---- 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 796782a102b..34cb8eb749e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -82,8 +82,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 233, - impl_version: 1, + spec_version: 234, + impl_version: 0, apis: RUNTIME_API_VERSIONS, }; diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 627cd1c2a19..5226f5a3b39 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -928,6 +928,8 @@ decl_error! { InvalidEraToReward, /// Invalid number of nominations. InvalidNumberOfNominations, + /// Items are not sorted and unique. + NotSortedAndUnique, } } @@ -1327,21 +1329,15 @@ decl_module! { .map(|_| ()) .or_else(ensure_root)?; - let mut slash_indices = slash_indices; - slash_indices.sort_unstable(); + ensure!(!slash_indices.is_empty(), Error::::EmptyTargets); + ensure!(Self::is_sorted_and_unique(&slash_indices), Error::::NotSortedAndUnique); + let mut unapplied = ::UnappliedSlashes::get(&era); + let last_item = slash_indices[slash_indices.len() - 1]; + ensure!((last_item as usize) < unapplied.len(), Error::::InvalidSlashIndex); for (removed, index) in slash_indices.into_iter().enumerate() { - let index = index as usize; - - // if `index` is not duplicate, `removed` must be <= index. - ensure!(removed <= index, Error::::DuplicateIndex); - - // all prior removals were from before this index, since the - // list is sorted. - let index = index - removed; - ensure!(index < unapplied.len(), Error::::InvalidSlashIndex); - + let index = (index as usize) - removed; unapplied.remove(index); } @@ -1411,7 +1407,7 @@ decl_module! { let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( - ledger.unlocking.len() > 0, + !ledger.unlocking.is_empty(), Error::::NoUnlockChunk, ); @@ -1460,6 +1456,11 @@ impl Module { Self::bonded(stash).and_then(Self::ledger).map(|l| l.active).unwrap_or_default() } + /// Check that list is sorted and has no duplicates. + fn is_sorted_and_unique(list: &Vec) -> bool { + list.windows(2).all(|w| w[0] < w[1]) + } + // MUTABLES (DANGEROUS) fn do_payout_nominator(who: T::AccountId, era: EraIndex, validators: Vec<(T::AccountId, u32)>) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 507b5591d5f..00a8f854dbb 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -2616,7 +2616,13 @@ fn remove_deferred() { 1, ); - Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0]).unwrap(); + // fails if empty + assert_noop!( + Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![]), + Error::::EmptyTargets + ); + + assert_ok!(Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0])); assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); @@ -2689,12 +2695,51 @@ fn remove_multi_deferred() { &[Perbill::from_percent(25)], ); - assert_eq!(::UnappliedSlashes::get(&1).len(), 3); - Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0, 2]).unwrap(); + on_offence_now( + &[ + OffenceDetails { + offender: (42, exposure.clone()), + reporters: vec![], + }, + ], + &[Perbill::from_percent(25)], + ); + + on_offence_now( + &[ + OffenceDetails { + offender: (69, exposure.clone()), + reporters: vec![], + }, + ], + &[Perbill::from_percent(25)], + ); + + assert_eq!(::UnappliedSlashes::get(&1).len(), 5); + + // fails if list is not sorted + assert_noop!( + Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![2, 0, 4]), + Error::::NotSortedAndUnique + ); + // fails if list is not unique + assert_noop!( + Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0, 2, 2]), + Error::::NotSortedAndUnique + ); + // fails if bad index + assert_noop!( + Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![1, 2, 3, 4, 5]), + Error::::InvalidSlashIndex + ); + + assert_ok!(Staking::cancel_deferred_slash(Origin::ROOT, 1, vec![0, 2, 4])); let slashes = ::UnappliedSlashes::get(&1); - assert_eq!(slashes.len(), 1); + assert_eq!(slashes.len(), 2); + println!("Slashes: {:?}", slashes); assert_eq!(slashes[0].validator, 21); + assert_eq!(slashes[1].validator, 42); }) } @@ -2994,4 +3039,3 @@ fn set_history_depth_works() { assert!(!::ErasTotalStake::contains_key(10 - 5)); }); } - -- GitLab From 6b5a7adecf2c853b9c188ace500422056b858164 Mon Sep 17 00:00:00 2001 From: Jianping Deng Date: Mon, 9 Mar 2020 19:39:17 +0800 Subject: [PATCH 003/220] Add 6 as address type of ss58 for Bifrost Network (#5184) --- primitives/core/src/crypto.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 8fa7c7e7b40..50f5c94b08a 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -438,6 +438,8 @@ ss58_address_format!( (2, "kusama", "Kusama Relay-chain, direct checksum, standard account (*25519).") PlasmAccountDirect => (5, "plasm", "Plasm Network, direct checksum, standard account (*25519).") + BifrostAccountDirect => + (6, "bifrost", "Bifrost mainnet, direct checksum, standard account (*25519).") EdgewareAccountDirect => (7, "edgeware", "Edgeware mainnet, direct checksum, standard account (*25519).") KaruraAccountDirect => -- GitLab From e896cf3da7a4d691789d874551fbbc850232e6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 9 Mar 2020 12:39:49 +0100 Subject: [PATCH 004/220] Improve debug implementation of `CheckNonce` and `CheckEra` (#5156) --- frame/system/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index f1286beac4e..bd9e61b51ab 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1257,7 +1257,7 @@ impl CheckNonce { impl Debug for CheckNonce { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - self.0.fmt(f) + write!(f, "CheckNonce({})", self.0) } #[cfg(not(feature = "std"))] @@ -1336,19 +1336,19 @@ impl IsDeadAccount for Module { /// Check for transaction mortality. #[derive(Encode, Decode, Clone, Eq, PartialEq)] -pub struct CheckEra((Era, sp_std::marker::PhantomData)); +pub struct CheckEra(Era, sp_std::marker::PhantomData); impl CheckEra { /// utility constructor. Used only in client/factory code. pub fn from(era: Era) -> Self { - Self((era, sp_std::marker::PhantomData)) + Self(era, sp_std::marker::PhantomData) } } impl Debug for CheckEra { #[cfg(feature = "std")] fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - self.0.fmt(f) + write!(f, "CheckEra({:?})", self.0) } #[cfg(not(feature = "std"))] @@ -1373,7 +1373,7 @@ impl SignedExtension for CheckEra { _len: usize, ) -> TransactionValidity { let current_u64 = >::block_number().saturated_into::(); - let valid_till = (self.0).0.death(current_u64); + let valid_till = self.0.death(current_u64); Ok(ValidTransaction { longevity: valid_till.saturating_sub(current_u64), ..Default::default() @@ -1382,7 +1382,7 @@ impl SignedExtension for CheckEra { fn additional_signed(&self) -> Result { let current_u64 = >::block_number().saturated_into::(); - let n = (self.0).0.birth(current_u64).saturated_into::(); + let n = self.0.birth(current_u64).saturated_into::(); if !>::contains_key(n) { Err(InvalidTransaction::AncientBirthBlock.into()) } else { -- GitLab From 78cdd3bf9b50d6a4fdfe510b5174bb22e2863f25 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 9 Mar 2020 16:31:29 +0100 Subject: [PATCH 005/220] client/network-gossip: Merge GossipEngine and GossipEngineInner (#5042) * client/network-gossip: Merge GossipEngine and GossipEngineInner Given that GossipEngine and GossipEngineInner are not shared between threads anyone (public interface + background tasks), neither depends on being Send or Sync. Thus one can merge the two as done in this patch. One only needs to wrap an `Arc>` around the whole structure when the owner (e.g. finality-grandpa) needs to share the gossip engine between threads. * client/finality-grandpa: Wrap GossipEngine in Arc Mutex & lock it on use GossipEngine in itself has no need to be Send and Sync, given that it does not rely on separately spawned background tasks anymore. Given that finality-grandpa shares the `NetworkBridge` potentially between threads its components need to be clonable, thus this patch wraps `GossipEngine` in an `Arc>`. --- Cargo.lock | 1 - .../finality-grandpa/src/communication/mod.rs | 52 ++++++------- client/network-gossip/Cargo.toml | 1 - client/network-gossip/src/bridge.rs | 73 +++++-------------- 4 files changed, 43 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b170d90826..32b2d0dc0f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6245,7 +6245,6 @@ dependencies = [ "libp2p", "log 0.4.8", "lru", - "parking_lot 0.10.0", "sc-network", "sp-runtime", "wasm-timer", diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 1f4e2235971..7525c44f15e 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -142,7 +142,7 @@ pub(crate) fn global_topic(set_id: SetIdNumber) -> B::Hash { /// Bridge between the underlying network service, gossiping consensus messages and Grandpa pub(crate) struct NetworkBridge> { service: N, - gossip_engine: GossipEngine, + gossip_engine: Arc>>, validator: Arc>, /// Sender side of the neighbor packet channel. @@ -185,12 +185,12 @@ impl> NetworkBridge { ); let validator = Arc::new(validator); - let gossip_engine = GossipEngine::new( + let gossip_engine = Arc::new(Mutex::new(GossipEngine::new( service.clone(), GRANDPA_ENGINE_ID, GRANDPA_PROTOCOL_NAME, validator.clone() - ); + ))); { // register all previous votes with the gossip service so that they're @@ -214,7 +214,7 @@ impl> NetworkBridge { } ); - gossip_engine.register_gossip_message( + gossip_engine.lock().register_gossip_message( topic, message.encode(), ); @@ -293,7 +293,7 @@ impl> NetworkBridge { }); let topic = round_topic::(round.0, set_id.0); - let incoming = self.gossip_engine.messages_for(topic) + let incoming = self.gossip_engine.lock().messages_for(topic) .filter_map(move |notification| { let decoded = GossipMessage::::decode(&mut ¬ification.message[..]); @@ -422,11 +422,11 @@ impl> NetworkBridge { impl> Future for NetworkBridge { type Output = Result<(), Error>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { loop { match self.neighbor_packet_worker.lock().poll_next_unpin(cx) { Poll::Ready(Some((to, packet))) => { - self.gossip_engine.send_message(to, packet.encode()); + self.gossip_engine.lock().send_message(to, packet.encode()); }, Poll::Ready(None) => return Poll::Ready( Err(Error::Network("Neighbor packet worker stream closed.".into())) @@ -438,7 +438,7 @@ impl> Future for NetworkBridge { loop { match self.gossip_validator_report_stream.lock().poll_next_unpin(cx) { Poll::Ready(Some(PeerReport { who, cost_benefit })) => { - self.gossip_engine.report(who, cost_benefit); + self.gossip_engine.lock().report(who, cost_benefit); }, Poll::Ready(None) => return Poll::Ready( Err(Error::Network("Gossip validator report stream closed.".into())) @@ -447,7 +447,7 @@ impl> Future for NetworkBridge { } } - match self.gossip_engine.poll_unpin(cx) { + match self.gossip_engine.lock().poll_unpin(cx) { // The gossip engine future finished. We should do the same. Poll::Ready(()) => return Poll::Ready(Ok(())), Poll::Pending => {}, @@ -458,7 +458,7 @@ impl> Future for NetworkBridge { } fn incoming_global( - mut gossip_engine: GossipEngine, + gossip_engine: Arc>>, topic: B::Hash, voters: Arc>, gossip_validator: Arc>, @@ -467,7 +467,7 @@ fn incoming_global( let process_commit = move | msg: FullCommitMessage, mut notification: sc_network_gossip::TopicNotification, - gossip_engine: &mut GossipEngine, + gossip_engine: &Arc>>, gossip_validator: &Arc>, voters: &VoterSet, | { @@ -491,7 +491,7 @@ fn incoming_global( msg.set_id, ) { if let Some(who) = notification.sender { - gossip_engine.report(who, cost); + gossip_engine.lock().report(who, cost); } return None; @@ -513,12 +513,12 @@ fn incoming_global( |to, neighbor| neighbor_sender.send(to, neighbor), ); - gossip_engine.gossip_message(topic, notification.message.clone(), false); + gossip_engine.lock().gossip_message(topic, notification.message.clone(), false); } voter::CommitProcessingOutcome::Bad(_) => { // report peer and do not gossip. if let Some(who) = notification.sender.take() { - gossip_engine.report(who, cost::INVALID_COMMIT); + gossip_engine.lock().report(who, cost::INVALID_COMMIT); } } }; @@ -531,7 +531,7 @@ fn incoming_global( let process_catch_up = move | msg: FullCatchUpMessage, mut notification: sc_network_gossip::TopicNotification, - gossip_engine: &mut GossipEngine, + gossip_engine: &Arc>>, gossip_validator: &Arc>, voters: &VoterSet, | { @@ -544,7 +544,7 @@ fn incoming_global( msg.set_id, ) { if let Some(who) = notification.sender { - gossip_engine.report(who, cost); + gossip_engine.lock().report(who, cost); } return None; @@ -554,7 +554,7 @@ fn incoming_global( if let voter::CatchUpProcessingOutcome::Bad(_) = outcome { // report peer if let Some(who) = notification.sender.take() { - gossip_engine.report(who, cost::INVALID_CATCH_UP); + gossip_engine.lock().report(who, cost::INVALID_CATCH_UP); } } @@ -566,7 +566,7 @@ fn incoming_global( Some(voter::CommunicationIn::CatchUp(msg.message, cb)) }; - gossip_engine.messages_for(topic) + gossip_engine.clone().lock().messages_for(topic) .filter_map(|notification| { // this could be optimized by decoding piecewise. let decoded = GossipMessage::::decode(&mut ¬ification.message[..]); @@ -578,9 +578,9 @@ fn incoming_global( .filter_map(move |(notification, msg)| { future::ready(match msg { GossipMessage::Commit(msg) => - process_commit(msg, notification, &mut gossip_engine, &gossip_validator, &*voters), + process_commit(msg, notification, &gossip_engine, &gossip_validator, &*voters), GossipMessage::CatchUp(msg) => - process_catch_up(msg, notification, &mut gossip_engine, &gossip_validator, &*voters), + process_catch_up(msg, notification, &gossip_engine, &gossip_validator, &*voters), _ => { debug!(target: "afg", "Skipping unknown message type"); None @@ -688,7 +688,7 @@ pub(crate) struct OutgoingMessages { set_id: SetIdNumber, locals: Option<(AuthorityPair, AuthorityId)>, sender: mpsc::Sender>, - network: GossipEngine, + network: Arc>>, has_voted: HasVoted, } @@ -754,11 +754,11 @@ impl Sink> for OutgoingMessages ); // announce the block we voted on to our peers. - self.network.announce(target_hash, Vec::new()); + self.network.lock().announce(target_hash, Vec::new()); // propagate the message to peers let topic = round_topic::(self.round, self.set_id); - self.network.gossip_message(topic, message.encode(), false); + self.network.lock().gossip_message(topic, message.encode(), false); // forward the message to the inner sender. return self.sender.start_send(signed).map_err(|e| { @@ -959,7 +959,7 @@ fn check_catch_up( /// An output sink for commit messages. struct CommitsOut { - network: GossipEngine, + network: Arc>>, set_id: SetId, is_voter: bool, gossip_validator: Arc>, @@ -969,7 +969,7 @@ struct CommitsOut { impl CommitsOut { /// Create a new commit output stream. pub(crate) fn new( - network: GossipEngine, + network: Arc>>, set_id: SetIdNumber, is_voter: bool, gossip_validator: Arc>, @@ -1028,7 +1028,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { commit.target_number, |to, neighbor| self.neighbor_sender.send(to, neighbor), ); - self.network.gossip_message(topic, message.encode(), false); + self.network.lock().gossip_message(topic, message.encode(), false); Ok(()) } diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 08c304c6e06..955911f1f07 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -16,7 +16,6 @@ futures-timer = "3.0.1" libp2p = { version = "0.16.2", default-features = false, features = ["libp2p-websocket"] } log = "0.4.8" lru = "0.4.3" -parking_lot = "0.10.0" sc-network = { version = "0.8.0-alpha.2", path = "../network" } sp-runtime = { version = "2.0.0-alpha.2", path = "../../primitives/runtime" } wasm-timer = "0.2" diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index c911766aba4..c06cb6268cc 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -22,18 +22,12 @@ use sc_network::{Event, ReputationChange}; use futures::{prelude::*, channel::mpsc}; use libp2p::PeerId; -use parking_lot::Mutex; use sp_runtime::{traits::Block as BlockT, ConsensusEngineId}; use std::{borrow::Cow, pin::Pin, sync::Arc, task::{Context, Poll}}; /// Wraps around an implementation of the `Network` crate and provides gossiping capabilities on /// top of it. pub struct GossipEngine { - inner: Arc>>, - engine_id: ConsensusEngineId, -} - -struct GossipEngineInner { state_machine: ConsensusGossip, network: Box + Send>, periodic_maintenance_interval: futures_timer::Delay, @@ -41,7 +35,7 @@ struct GossipEngineInner { engine_id: ConsensusEngineId, } -impl Unpin for GossipEngineInner {} +impl Unpin for GossipEngine {} impl GossipEngine { /// Create a new instance. @@ -60,24 +54,17 @@ impl GossipEngine { network.register_notifications_protocol(engine_id, protocol_name.into()); state_machine.register_validator(&mut network, engine_id, validator); - let inner = Arc::new(Mutex::new(GossipEngineInner { + GossipEngine { state_machine, network: Box::new(network), periodic_maintenance_interval: futures_timer::Delay::new(PERIODIC_MAINTENANCE_INTERVAL), network_event_stream, engine_id, - })); - - let gossip_engine = GossipEngine { - inner: inner.clone(), - engine_id, - }; - - gossip_engine + } } pub fn report(&self, who: PeerId, reputation: ReputationChange) { - self.inner.lock().network.report_peer(who, reputation); + self.network.report_peer(who, reputation); } /// Registers a message without propagating it to any peers. The message @@ -86,7 +73,7 @@ impl GossipEngine { /// message is already expired it should be dropped on the next garbage /// collection. pub fn register_gossip_message( - &self, + &mut self, topic: B::Hash, message: Vec, ) { @@ -95,38 +82,34 @@ impl GossipEngine { data: message, }; - self.inner.lock().state_machine.register_message(topic, message); + self.state_machine.register_message(topic, message); } /// Broadcast all messages with given topic. - pub fn broadcast_topic(&self, topic: B::Hash, force: bool) { - let mut inner = self.inner.lock(); - let inner = &mut *inner; - inner.state_machine.broadcast_topic(&mut *inner.network, topic, force); + pub fn broadcast_topic(&mut self, topic: B::Hash, force: bool) { + self.state_machine.broadcast_topic(&mut *self.network, topic, force); } /// Get data of valid, incoming messages for a topic (but might have expired meanwhile). - pub fn messages_for(&self, topic: B::Hash) + pub fn messages_for(&mut self, topic: B::Hash) -> mpsc::UnboundedReceiver { - self.inner.lock().state_machine.messages_for(self.engine_id, topic) + self.state_machine.messages_for(self.engine_id, topic) } /// Send all messages with given topic to a peer. pub fn send_topic( - &self, + &mut self, who: &PeerId, topic: B::Hash, force: bool ) { - let mut inner = self.inner.lock(); - let inner = &mut *inner; - inner.state_machine.send_topic(&mut *inner.network, who, topic, self.engine_id, force) + self.state_machine.send_topic(&mut *self.network, who, topic, self.engine_id, force) } /// Multicast a message to all peers. pub fn gossip_message( - &self, + &mut self, topic: B::Hash, message: Vec, force: bool, @@ -136,19 +119,14 @@ impl GossipEngine { data: message, }; - let mut inner = self.inner.lock(); - let inner = &mut *inner; - inner.state_machine.multicast(&mut *inner.network, topic, message, force) + self.state_machine.multicast(&mut *self.network, topic, message, force) } /// Send addressed message to the given peers. The message is not kept or multicast /// later on. - pub fn send_message(&self, who: Vec, data: Vec) { - let mut inner = self.inner.lock(); - let inner = &mut *inner; - + pub fn send_message(&mut self, who: Vec, data: Vec) { for who in &who { - inner.state_machine.send_message(&mut *inner.network, who, ConsensusMessage { + self.state_machine.send_message(&mut *self.network, who, ConsensusMessage { engine_id: self.engine_id, data: data.clone(), }); @@ -160,21 +138,13 @@ impl GossipEngine { /// Note: this method isn't strictly related to gossiping and should eventually be moved /// somewhere else. pub fn announce(&self, block: B::Hash, associated_data: Vec) { - self.inner.lock().network.announce(block, associated_data); + self.network.announce(block, associated_data); } } impl Future for GossipEngine { type Output = (); - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - self.inner.lock().poll_unpin(cx) - } -} - -impl Future for GossipEngineInner { - type Output = (); - fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll { let this = &mut *self; @@ -216,12 +186,3 @@ impl Future for GossipEngineInner { Poll::Pending } } - -impl Clone for GossipEngine { - fn clone(&self) -> Self { - GossipEngine { - inner: self.inner.clone(), - engine_id: self.engine_id.clone(), - } - } -} -- GitLab From 1c15f4f6cf187cce1f18279f10f8b926be440e3d Mon Sep 17 00:00:00 2001 From: thiolliere Date: Mon, 9 Mar 2020 16:32:24 +0100 Subject: [PATCH 006/220] Change space to tab (#5193) --- frame/staking/src/migration/deprecated.rs | 60 ++-- frame/staking/src/migration/tests.rs | 410 +++++++++++----------- 2 files changed, 235 insertions(+), 235 deletions(-) diff --git a/frame/staking/src/migration/deprecated.rs b/frame/staking/src/migration/deprecated.rs index 41cf6652291..b5ec26d32f6 100644 --- a/frame/staking/src/migration/deprecated.rs +++ b/frame/staking/src/migration/deprecated.rs @@ -24,50 +24,50 @@ use sp_std::prelude::*; /// Reward points of an era. Used to split era total payout between validators. #[derive(Encode, Decode, Default)] pub struct EraPoints { - /// Total number of points. Equals the sum of reward points for each validator. - pub total: u32, - /// The reward points earned by a given validator. The index of this vec corresponds to the - /// index into the current validator set. - pub individual: Vec, + /// Total number of points. Equals the sum of reward points for each validator. + pub total: u32, + /// The reward points earned by a given validator. The index of this vec corresponds to the + /// index into the current validator set. + pub individual: Vec, } #[derive(Encode, Decode)] pub struct OldStakingLedger { - pub stash: AccountId, - #[codec(compact)] - pub total: Balance, - #[codec(compact)] - pub active: Balance, - pub unlocking: Vec>, + pub stash: AccountId, + #[codec(compact)] + pub total: Balance, + #[codec(compact)] + pub active: Balance, + pub unlocking: Vec>, } decl_module! { - pub struct Module for enum Call where origin: T::Origin { } + pub struct Module for enum Call where origin: T::Origin { } } decl_storage! { - pub trait Store for Module as Staking { - pub SlotStake: BalanceOf; + pub trait Store for Module as Staking { + pub SlotStake: BalanceOf; - /// The currently elected validator set keyed by stash account ID. - pub CurrentElected: Vec; + /// The currently elected validator set keyed by stash account ID. + pub CurrentElected: Vec; - /// The start of the current era. - pub CurrentEraStart: MomentOf; + /// The start of the current era. + pub CurrentEraStart: MomentOf; - /// The session index at which the current era started. - pub CurrentEraStartSessionIndex: SessionIndex; + /// The session index at which the current era started. + pub CurrentEraStartSessionIndex: SessionIndex; - /// Rewards for the current era. Using indices of current elected set. - pub CurrentEraPointsEarned: EraPoints; + /// Rewards for the current era. Using indices of current elected set. + pub CurrentEraPointsEarned: EraPoints; - /// Nominators for a particular account that is in action right now. You can't iterate - /// through validators here, but you can find them in the Session module. - /// - /// This is keyed by the stash account. - pub Stakers: map hasher(blake2_256) T::AccountId => Exposure>; + /// Nominators for a particular account that is in action right now. You can't iterate + /// through validators here, but you can find them in the Session module. + /// + /// This is keyed by the stash account. + pub Stakers: map hasher(blake2_256) T::AccountId => Exposure>; - /// Old upgrade flag. - pub IsUpgraded: bool; - } + /// Old upgrade flag. + pub IsUpgraded: bool; + } } diff --git a/frame/staking/src/migration/tests.rs b/frame/staking/src/migration/tests.rs index d1ba35cadce..db437e08c18 100644 --- a/frame/staking/src/migration/tests.rs +++ b/frame/staking/src/migration/tests.rs @@ -7,214 +7,214 @@ use sp_runtime::traits::OnRuntimeUpgrade; #[test] fn upgrade_works() { - ExtBuilder::default().build().execute_with(|| { - start_era(3); - - assert_eq!(Session::validators(), vec![21, 11]); - - // Insert fake data to check the migration - put_storage_value::>(b"Staking", b"CurrentElected", b"", vec![21, 31]); - put_storage_value::(b"Staking", b"CurrentEraStartSessionIndex", b"", 5); - put_storage_value::>(b"Staking", b"CurrentEraStart", b"", 777); - put_storage_value( - b"Staking", b"Stakers", &blake2_256(&11u64.encode()), - Exposure:: { - total: 10, - own: 10, - others: vec![], - } - ); - put_storage_value( - b"Staking", b"Stakers", &blake2_256(&21u64.encode()), - Exposure:: { - total: 20, - own: 20, - others: vec![], - } - ); - put_storage_value( - b"Staking", b"Stakers", &blake2_256(&31u64.encode()), - Exposure:: { - total: 30, - own: 30, - others: vec![], - } - ); - put_storage_value::<(u32, Vec)>(b"Staking", b"CurrentEraPointsEarned", b"", (12, vec![2, 10])); - ::ErasStakers::remove_all(); - ::ErasStakersClipped::remove_all(); - - ::StorageVersion::put(Releases::V1_0_0); - - // Perform upgrade - Staking::on_runtime_upgrade(); - - assert_eq!(::StorageVersion::get(), Releases::V2_0_0); - - // Check migration - assert_eq!(::ErasStartSessionIndex::get(3).unwrap(), 5); - assert_eq!(::ErasRewardPoints::get(3), EraRewardPoints { - total: 12, - individual: vec![(21, 2), (31, 10)].into_iter().collect(), - }); - assert_eq!(::ActiveEra::get().unwrap().index, 3); - assert_eq!(::ActiveEra::get().unwrap().start, Some(777)); - assert_eq!(::CurrentEra::get().unwrap(), 3); - assert_eq!(::ErasStakers::get(3, 11), Exposure { - total: 0, - own: 0, - others: vec![], - }); - assert_eq!(::ErasStakers::get(3, 21), Exposure { - total: 20, - own: 20, - others: vec![], - }); - assert_eq!(::ErasStakers::get(3, 31), Exposure { - total: 30, - own: 30, - others: vec![], - }); - assert_eq!(::ErasStakersClipped::get(3, 11), Exposure { - total: 0, - own: 0, - others: vec![], - }); - assert_eq!(::ErasStakersClipped::get(3, 21), Exposure { - total: 20, - own: 20, - others: vec![], - }); - assert_eq!(::ErasStakersClipped::get(3, 31), Exposure { - total: 30, - own: 30, - others: vec![], - }); - assert_eq!(::ErasValidatorPrefs::get(3, 21), Staking::validators(21)); - assert_eq!(::ErasValidatorPrefs::get(3, 31), Staking::validators(31)); - assert_eq!(::ErasTotalStake::get(3), 50); - }) + ExtBuilder::default().build().execute_with(|| { + start_era(3); + + assert_eq!(Session::validators(), vec![21, 11]); + + // Insert fake data to check the migration + put_storage_value::>(b"Staking", b"CurrentElected", b"", vec![21, 31]); + put_storage_value::(b"Staking", b"CurrentEraStartSessionIndex", b"", 5); + put_storage_value::>(b"Staking", b"CurrentEraStart", b"", 777); + put_storage_value( + b"Staking", b"Stakers", &blake2_256(&11u64.encode()), + Exposure:: { + total: 10, + own: 10, + others: vec![], + } + ); + put_storage_value( + b"Staking", b"Stakers", &blake2_256(&21u64.encode()), + Exposure:: { + total: 20, + own: 20, + others: vec![], + } + ); + put_storage_value( + b"Staking", b"Stakers", &blake2_256(&31u64.encode()), + Exposure:: { + total: 30, + own: 30, + others: vec![], + } + ); + put_storage_value::<(u32, Vec)>(b"Staking", b"CurrentEraPointsEarned", b"", (12, vec![2, 10])); + ::ErasStakers::remove_all(); + ::ErasStakersClipped::remove_all(); + + ::StorageVersion::put(Releases::V1_0_0); + + // Perform upgrade + Staking::on_runtime_upgrade(); + + assert_eq!(::StorageVersion::get(), Releases::V2_0_0); + + // Check migration + assert_eq!(::ErasStartSessionIndex::get(3).unwrap(), 5); + assert_eq!(::ErasRewardPoints::get(3), EraRewardPoints { + total: 12, + individual: vec![(21, 2), (31, 10)].into_iter().collect(), + }); + assert_eq!(::ActiveEra::get().unwrap().index, 3); + assert_eq!(::ActiveEra::get().unwrap().start, Some(777)); + assert_eq!(::CurrentEra::get().unwrap(), 3); + assert_eq!(::ErasStakers::get(3, 11), Exposure { + total: 0, + own: 0, + others: vec![], + }); + assert_eq!(::ErasStakers::get(3, 21), Exposure { + total: 20, + own: 20, + others: vec![], + }); + assert_eq!(::ErasStakers::get(3, 31), Exposure { + total: 30, + own: 30, + others: vec![], + }); + assert_eq!(::ErasStakersClipped::get(3, 11), Exposure { + total: 0, + own: 0, + others: vec![], + }); + assert_eq!(::ErasStakersClipped::get(3, 21), Exposure { + total: 20, + own: 20, + others: vec![], + }); + assert_eq!(::ErasStakersClipped::get(3, 31), Exposure { + total: 30, + own: 30, + others: vec![], + }); + assert_eq!(::ErasValidatorPrefs::get(3, 21), Staking::validators(21)); + assert_eq!(::ErasValidatorPrefs::get(3, 31), Staking::validators(31)); + assert_eq!(::ErasTotalStake::get(3), 50); + }) } // Test that an upgrade from previous test environment works. #[test] fn test_upgrade_from_master_works() { - let data_sets = &[ - test_upgrade_from_master_dataset::_0, - test_upgrade_from_master_dataset::_1, - test_upgrade_from_master_dataset::_2, - test_upgrade_from_master_dataset::_3, - test_upgrade_from_master_dataset::_4, - test_upgrade_from_master_dataset::_5, - test_upgrade_from_master_dataset::_6, - test_upgrade_from_master_dataset::_7, - test_upgrade_from_master_dataset::_8, - ]; - for data_set in data_sets.iter() { - let mut storage = sp_runtime::Storage::default(); - for (key, value) in data_set.iter() { - storage.top.insert(key.to_vec(), value.to_vec()); - } - let mut ext = sp_io::TestExternalities::from(storage); - ext.execute_with(|| { - let old_stakers = - get_storage_value::>(b"Staking", b"CurrentElected", b"").unwrap(); - let old_staker_0 = old_stakers[0]; - let old_staker_1 = old_stakers[1]; - let old_current_era = - get_storage_value::(b"Staking", b"CurrentEra", b"").unwrap(); - let old_staker_0_exposure = get_storage_value::>( - b"Staking", b"Stakers", &blake2_256(&old_staker_0.encode()) - ).unwrap(); - let old_staker_1_exposure = get_storage_value::>( - b"Staking", b"Stakers", &blake2_256(&old_staker_1.encode()) - ).unwrap(); - let ( - old_era_points_earned_total, - old_era_points_earned_individual - ) = get_storage_value::<(u32, Vec)>(b"Staking", b"CurrentEraPointsEarned", b"") - .unwrap_or((0, vec![])); - - Staking::on_runtime_upgrade(); - assert!(::StorageVersion::get() == Releases::V2_0_0); - - // Check ActiveEra and CurrentEra - let active_era = Staking::active_era().unwrap().index; - let current_era = Staking::current_era().unwrap(); - assert!(current_era == active_era); - assert!(current_era == old_current_era); - - // Check ErasStartSessionIndex - let active_era_start = Staking::eras_start_session_index(active_era).unwrap(); - let current_era_start = Staking::eras_start_session_index(current_era).unwrap(); - let current_session_index = Session::current_index(); - assert!(current_era_start == active_era_start); - assert!(active_era_start <= current_session_index); - assert_eq!(::ErasStartSessionIndex::iter().count(), 1); - - // Check ErasStakers - assert_eq!(::ErasStakers::iter().count(), 2); - assert_eq!( - ::ErasStakers::get(current_era, old_staker_0), - old_staker_0_exposure - ); - assert_eq!( - ::ErasStakers::get(current_era, old_staker_1), - old_staker_1_exposure - ); - - // Check ErasStakersClipped - assert_eq!(::ErasStakersClipped::iter().count(), 2); - assert!(::ErasStakersClipped::iter().all(|exposure_clipped| { - let max = ::MaxNominatorRewardedPerValidator::get() as usize; - exposure_clipped.others.len() <= max - })); - assert_eq!( - ::ErasStakersClipped::get(current_era, old_staker_0), - old_staker_0_exposure - ); - assert_eq!( - ::ErasStakersClipped::get(current_era, old_staker_1), - old_staker_1_exposure - ); - - // Check ErasValidatorPrefs - assert_eq!(::ErasValidatorPrefs::iter().count(), 2); - assert_eq!( - ::ErasValidatorPrefs::get(current_era, old_staker_0), - Staking::validators(old_staker_0) - ); - assert_eq!( - ::ErasValidatorPrefs::get(current_era, old_staker_1), - Staking::validators(old_staker_1) - ); - - // Check ErasTotalStake - assert_eq!(::ErasTotalStake::iter().count(), 1); - assert_eq!( - ::ErasTotalStake::get(current_era), - old_staker_0_exposure.total + old_staker_1_exposure.total - ); - - // Check ErasRewardPoints - assert_eq!(::ErasRewardPoints::iter().count(), 1); - let mut individual = BTreeMap::new(); - if let Some(p) = old_era_points_earned_individual.get(0) { - individual.insert(old_staker_0, p.clone()); - } - if let Some(p) = old_era_points_earned_individual.get(1) { - individual.insert(old_staker_1, p.clone()); - } - assert_eq!( - ::ErasRewardPoints::get(current_era), - EraRewardPoints { - total: old_era_points_earned_total, - individual, - } - ); - - // Check ErasValidatorReward - assert_eq!(::ErasValidatorReward::iter().count(), 0); - }); - } + let data_sets = &[ + test_upgrade_from_master_dataset::_0, + test_upgrade_from_master_dataset::_1, + test_upgrade_from_master_dataset::_2, + test_upgrade_from_master_dataset::_3, + test_upgrade_from_master_dataset::_4, + test_upgrade_from_master_dataset::_5, + test_upgrade_from_master_dataset::_6, + test_upgrade_from_master_dataset::_7, + test_upgrade_from_master_dataset::_8, + ]; + for data_set in data_sets.iter() { + let mut storage = sp_runtime::Storage::default(); + for (key, value) in data_set.iter() { + storage.top.insert(key.to_vec(), value.to_vec()); + } + let mut ext = sp_io::TestExternalities::from(storage); + ext.execute_with(|| { + let old_stakers = + get_storage_value::>(b"Staking", b"CurrentElected", b"").unwrap(); + let old_staker_0 = old_stakers[0]; + let old_staker_1 = old_stakers[1]; + let old_current_era = + get_storage_value::(b"Staking", b"CurrentEra", b"").unwrap(); + let old_staker_0_exposure = get_storage_value::>( + b"Staking", b"Stakers", &blake2_256(&old_staker_0.encode()) + ).unwrap(); + let old_staker_1_exposure = get_storage_value::>( + b"Staking", b"Stakers", &blake2_256(&old_staker_1.encode()) + ).unwrap(); + let ( + old_era_points_earned_total, + old_era_points_earned_individual + ) = get_storage_value::<(u32, Vec)>(b"Staking", b"CurrentEraPointsEarned", b"") + .unwrap_or((0, vec![])); + + Staking::on_runtime_upgrade(); + assert!(::StorageVersion::get() == Releases::V2_0_0); + + // Check ActiveEra and CurrentEra + let active_era = Staking::active_era().unwrap().index; + let current_era = Staking::current_era().unwrap(); + assert!(current_era == active_era); + assert!(current_era == old_current_era); + + // Check ErasStartSessionIndex + let active_era_start = Staking::eras_start_session_index(active_era).unwrap(); + let current_era_start = Staking::eras_start_session_index(current_era).unwrap(); + let current_session_index = Session::current_index(); + assert!(current_era_start == active_era_start); + assert!(active_era_start <= current_session_index); + assert_eq!(::ErasStartSessionIndex::iter().count(), 1); + + // Check ErasStakers + assert_eq!(::ErasStakers::iter().count(), 2); + assert_eq!( + ::ErasStakers::get(current_era, old_staker_0), + old_staker_0_exposure + ); + assert_eq!( + ::ErasStakers::get(current_era, old_staker_1), + old_staker_1_exposure + ); + + // Check ErasStakersClipped + assert_eq!(::ErasStakersClipped::iter().count(), 2); + assert!(::ErasStakersClipped::iter().all(|exposure_clipped| { + let max = ::MaxNominatorRewardedPerValidator::get() as usize; + exposure_clipped.others.len() <= max + })); + assert_eq!( + ::ErasStakersClipped::get(current_era, old_staker_0), + old_staker_0_exposure + ); + assert_eq!( + ::ErasStakersClipped::get(current_era, old_staker_1), + old_staker_1_exposure + ); + + // Check ErasValidatorPrefs + assert_eq!(::ErasValidatorPrefs::iter().count(), 2); + assert_eq!( + ::ErasValidatorPrefs::get(current_era, old_staker_0), + Staking::validators(old_staker_0) + ); + assert_eq!( + ::ErasValidatorPrefs::get(current_era, old_staker_1), + Staking::validators(old_staker_1) + ); + + // Check ErasTotalStake + assert_eq!(::ErasTotalStake::iter().count(), 1); + assert_eq!( + ::ErasTotalStake::get(current_era), + old_staker_0_exposure.total + old_staker_1_exposure.total + ); + + // Check ErasRewardPoints + assert_eq!(::ErasRewardPoints::iter().count(), 1); + let mut individual = BTreeMap::new(); + if let Some(p) = old_era_points_earned_individual.get(0) { + individual.insert(old_staker_0, p.clone()); + } + if let Some(p) = old_era_points_earned_individual.get(1) { + individual.insert(old_staker_1, p.clone()); + } + assert_eq!( + ::ErasRewardPoints::get(current_era), + EraRewardPoints { + total: old_era_points_earned_total, + individual, + } + ); + + // Check ErasValidatorReward + assert_eq!(::ErasValidatorReward::iter().count(), 0); + }); + } } -- GitLab From 971cdc3e3b1050447205dd32f4e1fbf745ef5a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 9 Mar 2020 23:46:03 +0000 Subject: [PATCH 007/220] grandpa: improve handling of global gossip messages (#5133) * grandpa: only gossip commits to peers on the same set * grandpa: track commits uniquely by round and set * grandpa: fix communication test * grandpa: add tests for commit gossip handling * grandpa: add missing docs --- .../src/communication/gossip.rs | 238 +++++++++++++++--- .../finality-grandpa/src/communication/mod.rs | 11 +- .../src/communication/tests.rs | 22 +- 3 files changed, 237 insertions(+), 34 deletions(-) diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 7fef47867f0..77c3543aae1 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -147,14 +147,6 @@ impl Default for View { } impl View { - /// Update the set ID. implies a reset to round 0. - fn update_set(&mut self, set_id: SetId) { - if set_id != self.set_id { - self.set_id = set_id; - self.round = Round(1); - } - } - /// Consider a round and set ID combination under a current view. fn consider_vote(&self, round: Round, set_id: SetId) -> Consider { // only from current set @@ -188,6 +180,39 @@ impl View { } } +/// A local view of protocol state. Only differs from `View` in that we also +/// track the round and set id at which the last commit was observed. +struct LocalView { + round: Round, + set_id: SetId, + last_commit: Option<(N, Round, SetId)>, +} + +impl LocalView { + /// Converts the local view to a `View` discarding round and set id + /// information about the last commit. + fn as_view(&self) -> View<&N> { + View { + round: self.round, + set_id: self.set_id, + last_commit: self.last_commit_height(), + } + } + + /// Update the set ID. implies a reset to round 1. + fn update_set(&mut self, set_id: SetId) { + if set_id != self.set_id { + self.set_id = set_id; + self.round = Round(1); + } + } + + /// Returns the height of the block that the last observed commit finalizes. + fn last_commit_height(&self) -> Option<&N> { + self.last_commit.as_ref().map(|(number, _, _)| number) + } +} + const KEEP_RECENT_ROUNDS: usize = 3; /// Tracks gossip topics that we are keeping messages for. We keep topics of: @@ -614,7 +639,7 @@ impl CatchUpConfig { } struct Inner { - local_view: Option>>, + local_view: Option>>, peers: Peers>, live_topics: KeepTopics, round_start: Instant, @@ -690,7 +715,7 @@ impl Inner { fn note_set(&mut self, set_id: SetId, authorities: Vec) -> MaybeMessage { { let local_view = match self.local_view { - ref mut x @ None => x.get_or_insert(View { + ref mut x @ None => x.get_or_insert(LocalView { round: Round(1), set_id, last_commit: None, @@ -710,12 +735,17 @@ impl Inner { } /// Note that we've imported a commit finalizing a given block. - fn note_commit_finalized(&mut self, finalized: NumberFor) -> MaybeMessage { + fn note_commit_finalized( + &mut self, + round: Round, + set_id: SetId, + finalized: NumberFor, + ) -> MaybeMessage { { match self.local_view { None => return None, - Some(ref mut v) => if v.last_commit.as_ref() < Some(&finalized) { - v.last_commit = Some(finalized); + Some(ref mut v) => if v.last_commit_height() < Some(&finalized) { + v.last_commit = Some((finalized, round, set_id)); } else { return None }, @@ -726,12 +756,16 @@ impl Inner { } fn consider_vote(&self, round: Round, set_id: SetId) -> Consider { - self.local_view.as_ref().map(|v| v.consider_vote(round, set_id)) + self.local_view.as_ref() + .map(LocalView::as_view) + .map(|v| v.consider_vote(round, set_id)) .unwrap_or(Consider::RejectOutOfScope) } fn consider_global(&self, set_id: SetId, number: NumberFor) -> Consider { - self.local_view.as_ref().map(|v| v.consider_global(set_id, number)) + self.local_view.as_ref() + .map(LocalView::as_view) + .map(|v| v.consider_global(set_id, &number)) .unwrap_or(Consider::RejectOutOfScope) } @@ -1012,7 +1046,7 @@ impl Inner { let packet = NeighborPacket { round: local_view.round, set_id: local_view.set_id, - commit_finalized_height: local_view.last_commit.unwrap_or(Zero::zero()), + commit_finalized_height: *local_view.last_commit_height().unwrap_or(&Zero::zero()), }; let peers = self.peers.inner.keys().cloned().collect(); @@ -1210,10 +1244,21 @@ impl GossipValidator { } /// Note that we've imported a commit finalizing a given block. - pub(super) fn note_commit_finalized(&self, finalized: NumberFor, send_neighbor: F) + pub(super) fn note_commit_finalized( + &self, + round: Round, + set_id: SetId, + finalized: NumberFor, + send_neighbor: F, + ) where F: FnOnce(Vec, NeighborPacket>) { - let maybe_msg = self.inner.write().note_commit_finalized(finalized); + let maybe_msg = self.inner.write().note_commit_finalized( + round, + set_id, + finalized, + ); + if let Some((to, msg)) = maybe_msg { send_neighbor(to, msg); } @@ -1289,7 +1334,7 @@ impl sc_network_gossip::Validator for GossipValidator sc_network_gossip::Validator for GossipValidator return false, // cannot evaluate until we have a local view. }; - let our_best_commit = local_view.last_commit; - let peer_best_commit = peer.view.last_commit; - match GossipMessage::::decode(&mut data) { Err(_) => false, Ok(GossipMessage::Commit(full)) => { - // we only broadcast our best commit and only if it's - // better than last received by peer. - Some(full.message.target_number) == our_best_commit && - Some(full.message.target_number) > peer_best_commit + // we only broadcast commit messages if they're for the same + // set the peer is in and if the commit is better than the + // last received by peer, additionally we make sure to only + // broadcast our best commit. + peer.view.consider_global(set_id, full.message.target_number) == Consider::Accept && + Some(&full.message.target_number) == local_view.last_commit_height() } Ok(GossipMessage::Neighbor(_)) => false, Ok(GossipMessage::CatchUpRequest(_)) => false, @@ -1432,12 +1476,17 @@ impl sc_network_gossip::Validator for GossipValidator::decode(&mut data) { Err(_) => true, - Ok(GossipMessage::Commit(full)) - => Some(full.message.target_number) != best_commit, + Ok(GossipMessage::Commit(full)) => match local_view.last_commit { + Some((number, round, set_id)) => + // we expire any commit message that doesn't target the same block + // as our best commit or isn't from the same round and set id + !(full.message.target_number == number && + full.round == round && + full.set_id == set_id), + None => true, + }, Ok(_) => true, } }) @@ -2306,4 +2355,133 @@ mod tests { } } } + + #[test] + fn only_gossip_commits_to_peers_on_same_set() { + let (val, _) = GossipValidator::::new(config(), voter_set_state()); + + // the validator start at set id 1 + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + // add a new peer at set id 1 + let peer1 = PeerId::random(); + + val.inner + .write() + .peers + .new_peer(peer1.clone(), Roles::AUTHORITY); + + val.inner + .write() + .peers + .update_peer_state( + &peer1, + NeighborPacket { + round: Round(1), + set_id: SetId(1), + commit_finalized_height: 1, + }, + ) + .unwrap(); + + // peer2 will default to set id 0 + let peer2 = PeerId::random(); + val.inner + .write() + .peers + .new_peer(peer2.clone(), Roles::AUTHORITY); + + // create a commit for round 1 of set id 1 + // targeting a block at height 2 + let commit = { + let commit = finality_grandpa::CompactCommit { + target_hash: H256::random(), + target_number: 2, + precommits: Vec::new(), + auth_data: Vec::new(), + }; + + crate::communication::gossip::GossipMessage::::Commit( + crate::communication::gossip::FullCommitMessage { + round: Round(1), + set_id: SetId(1), + message: commit, + }, + ) + .encode() + }; + + // note the commit in the validator + val.note_commit_finalized(Round(1), SetId(1), 2, |_, _| {}); + + let mut message_allowed = val.message_allowed(); + + // the commit should be allowed to peer 1 + assert!(message_allowed( + &peer1, + MessageIntent::Broadcast, + &crate::communication::global_topic::(1), + &commit, + )); + + // but disallowed to peer 2 since the peer is on set id 0 + // the commit should be allowed to peer 1 + assert!(!message_allowed( + &peer2, + MessageIntent::Broadcast, + &crate::communication::global_topic::(1), + &commit, + )); + } + + #[test] + fn expire_commits_from_older_rounds() { + let (val, _) = GossipValidator::::new(config(), voter_set_state()); + + let commit = |round, set_id, target_number| { + let commit = finality_grandpa::CompactCommit { + target_hash: H256::random(), + target_number, + precommits: Vec::new(), + auth_data: Vec::new(), + }; + + crate::communication::gossip::GossipMessage::::Commit( + crate::communication::gossip::FullCommitMessage { + round: Round(round), + set_id: SetId(set_id), + message: commit, + }, + ) + .encode() + }; + + // note the beginning of a new set with id 1 + val.note_set(SetId(1), Vec::new(), |_, _| {}); + + // note a commit for round 1 in the validator + // finalizing a block at height 2 + val.note_commit_finalized(Round(1), SetId(1), 2, |_, _| {}); + + let mut message_expired = val.message_expired(); + + // a commit message for round 1 that finalizes the same height as we + // have observed previously should not be expired + assert!(!message_expired( + crate::communication::global_topic::(1), + &commit(1, 1, 2), + )); + + // it should be expired if it is for a lower block + assert!(message_expired( + crate::communication::global_topic::(1), + &commit(1, 1, 1), + )); + + // or the same block height but from the previous round + assert!(message_expired( + crate::communication::global_topic::(1), + &commit(0, 1, 2), + )); + } } diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 7525c44f15e..d496f305fc5 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -497,7 +497,8 @@ fn incoming_global( return None; } - let round = msg.round.0; + let round = msg.round; + let set_id = msg.set_id; let commit = msg.message; let finalized_number = commit.target_number; let gossip_validator = gossip_validator.clone(); @@ -509,6 +510,8 @@ fn incoming_global( // any discrepancy between the actual ghost and the claimed // finalized number. gossip_validator.note_commit_finalized( + round, + set_id, finalized_number, |to, neighbor| neighbor_sender.send(to, neighbor), ); @@ -525,7 +528,7 @@ fn incoming_global( let cb = voter::Callback::Work(Box::new(cb)); - Some(voter::CommunicationIn::Commit(round, commit, cb)) + Some(voter::CommunicationIn::Commit(round.0, commit, cb)) }; let process_catch_up = move | @@ -1015,7 +1018,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { }; let message = GossipMessage::Commit(FullCommitMessage:: { - round: round, + round, set_id: self.set_id, message: compact_commit, }); @@ -1025,6 +1028,8 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { // the gossip validator needs to be made aware of the best commit-height we know of // before gossiping self.gossip_validator.note_commit_finalized( + round, + self.set_id, commit.target_number, |to, neighbor| self.neighbor_sender.send(to, neighbor), ); diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 96761a2f3c0..fb2c0f12f45 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -292,12 +292,32 @@ fn good_commit_leads_to_relay() { }); // Add a random peer which will be the recipient of this message + let receiver_id = sc_network::PeerId::random(); let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { - remote: sc_network::PeerId::random(), + remote: receiver_id.clone(), engine_id: GRANDPA_ENGINE_ID, roles: Roles::FULL, }); + // Announce its local set has being on the current set id through a neighbor + // packet, otherwise it won't be eligible to receive the commit + let _ = { + let update = gossip::VersionedNeighborPacket::V1( + gossip::NeighborPacket { + round: Round(round), + set_id: SetId(set_id), + commit_finalized_height: 1, + } + ); + + let msg = gossip::GossipMessage::::Neighbor(update); + + sender.unbounded_send(NetworkEvent::NotificationsReceived { + remote: receiver_id, + messages: vec![(GRANDPA_ENGINE_ID, msg.encode().into())], + }) + }; + true } _ => false, -- GitLab From 51ead38104df06ed1886dd348d18022dad40f5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 10 Mar 2020 10:44:56 +0100 Subject: [PATCH 008/220] Make sure to always run `wasm-builder` for the `HOST` architecture (#5199) --- utils/wasm-builder-runner/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/wasm-builder-runner/src/lib.rs b/utils/wasm-builder-runner/src/lib.rs index 6366c1ce375..0e4b1421f88 100644 --- a/utils/wasm-builder-runner/src/lib.rs +++ b/utils/wasm-builder-runner/src/lib.rs @@ -428,6 +428,10 @@ fn run_project(project_folder: &Path) { cmd.arg("--release"); } + // Make sure we always run the `wasm-builder` project for the `HOST` architecture. + let host_triple = env::var("HOST").expect("`HOST` is always set when executing `build.rs`."); + cmd.arg(&format!("--target={}", host_triple)); + // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir exclusive). // The runner project is created in `CARGO_TARGET_DIR` and executing it will create a sub target // directory inside of `CARGO_TARGET_DIR`. -- GitLab From 22f85eff6b025f954e42b23c06b9f01d4b2f3e7f Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 10 Mar 2020 10:45:10 +0100 Subject: [PATCH 009/220] Make sc-offchain tests more resilient on macOS (#5191) * offchain: Simplify bits of http code * offchain: Sort dev-dependencies * deps: Bump parity-multiaddr to 0.7.3 Fixes build failure when using: rustc 1.43.0-nightly (96bb8b31c 2020-03-05). * offchain: Raise FD limit for HTTP tests * offchain: Reword the comment on increasing the test fd limit --- Cargo.lock | 9 +++++---- client/offchain/Cargo.toml | 7 ++++--- client/offchain/src/api/http.rs | 12 ++++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32b2d0dc0f2..6fb0b658b89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2642,7 +2642,7 @@ dependencies = [ "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", - "parity-multiaddr 0.7.2", + "parity-multiaddr 0.7.3", "parity-multihash 0.2.3", "parking_lot 0.10.0", "pin-project", @@ -2666,7 +2666,7 @@ dependencies = [ "libsecp256k1", "log 0.4.8", "multistream-select", - "parity-multiaddr 0.7.2", + "parity-multiaddr 0.7.3", "parity-multihash 0.2.3", "parking_lot 0.10.0", "pin-project", @@ -4585,9 +4585,9 @@ dependencies = [ [[package]] name = "parity-multiaddr" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26df883298bc3f4e92528b4c5cc9f806b791955b136da3e5e939ed9de0fd958b" +checksum = "f77055f9e81921a8cc7bebeb6cded3d128931d51f1e3dd6251f0770a6d431477" dependencies = [ "arrayref", "bs58 0.3.0", @@ -6281,6 +6281,7 @@ version = "2.0.0-alpha.3" dependencies = [ "bytes 0.5.4", "env_logger 0.7.1", + "fdlimit", "fnv", "futures 0.3.4", "futures-timer 3.0.2", diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 9ea0372969b..e5c8e8228d4 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -32,12 +32,13 @@ hyper = "0.13.2" hyper-rustls = "0.19" [dev-dependencies] -sc-client-db = { version = "0.8.0-alpha.2", default-features = true, path = "../db/" } env_logger = "0.7.0" -substrate-test-runtime-client = { version = "2.0.0-dev", path = "../../test-utils/runtime/client" } -tokio = "0.2" +fdlimit = "0.1" +sc-client-db = { version = "0.8.0-alpha.2", default-features = true, path = "../db/" } sc-transaction-pool = { version = "2.0.0-alpha.2", path = "../../client/transaction-pool" } sp-transaction-pool = { version = "2.0.0-alpha.2", path = "../../primitives/transaction-pool" } +substrate-test-runtime-client = { version = "2.0.0-dev", path = "../../test-utils/runtime/client" } +tokio = "0.2" [features] default = [] diff --git a/client/offchain/src/api/http.rs b/client/offchain/src/api/http.rs index 0483f84e2f1..7923a767f11 100644 --- a/client/offchain/src/api/http.rs +++ b/client/offchain/src/api/http.rs @@ -304,7 +304,7 @@ impl HttpApi { let mut output = Vec::with_capacity(ids.len()); let mut must_wait_more = false; for id in ids { - output.push(match self.requests.get_mut(id) { + output.push(match self.requests.get(id) { None => HttpRequestStatus::Invalid, Some(HttpApiRequest::NotDispatched(_, _)) => unreachable!("we replaced all the NotDispatched with Dispatched earlier; qed"), @@ -322,10 +322,8 @@ impl HttpApi { // Are we ready to call `return`? let is_done = if let future::MaybeDone::Done(_) = deadline { true - } else if !must_wait_more { - true } else { - false + !must_wait_more }; if is_done { @@ -701,6 +699,12 @@ mod tests { let _ = tokio::runtime::Runtime::new().unwrap().block_on(future); } + // We spawn quite a bit of HTTP servers here due to how async API + // works for offchain workers, so be sure to raise the FD limit + // (particularly useful for macOS where the default soft limit may + // not be enough). + fdlimit::raise_fd_limit(); + let (api, worker) = http(); std::thread::spawn(move || tokio_run(worker)); -- GitLab From d771dfad511736bc3b6efbe8121dbe8bc05b5c76 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 10 Mar 2020 11:12:32 +0100 Subject: [PATCH 010/220] client/service/src/builder.rs: Add build_info metric (#5192) * client/service/src/builder.rs: Add build_info metric Add static Prometheus metric exposing the chain name, the version and the commit. * client/service/src/builder.rs: Move node_role to static metrics The Prometheus metrics `node_role` is static and thus there is no need to keep a reference of it within `ServiceMetrics`. This follows the example of the `build_info` metric. * client/service/src/builder.rs: Adjust indentation --- client/service/src/builder.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index e49f5687337..e4328a34038 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -61,7 +61,6 @@ struct ServiceMetrics { memory_usage_bytes: Gauge, cpu_usage_percentage: Gauge, network_per_sec_bytes: GaugeVec, - node_roles: Gauge, database_cache: Gauge, state_cache: Gauge, state_db: GaugeVec, @@ -87,9 +86,6 @@ impl ServiceMetrics { Opts::new("network_per_sec_bytes", "Networking bytes per second"), &["direction"] )?, registry)?, - node_roles: register(Gauge::new( - "node_roles", "The roles the node is running as", - )?, registry)?, database_cache: register(Gauge::new( "database_cache_bytes", "RocksDB cache size in bytes", )?, registry)?, @@ -1011,18 +1007,34 @@ ServiceBuilder< ); } - // Prometheus metrics + // Prometheus metrics. let metrics = if let Some(PrometheusConfig { port, registry }) = config.prometheus_config.clone() { + // Set static metrics. + register(Gauge::::with_opts( + Opts::new( + "build_info", + "A metric with a constant '1' value labeled by name, version, and commit." + ) + .const_label("name", config.impl_name) + .const_label("version", config.impl_version) + .const_label("commit", config.impl_commit), + )?, ®istry)?.set(1); + register(Gauge::::new( + "node_roles", "The roles the node is running as", + )?, ®istry)?.set(u64::from(config.roles.bits())); + let metrics = ServiceMetrics::register(®istry)?; - metrics.node_roles.set(u64::from(config.roles.bits())); + spawn_handle.spawn( "prometheus-endpoint", prometheus_endpoint::init_prometheus(port, registry).map(drop) ); + Some(metrics) } else { None }; + // Periodically notify the telemetry. let transaction_pool_ = transaction_pool.clone(); let client_ = client.clone(); -- GitLab From f1419b13faf90e14cc9ed85caf9054c4daa8c7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 10 Mar 2020 11:13:20 +0100 Subject: [PATCH 011/220] Don't include `:code` by default in storage proofs (#5179) * Don't include `:code` by default in storage proofs (#5060) * Adds test to verify that the runtime currently is always contained in the proof * Start passing the runtime wasm code from the outside * Fix compilation * More build fixes * Make the test work as expected now :) * Last fixes * Fixes benchmarks * Review feedback * Apply suggestions from code review Co-Authored-By: Sergei Pepyakin * Review feedback * Fix compilation Co-authored-by: Sergei Pepyakin * Fix compilation and change the way `RuntimeCode` works * Fix tests * Switch to `Cow` Co-authored-by: Benjamin Kampmann Co-authored-by: Sergei Pepyakin --- Cargo.lock | 5 + bin/node/executor/Cargo.toml | 1 + bin/node/executor/benches/bench.rs | 21 +++- bin/node/executor/tests/common.rs | 13 ++- .../basic-authorship/src/basic_authorship.rs | 1 - client/block-builder/Cargo.toml | 4 + client/block-builder/src/lib.rs | 38 ++++++ client/executor/src/integration_tests/mod.rs | 2 + client/executor/src/lib.rs | 9 +- client/executor/src/native_executor.rs | 60 ++++++++-- client/executor/src/wasm_runtime.rs | 48 ++------ client/network/src/chain.rs | 7 +- .../src/protocol/light_client_handler.rs | 19 +-- client/network/src/protocol/light_dispatch.rs | 6 +- client/src/call_executor.rs | 85 ++++++++------ client/src/client.rs | 19 ++- client/src/genesis.rs | 14 +++ client/src/light/backend.rs | 4 +- client/src/light/call_executor.rs | 13 ++- client/src/light/fetcher.rs | 11 +- frame/system/benches/bench.rs | 2 +- frame/system/src/lib.rs | 1 + primitives/api/test/Cargo.toml | 1 + primitives/api/test/tests/runtime_calls.rs | 7 ++ primitives/core/src/traits.rs | 90 ++++++++++++++- primitives/externalities/src/lib.rs | 30 ----- primitives/io/src/lib.rs | 2 +- primitives/runtime-interface/test/src/lib.rs | 3 +- primitives/runtime/src/generic/block.rs | 11 +- primitives/state-machine/src/backend.rs | 43 ++++++- primitives/state-machine/src/basic.rs | 26 ----- primitives/state-machine/src/ext.rs | 68 ----------- primitives/state-machine/src/lib.rs | 65 +++++++++-- .../state-machine/src/proving_backend.rs | 100 +--------------- primitives/trie/src/lib.rs | 2 + primitives/trie/src/storage_proof.rs | 109 ++++++++++++++++++ test-utils/runtime/src/system.rs | 16 ++- utils/frame/benchmarking-cli/Cargo.toml | 1 + utils/frame/benchmarking-cli/src/lib.rs | 1 + 39 files changed, 596 insertions(+), 362 deletions(-) create mode 100644 primitives/trie/src/storage_proof.rs diff --git a/Cargo.lock b/Cargo.lock index 6fb0b658b89..5f6d9b41d0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1470,6 +1470,7 @@ dependencies = [ "sc-executor", "sc-service", "sp-runtime", + "sp-state-machine", "structopt", ] @@ -3426,6 +3427,7 @@ dependencies = [ "sc-executor", "sp-application-crypto", "sp-core", + "sp-externalities", "sp-io", "sp-runtime", "sp-state-machine", @@ -5651,6 +5653,8 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", + "sp-trie", + "substrate-test-runtime-client", ] [[package]] @@ -6964,6 +6968,7 @@ dependencies = [ "sp-api", "sp-blockchain", "sp-consensus", + "sp-core", "sp-runtime", "sp-state-machine", "sp-version", diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index c8ef75a5a2a..a77efcf7f85 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -36,6 +36,7 @@ pallet-transaction-payment = { version = "2.0.0-alpha.2", path = "../../../frame pallet-treasury = { version = "2.0.0-alpha.2", path = "../../../frame/treasury" } sp-application-crypto = { version = "2.0.0-alpha.2", path = "../../../primitives/application-crypto" } sp-runtime = { version = "2.0.0-alpha.2", path = "../../../primitives/runtime" } +sp-externalities = { version = "0.8.0-alpha.3", path = "../../../primitives/externalities" } substrate-test-client = { version = "2.0.0-dev", path = "../../../test-utils/client" } wabt = "0.9.2" diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index ef0cdf445a5..cb6b6a09168 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -25,8 +25,8 @@ use node_runtime::constants::currency::*; use node_testing::keyring::*; use sp_core::{NativeOrEncoded, NeverNativeValue}; use sp_core::storage::well_known_keys; -use sp_core::traits::CodeExecutor; -use frame_support::Hashable; +use sp_core::traits::{CodeExecutor, RuntimeCode}; +use frame_support::Hashable; use sp_state_machine::TestExternalities as CoreTestExternalities; use sc_executor::{NativeExecutor, RuntimeInfo, WasmExecutionMethod, Externalities}; use sp_runtime::traits::BlakeTwo256; @@ -90,9 +90,16 @@ fn construct_block( digest: Default::default(), }; + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(COMPACT_CODE.into()), + hash: vec![1, 2, 3], + heap_pages: None, + }; + // execute the block to get the real header. executor.call:: _>( ext, + &runtime_code, "Core_initialize_block", &header.encode(), true, @@ -102,6 +109,7 @@ fn construct_block( for i in extrinsics.iter() { executor.call:: _>( ext, + &runtime_code, "BlockBuilder_apply_extrinsic", &i.encode(), true, @@ -111,6 +119,7 @@ fn construct_block( let header = match executor.call:: _>( ext, + &runtime_code, "BlockBuilder_finalize_block", &[0u8;0], true, @@ -162,11 +171,16 @@ fn bench_execute_block(c: &mut Criterion) { ExecutionMethod::Wasm(wasm_method) => (false, *wasm_method), }; let executor = NativeExecutor::new(wasm_method, None); + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(COMPACT_CODE.into()), + hash: vec![1, 2, 3], + heap_pages: None, + }; // Get the runtime version to initialize the runtimes cache. { let mut test_ext = new_test_ext(&genesis_config); - executor.runtime_version(&mut test_ext.ext()).unwrap(); + executor.runtime_version(&mut test_ext.ext(), &runtime_code).unwrap(); } let blocks = test_blocks(&genesis_config, &executor); @@ -177,6 +191,7 @@ fn bench_execute_block(c: &mut Criterion) { for block in blocks.iter() { executor.call:: _>( &mut test_ext.ext(), + &runtime_code, "Core_execute_block", &block.0, use_native, diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 34f3034208a..d8ede1d7cda 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -17,7 +17,7 @@ use codec::{Encode, Decode}; use frame_support::Hashable; use sp_state_machine::TestExternalities as CoreTestExternalities; -use sp_core::{NeverNativeValue, NativeOrEncoded, traits::CodeExecutor}; +use sp_core::{NeverNativeValue, NativeOrEncoded, traits::{CodeExecutor, RuntimeCode}}; use sp_runtime::{ApplyExtrinsicResult, traits::{Header as HeaderT, BlakeTwo256}}; use sc_executor::{NativeExecutor, WasmExecutionMethod}; use sc_executor::error::Result; @@ -29,6 +29,7 @@ use node_runtime::{ }; use node_primitives::{Hash, BlockNumber}; use node_testing::keyring::*; +use sp_externalities::Externalities; /// The wasm runtime code. /// @@ -71,8 +72,18 @@ pub fn executor_call< native_call: Option, ) -> (Result>, bool) { let mut t = t.ext(); + + let code = t.storage(sp_core::storage::well_known_keys::CODE).unwrap(); + let heap_pages = t.storage(sp_core::storage::well_known_keys::HEAP_PAGES); + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(code.as_slice().into()), + hash: sp_core::blake2_256(&code).to_vec(), + heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), + }; + executor().call::( &mut t, + &runtime_code, method, data, use_native, diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index 9dfe1c33be0..fc9a5dec066 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -471,4 +471,3 @@ mod tests { client.import(BlockOrigin::Own, block).unwrap(); } } - diff --git a/client/block-builder/Cargo.toml b/client/block-builder/Cargo.toml index 745669c033e..dd4ebcb07f8 100644 --- a/client/block-builder/Cargo.toml +++ b/client/block-builder/Cargo.toml @@ -19,3 +19,7 @@ sp-core = { version = "2.0.0-alpha.2", path = "../../primitives/core" } sp-block-builder = { version = "2.0.0-alpha.2", path = "../../primitives/block-builder" } sc-client-api = { version = "2.0.0-alpha.2", path = "../api" } codec = { package = "parity-scale-codec", version = "1.2.0", features = ["derive"] } + +[dev-dependencies] +substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } +sp-trie = { version = "2.0.0-alpha.2", path = "../../primitives/trie" } diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 6aaa8e90162..d0e9f85ff43 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -205,3 +205,41 @@ where }) } } + +#[cfg(test)] +mod tests { + use super::*; + use sp_blockchain::HeaderBackend; + use sp_core::Blake2Hasher; + use sp_state_machine::Backend; + use substrate_test_runtime_client::{DefaultTestClientBuilderExt, TestClientBuilderExt}; + + #[test] + fn block_building_storage_proof_does_not_include_runtime_by_default() { + let builder = substrate_test_runtime_client::TestClientBuilder::new(); + let backend = builder.backend(); + let client = builder.build(); + + let block = BlockBuilder::new( + &client, + client.info().best_hash, + client.info().best_number, + RecordProof::Yes, + Default::default(), + &*backend, + ).unwrap().build().unwrap(); + + let proof = block.proof.expect("Proof is build on request"); + + let backend = sp_state_machine::create_proof_check_backend::( + block.storage_changes.transaction_storage_root, + proof, + ).unwrap(); + + assert!( + backend.storage(&sp_core::storage::well_known_keys::CODE) + .unwrap_err() + .contains("Database missing expected key"), + ); + } +} diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index e787b229ec8..28e18bdb007 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -49,6 +49,7 @@ fn call_in_wasm( ); executor.call_in_wasm( &WASM_BINARY[..], + None, function, call_data, ext, @@ -513,6 +514,7 @@ fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) { ); executor.call_in_wasm( &WASM_BINARY[..], + None, "test_exhaust_heap", &[0], &mut ext.ext(), diff --git a/client/executor/src/lib.rs b/client/executor/src/lib.rs index 1c21026fd8d..539c8e82031 100644 --- a/client/executor/src/lib.rs +++ b/client/executor/src/lib.rs @@ -52,8 +52,12 @@ pub trait RuntimeInfo { /// Native runtime information. fn native_version(&self) -> &NativeVersion; - /// Extract RuntimeVersion of given :code block - fn runtime_version(&self, ext: &mut dyn Externalities) -> error::Result; + /// Extract [`RuntimeVersion`](sp_version::RuntimeVersion) of the given `runtime_code`. + fn runtime_version( + &self, + ext: &mut dyn Externalities, + runtime_code: &sp_core::traits::RuntimeCode, + ) -> error::Result; } #[cfg(test)] @@ -77,6 +81,7 @@ mod tests { ); let res = executor.call_in_wasm( &WASM_BINARY[..], + None, "test_empty_return", &[], &mut ext, diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index dfc88d2ede7..fb18528b609 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -16,11 +16,11 @@ use crate::{ RuntimeInfo, error::{Error, Result}, - wasm_runtime::{RuntimeCache, WasmExecutionMethod, CodeSource}, + wasm_runtime::{RuntimeCache, WasmExecutionMethod}, }; use sp_version::{NativeVersion, RuntimeVersion}; use codec::{Decode, Encode}; -use sp_core::{NativeOrEncoded, traits::{CodeExecutor, Externalities}}; +use sp_core::{NativeOrEncoded, traits::{CodeExecutor, Externalities, RuntimeCode}}; use log::trace; use std::{result, panic::{UnwindSafe, AssertUnwindSafe}, sync::Arc}; use sp_wasm_interface::{HostFunctions, Function}; @@ -111,7 +111,7 @@ impl WasmExecutor { } } - /// Execute the given closure `f` with the latest runtime (based on the `CODE` key in `ext`). + /// Execute the given closure `f` with the latest runtime (based on `runtime_code`). /// /// The closure `f` is expected to return `Err(_)` when there happened a `panic!` in native code /// while executing the runtime in Wasm. If a `panic!` occurred, the runtime is invalidated to @@ -124,9 +124,9 @@ impl WasmExecutor { /// runtime is invalidated on any `panic!` to prevent a poisoned state. `ext` is already /// implicitly handled as unwind safe, as we store it in a global variable while executing the /// native runtime. - fn with_instance<'c, R, F>( + fn with_instance( &self, - code: CodeSource<'c>, + runtime_code: &RuntimeCode, ext: &mut dyn Externalities, f: F, ) -> Result @@ -137,7 +137,7 @@ impl WasmExecutor { ) -> Result>, { match self.cache.with_instance( - code, + runtime_code, ext, self.method, self.default_heap_pages, @@ -158,17 +158,48 @@ impl WasmExecutor { impl sp_core::traits::CallInWasm for WasmExecutor { fn call_in_wasm( &self, - wasm_blob: &[u8], + wasm_code: &[u8], + code_hash: Option>, method: &str, call_data: &[u8], ext: &mut dyn Externalities, ) -> std::result::Result, String> { - self.with_instance(CodeSource::Custom(wasm_blob), ext, |instance, _, mut ext| { + if let Some(hash) = code_hash { + let code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(wasm_code.into()), + hash, + heap_pages: None, + }; + + self.with_instance(&code, ext, |instance, _, mut ext| { + with_externalities_safe( + &mut **ext, + move || instance.call(method, call_data), + ) + }).map_err(|e| e.to_string()) + } else { + let module = crate::wasm_runtime::create_wasm_runtime_with_code( + self.method, + self.default_heap_pages, + &wasm_code, + self.host_functions.to_vec(), + self.allow_missing_func_imports, + ) + .map_err(|e| format!("Failed to create module: {:?}", e))?; + + let instance = module.new_instance() + .map_err(|e| format!("Failed to create instance: {:?}", e))?; + + let instance = AssertUnwindSafe(instance); + let mut ext = AssertUnwindSafe(ext); + with_externalities_safe( &mut **ext, move || instance.call(method, call_data), ) - }).map_err(|e| e.to_string()) + .and_then(|r| r) + .map_err(|e| e.to_string()) + } } } @@ -220,8 +251,11 @@ impl RuntimeInfo for NativeExecutor { fn runtime_version( &self, ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, ) -> Result { - self.wasm.with_instance(CodeSource::Externalities, ext, + self.wasm.with_instance( + runtime_code, + ext, |_instance, version, _ext| Ok(version.cloned().ok_or_else(|| Error::ApiError("Unknown version".into()))) ) @@ -237,6 +271,7 @@ impl CodeExecutor for NativeExecutor { >( &self, ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, @@ -244,7 +279,7 @@ impl CodeExecutor for NativeExecutor { ) -> (Result>, bool) { let mut used_native = false; let result = self.wasm.with_instance( - CodeSource::Externalities, + runtime_code, ext, |instance, onchain_version, mut ext| { let onchain_version = onchain_version.ok_or_else( @@ -324,11 +359,12 @@ impl sp_core::traits::CallInWasm for NativeExecutor< fn call_in_wasm( &self, wasm_blob: &[u8], + code_hash: Option>, method: &str, call_data: &[u8], ext: &mut dyn Externalities, ) -> std::result::Result, String> { - sp_core::traits::CallInWasm::call_in_wasm(&self.wasm, wasm_blob, method, call_data, ext) + self.wasm.call_in_wasm(wasm_blob, code_hash, method, call_data, ext) } } diff --git a/client/executor/src/wasm_runtime.rs b/client/executor/src/wasm_runtime.rs index 680bc4c4589..09ed456e659 100644 --- a/client/executor/src/wasm_runtime.rs +++ b/client/executor/src/wasm_runtime.rs @@ -20,11 +20,10 @@ //! components of the runtime that are expensive to initialize. use std::sync::Arc; -use std::borrow::Cow; use crate::error::{Error, WasmError}; use parking_lot::{Mutex, RwLock}; use codec::Decode; -use sp_core::{storage::well_known_keys, traits::Externalities}; +use sp_core::traits::{Externalities, RuntimeCode, FetchRuntimeCode}; use sp_version::RuntimeVersion; use std::panic::AssertUnwindSafe; use sc_executor_common::wasm_runtime::{WasmModule, WasmInstance}; @@ -41,14 +40,6 @@ pub enum WasmExecutionMethod { Compiled, } -/// Executoed code origin. -pub enum CodeSource<'a> { - /// Take code from storage, - Externalities, - /// Use provided code, - Custom(&'a [u8]), -} - /// A Wasm runtime object along with its cached runtime version. struct VersionedRuntime { /// Runtime code hash. @@ -102,8 +93,7 @@ impl RuntimeCache { /// /// `code` - Provides external code or tells the executor to fetch it from storage. /// - /// `ext` - Externalities to use for the runtime. This is used for setting - /// up an initial runtime instance. + /// `runtime_code` - The runtime wasm code used setup the runtime. /// /// `default_heap_pages` - Number of 64KB pages to allocate for Wasm execution. /// @@ -124,7 +114,7 @@ impl RuntimeCache { /// identifier `memory` can be found in the runtime. pub fn with_instance<'c, R, F>( &self, - code: CodeSource<'c>, + runtime_code: &'c RuntimeCode<'c>, ext: &mut dyn Externalities, wasm_method: WasmExecutionMethod, default_heap_pages: u64, @@ -138,28 +128,14 @@ impl RuntimeCache { &mut dyn Externalities) -> Result, { - let (code_hash, heap_pages) = match &code { - CodeSource::Externalities => { - ( - ext - .original_storage_hash(well_known_keys::CODE) - .ok_or(Error::InvalidCode("`CODE` not found in storage.".into()))?, - ext - .storage(well_known_keys::HEAP_PAGES) - .and_then(|pages| u64::decode(&mut &pages[..]).ok()) - .unwrap_or(default_heap_pages), - ) - }, - CodeSource::Custom(code) => { - (sp_core::blake2_256(code).to_vec(), default_heap_pages) - } - }; + let code_hash = &runtime_code.hash; + let heap_pages = runtime_code.heap_pages.unwrap_or(default_heap_pages); let mut runtimes = self.runtimes.lock(); // this must be released prior to calling f let pos = runtimes.iter().position(|r| r.as_ref().map_or( false, |r| r.wasm_method == wasm_method && - r.code_hash == code_hash && + r.code_hash == *code_hash && r.heap_pages == heap_pages )); @@ -168,19 +144,11 @@ impl RuntimeCache { .clone() .expect("`position` only returns `Some` for entries that are `Some`"), None => { - let code = match code { - CodeSource::Externalities => { - Cow::Owned(ext.original_storage(well_known_keys::CODE) - .ok_or(WasmError::CodeNotFound)?) - } - CodeSource::Custom(code) => { - Cow::Borrowed(code) - } - }; + let code = runtime_code.fetch_runtime_code().ok_or(WasmError::CodeNotFound)?; let result = create_versioned_wasm_runtime( &code, - code_hash, + code_hash.clone(), ext, wasm_method, heap_pages, diff --git a/client/network/src/chain.rs b/client/network/src/chain.rs index 3c075ec881c..12033e1d512 100644 --- a/client/network/src/chain.rs +++ b/client/network/src/chain.rs @@ -66,7 +66,12 @@ pub trait Client: Send + Sync { ) -> Result; /// Get method execution proof. - fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec, StorageProof), Error>; + fn execution_proof( + &self, + block: &Block::Hash, + method: &str, + data: &[u8], + ) -> Result<(Vec, StorageProof), Error>; /// Get key changes proof. fn key_changes_proof( diff --git a/client/network/src/protocol/light_client_handler.rs b/client/network/src/protocol/light_client_handler.rs index a141e134fca..af8fa89f510 100644 --- a/client/network/src/protocol/light_client_handler.rs +++ b/client/network/src/protocol/light_client_handler.rs @@ -254,13 +254,12 @@ where B: Block, { /// Construct a new light client handler. - pub fn new - ( cfg: Config - , chain: Arc> - , checker: Arc> - , peerset: sc_peerset::PeersetHandle - ) -> Self - { + pub fn new( + cfg: Config, + chain: Arc>, + checker: Arc>, + peerset: sc_peerset::PeersetHandle, + ) -> Self { LightClientHandler { config: cfg, chain, @@ -425,7 +424,8 @@ where log::trace!("remote call request from {} ({} at {:?})", peer, request.method, - request.block); + request.block, + ); let block = Decode::decode(&mut request.block.as_ref())?; @@ -436,7 +436,8 @@ where peer, request.method, request.block, - e); + e, + ); StorageProof::empty() } }; diff --git a/client/network/src/protocol/light_dispatch.rs b/client/network/src/protocol/light_dispatch.rs index b734fc91eb2..8146172e159 100644 --- a/client/network/src/protocol/light_dispatch.rs +++ b/client/network/src/protocol/light_dispatch.rs @@ -750,7 +750,11 @@ pub mod tests { } } - fn check_execution_proof(&self, _: &RemoteCallRequest, _: StorageProof) -> ClientResult> { + fn check_execution_proof( + &self, + _: &RemoteCallRequest, + _: StorageProof, + ) -> ClientResult> { match self.ok { true => Ok(vec![42]), false => Err(ClientError::Backend("Test error".into())), diff --git a/client/src/call_executor.rs b/client/src/call_executor.rs index b5206d3c461..3fb6123640c 100644 --- a/client/src/call_executor.rs +++ b/client/src/call_executor.rs @@ -81,6 +81,7 @@ where id, self.backend.changes_trie_storage() )?; let state = self.backend.state_at(*id)?; + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let return_data = StateMachine::new( &state, changes_trie, @@ -89,6 +90,7 @@ where method, call_data, extensions.unwrap_or_default(), + &state_runtime_code.runtime_code()?, ).execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( strategy.get_manager(), None, @@ -135,42 +137,53 @@ where let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); let mut state = self.backend.state_at(*at)?; + match recorder { - Some(recorder) => state.as_trie_backend() - .ok_or_else(|| - Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) - as Box + Some(recorder) => { + let trie_state = state.as_trie_backend() + .ok_or_else(|| + Box::new(sp_state_machine::ExecutionError::UnableToGenerateProof) as Box + )?; + + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&trie_state); + // It is important to extract the runtime code here before we create the proof + // recorder. + let runtime_code = state_runtime_code.runtime_code()?; + + let backend = sp_state_machine::ProvingBackend::new_with_recorder( + trie_state, + recorder.clone(), + ); + + StateMachine::new( + &backend, + changes_trie_state, + &mut *changes.borrow_mut(), + &self.executor, + method, + call_data, + extensions.unwrap_or_default(), + &runtime_code, + ) + // TODO: https://github.com/paritytech/substrate/issues/4455 + // .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) + .execute_using_consensus_failure_handler(execution_manager, native_call) + }, + None => { + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); + StateMachine::new( + &state, + changes_trie_state, + &mut *changes.borrow_mut(), + &self.executor, + method, + call_data, + extensions.unwrap_or_default(), + &state_runtime_code.runtime_code()?, ) - .and_then(|trie_state| { - let backend = sp_state_machine::ProvingBackend::new_with_recorder( - trie_state, - recorder.clone(), - ); - - StateMachine::new( - &backend, - changes_trie_state, - &mut *changes.borrow_mut(), - &self.executor, - method, - call_data, - extensions.unwrap_or_default(), - ) - // TODO: https://github.com/paritytech/substrate/issues/4455 - // .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) - .execute_using_consensus_failure_handler(execution_manager, native_call) - }), - None => StateMachine::new( - &state, - changes_trie_state, - &mut *changes.borrow_mut(), - &self.executor, - method, - call_data, - extensions.unwrap_or_default(), - ) - .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) - .execute_using_consensus_failure_handler(execution_manager, native_call) + .with_storage_transaction_cache(storage_transaction_cache.as_mut().map(|c| &mut **c)) + .execute_using_consensus_failure_handler(execution_manager, native_call) + } }.map_err(Into::into) } @@ -189,7 +202,8 @@ where changes_trie_state, None, ); - self.executor.runtime_version(&mut ext) + let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); + self.executor.runtime_version(&mut ext, &state_runtime_code.runtime_code()?) .map_err(|e| sp_blockchain::Error::VersionInvalid(format!("{:?}", e)).into()) } @@ -206,6 +220,7 @@ where &self.executor, method, call_data, + &sp_state_machine::backend::BackendRuntimeCode::new(trie_state).runtime_code()?, ) .map_err(Into::into) } diff --git a/client/src/client.rs b/client/src/client.rs index adfdfb4b631..ab5ea820eec 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -41,8 +41,7 @@ use sp_runtime::{ use sp_state_machine::{ DBValue, Backend as StateBackend, ChangesTrieAnchorBlockId, prove_read, prove_child_read, ChangesTrieRootsStorage, ChangesTrieStorage, - ChangesTrieConfigurationRange, key_changes, key_changes_proof, StorageProof, - merge_storage_proofs, + ChangesTrieConfigurationRange, key_changes, key_changes_proof, }; use sc_executor::{RuntimeVersion, RuntimeInfo}; use sp_consensus::{ @@ -55,6 +54,7 @@ use sp_blockchain::{self as blockchain, well_known_cache_keys::Id as CacheKeyId, HeaderMetadata, CachedHeaderMetadata, }; +use sp_trie::StorageProof; use sp_api::{ CallApiAt, ConstructRuntimeApi, Core as CoreApi, ApiExt, ApiRef, ProvideRuntimeApi, @@ -472,7 +472,7 @@ impl Client where Ok(()) }, ())?; - Ok(merge_storage_proofs(proofs)) + Ok(StorageProof::merge(proofs)) } /// Generates CHT-based proof for roots of changes tries at given blocks (that are part of single CHT). @@ -1140,9 +1140,20 @@ impl ProofProvider for Client where method: &str, call_data: &[u8] ) -> sp_blockchain::Result<(Vec, StorageProof)> { + // Make sure we include the `:code` and `:heap_pages` in the execution proof to be + // backwards compatible. + // + // TODO: Remove when solved: https://github.com/paritytech/substrate/issues/5047 + let code_proof = self.read_proof( + id, + &mut [well_known_keys::CODE, well_known_keys::HEAP_PAGES].iter().map(|v| *v), + )?; + let state = self.state_at(id)?; let header = self.prepare_environment_block(id)?; - prove_execution(state, header, &self.executor, method, call_data) + prove_execution(state, header, &self.executor, method, call_data).map(|(r, p)| { + (r, StorageProof::merge(vec![p, code_proof])) + }) } fn header_proof(&self, id: &BlockId) -> sp_blockchain::Result<(Block::Header, StorageProof)> { diff --git a/client/src/genesis.rs b/client/src/genesis.rs index 0eecc6cdae8..6e55b5a42d3 100644 --- a/client/src/genesis.rs +++ b/client/src/genesis.rs @@ -89,6 +89,8 @@ mod tests { }; let hash = header.hash(); let mut overlay = OverlayedChanges::default(); + let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); + let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); StateMachine::new( backend, @@ -98,6 +100,7 @@ mod tests { "Core_initialize_block", &header.encode(), Default::default(), + &runtime_code, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -111,6 +114,7 @@ mod tests { "BlockBuilder_apply_extrinsic", &tx.encode(), Default::default(), + &runtime_code, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -124,6 +128,7 @@ mod tests { "BlockBuilder_finalize_block", &[], Default::default(), + &runtime_code, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -161,6 +166,8 @@ mod tests { let backend = InMemoryBackend::from(storage); let (b1data, _b1hash) = block1(genesis_hash, &backend); + let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); + let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); let mut overlay = OverlayedChanges::default(); let _ = StateMachine::new( @@ -171,6 +178,7 @@ mod tests { "Core_execute_block", &b1data, Default::default(), + &runtime_code, ).execute( ExecutionStrategy::NativeElseWasm, ).unwrap(); @@ -189,6 +197,8 @@ mod tests { let backend = InMemoryBackend::from(storage); let (b1data, _b1hash) = block1(genesis_hash, &backend); + let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); + let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); let mut overlay = OverlayedChanges::default(); let _ = StateMachine::new( @@ -199,6 +209,7 @@ mod tests { "Core_execute_block", &b1data, Default::default(), + &runtime_code, ).execute( ExecutionStrategy::AlwaysWasm, ).unwrap(); @@ -217,6 +228,8 @@ mod tests { let backend = InMemoryBackend::from(storage); let (b1data, _b1hash) = block1(genesis_hash, &backend); + let backend_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&backend); + let runtime_code = backend_runtime_code.runtime_code().expect("Code is part of the backend"); let mut overlay = OverlayedChanges::default(); let r = StateMachine::new( @@ -227,6 +240,7 @@ mod tests { "Core_execute_block", &b1data, Default::default(), + &runtime_code, ).execute( ExecutionStrategy::NativeElseWasm, ); diff --git a/client/src/light/backend.rs b/client/src/light/backend.rs index 6b5f9263009..749e24af046 100644 --- a/client/src/light/backend.rs +++ b/client/src/light/backend.rs @@ -172,9 +172,9 @@ impl ClientBackend for Backend> match maybe_val { Some(val) => self.blockchain.storage().insert_aux( &[(&key[..], &val[..])], - ::std::iter::empty(), + std::iter::empty(), )?, - None => self.blockchain.storage().insert_aux(::std::iter::empty(), &[&key[..]])?, + None => self.blockchain.storage().insert_aux(std::iter::empty(), &[&key[..]])?, } } } diff --git a/client/src/light/call_executor.rs b/client/src/light/call_executor.rs index cae5d5a0aa8..2e1a820f7c1 100644 --- a/client/src/light/call_executor.rs +++ b/client/src/light/call_executor.rs @@ -29,7 +29,6 @@ use sp_externalities::Extensions; use sp_state_machine::{ self, Backend as StateBackend, OverlayedChanges, ExecutionStrategy, create_proof_check_backend, execution_proof_check_on_trie_backend, ExecutionManager, StorageProof, - merge_storage_proofs, }; use hash_db::Hasher; @@ -206,7 +205,7 @@ pub fn prove_execution( method, call_data, )?; - let total_proof = merge_storage_proofs(vec![init_proof, exec_proof]); + let total_proof = StorageProof::merge(vec![init_proof, exec_proof]); Ok((result, total_proof)) } @@ -259,12 +258,18 @@ fn check_execution_proof_with_make_header( &trie_backend, &mut changes, executor, "Core_initialize_block", &next_header.encode(), + &runtime_code, )?; // execute method @@ -274,7 +279,9 @@ fn check_execution_proof_with_make_header> LightDataChecker { H::Out: Ord + codec::Codec, { // all the checks are sharing the same storage - let storage = create_proof_check_backend_storage(remote_roots_proof); + let storage = remote_roots_proof.into_memory_db(); // remote_roots.keys() are sorted => we can use this to group changes tries roots // that are belongs to the same CHT @@ -187,7 +187,8 @@ impl> LightDataChecker { local_cht_root, block, remote_changes_trie_root, - &proving_backend)?; + &proving_backend, + )?; // and return the storage to use in following checks storage = proving_backend.into_storage(); @@ -270,7 +271,7 @@ impl FetchChecker for LightDataChecker body: Vec ) -> ClientResult> { // TODO: #2621 - let extrinsics_root = HashFor::::ordered_trie_root( + let extrinsics_root = HashFor::::ordered_trie_root( body.iter().map(Encode::encode).collect(), ); if *request.header.extrinsics_root() == extrinsics_root { @@ -294,7 +295,7 @@ struct RootsStorage<'a, Number: AtLeast32Bit, Hash: 'a> { impl<'a, H, Number, Hash> ChangesTrieRootsStorage for RootsStorage<'a, Number, Hash> where H: Hasher, - Number: ::std::fmt::Display + ::std::hash::Hash + Clone + AtLeast32Bit + Encode + Decode + Send + Sync + 'static, + Number: std::fmt::Display + std::hash::Hash + Clone + AtLeast32Bit + Encode + Decode + Send + Sync + 'static, Hash: 'a + Send + Sync + Clone + AsRef<[u8]>, { fn build_anchor( diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index cfcaa6f64ac..90a4ad1d34d 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -18,7 +18,7 @@ use criterion::{Criterion, criterion_group, criterion_main, black_box}; use frame_system as system; use frame_support::{decl_module, decl_event, impl_outer_origin, impl_outer_event, weights::Weight}; use sp_core::H256; -use sp_runtime::{Perbill, PerThing, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; +use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup}, testing::Header}; mod module { use super::*; diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index bd9e61b51ab..5f9928d78d0 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -1925,6 +1925,7 @@ mod tests { fn call_in_wasm( &self, _: &[u8], + _: Option>, _: &str, _: &[u8], _: &mut dyn sp_externalities::Externalities, diff --git a/primitives/api/test/Cargo.toml b/primitives/api/test/Cargo.toml index 6d2207c178a..3b41e28cf3b 100644 --- a/primitives/api/test/Cargo.toml +++ b/primitives/api/test/Cargo.toml @@ -24,6 +24,7 @@ rustversion = "1.0.0" [dev-dependencies] criterion = "0.3.0" substrate-test-runtime-client = { version = "2.0.0-dev", path = "../../../test-utils/runtime/client" } +sp-core = { version = "2.0.0-alpha.1", path = "../../core" } [[bench]] name = "bench" diff --git a/primitives/api/test/tests/runtime_calls.rs b/primitives/api/test/tests/runtime_calls.rs index 18beaad9170..7859202845e 100644 --- a/primitives/api/test/tests/runtime_calls.rs +++ b/primitives/api/test/tests/runtime_calls.rs @@ -164,6 +164,12 @@ fn record_proof_works() { let block_id = BlockId::Number(client.chain_info().best_number); let storage_root = longest_chain.best_chain().unwrap().state_root().clone(); + let runtime_code = sp_core::traits::RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(client.code_at(&block_id).unwrap().into()), + hash: vec![1], + heap_pages: None, + }; + let transaction = Transfer { amount: 1000, nonce: 0, @@ -192,5 +198,6 @@ fn record_proof_works() { &executor, "Core_execute_block", &block.encode(), + &runtime_code, ).expect("Executes block while using the proof backend"); } diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index e86a0234bf5..83cbebd7d6a 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -19,9 +19,7 @@ use crate::{crypto::KeyTypeId, ed25519, sr25519}; use std::{ - fmt::{Debug, Display}, - panic::UnwindSafe, - sync::Arc, + fmt::{Debug, Display}, panic::UnwindSafe, sync::Arc, borrow::Cow, }; pub use sp_externalities::{Externalities, ExternalitiesExt}; @@ -97,6 +95,7 @@ pub trait CodeExecutor: Sized + Send + Sync + CallInWasm + Clone + 'static { >( &self, ext: &mut dyn Externalities, + runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, @@ -104,15 +103,98 @@ pub trait CodeExecutor: Sized + Send + Sync + CallInWasm + Clone + 'static { ) -> (Result, Self::Error>, bool); } +/// Something that can fetch the runtime `:code`. +pub trait FetchRuntimeCode { + /// Fetch the runtime `:code`. + /// + /// If the `:code` could not be found/not available, `None` should be returned. + fn fetch_runtime_code<'a>(&'a self) -> Option>; +} + +/// Wrapper to use a `u8` slice or `Vec` as [`FetchRuntimeCode`]. +pub struct WrappedRuntimeCode<'a>(pub std::borrow::Cow<'a, [u8]>); + +impl<'a> FetchRuntimeCode for WrappedRuntimeCode<'a> { + fn fetch_runtime_code<'b>(&'b self) -> Option> { + Some(self.0.as_ref().into()) + } +} + +/// Type that implements [`FetchRuntimeCode`] and always returns `None`. +pub struct NoneFetchRuntimeCode; + +impl FetchRuntimeCode for NoneFetchRuntimeCode { + fn fetch_runtime_code<'a>(&'a self) -> Option> { + None + } +} + +/// The Wasm code of a Substrate runtime. +#[derive(Clone)] +pub struct RuntimeCode<'a> { + /// The code fetcher that can be used to lazily fetch the code. + pub code_fetcher: &'a dyn FetchRuntimeCode, + /// The optional heap pages this `code` should be executed with. + /// + /// If `None` are given, the default value of the executor will be used. + pub heap_pages: Option, + /// The SCALE encoded hash of `code`. + /// + /// The hashing algorithm isn't that important, as long as all runtime + /// code instances use the same. + pub hash: Vec, +} + +impl<'a> PartialEq for RuntimeCode<'a> { + fn eq(&self, other: &Self) -> bool { + self.hash == other.hash + } +} + +impl<'a> RuntimeCode<'a> { + /// Create an empty instance. + /// + /// This is only useful for tests that don't want to execute any code. + pub fn empty() -> Self { + Self { + code_fetcher: &NoneFetchRuntimeCode, + hash: Vec::new(), + heap_pages: None, + } + } +} + +impl<'a> FetchRuntimeCode for RuntimeCode<'a> { + fn fetch_runtime_code<'b>(&'b self) -> Option> { + self.code_fetcher.fetch_runtime_code() + } +} + +/// Could not find the `:code` in the externalities while initializing the [`RuntimeCode`]. +#[derive(Debug)] +pub struct CodeNotFound; + +impl std::fmt::Display for CodeNotFound { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "the storage entry `:code` doesn't have any code") + } +} + /// Something that can call a method in a WASM blob. pub trait CallInWasm: Send + Sync { /// Call the given `method` in the given `wasm_blob` using `call_data` (SCALE encoded arguments) /// to decode the arguments for the method. /// /// Returns the SCALE encoded return value of the method. + /// + /// # Note + /// + /// If `code_hash` is `Some(_)` the `wasm_code` module and instance will be cached internally, + /// otherwise it is thrown away after the call. fn call_in_wasm( &self, - wasm_blob: &[u8], + wasm_code: &[u8], + code_hash: Option>, method: &str, call_data: &[u8], ext: &mut dyn Externalities, diff --git a/primitives/externalities/src/lib.rs b/primitives/externalities/src/lib.rs index fa0f9e4454d..6fbd239b89c 100644 --- a/primitives/externalities/src/lib.rs +++ b/primitives/externalities/src/lib.rs @@ -52,36 +52,6 @@ pub trait Externalities: ExtensionStore { key: &[u8], ) -> Option>; - /// Read original runtime storage, ignoring any overlayed changes. - fn original_storage(&self, key: &[u8]) -> Option>; - - /// Read original runtime child storage, ignoring any overlayed changes. - /// - /// Returns an `Option` that holds the SCALE encoded hash. - fn original_child_storage( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option>; - - /// Get original storage value hash, ignoring any overlayed changes. - /// This may be optimized for large values. - /// - /// Returns an `Option` that holds the SCALE encoded hash. - fn original_storage_hash(&self, key: &[u8]) -> Option>; - - /// Get original child storage value hash, ignoring any overlayed changes. - /// This may be optimized for large values. - /// - /// Returns an `Option` that holds the SCALE encoded hash. - fn original_child_storage_hash( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option>; - /// Read child runtime storage. /// /// Returns an `Option` that holds the SCALE encoded hash. diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 4b520a240a9..2702be02071 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -366,7 +366,7 @@ pub trait Misc { self.extension::() .expect("No `CallInWasmExt` associated for the current context!") - .call_in_wasm(wasm, "Core_version", &[], &mut ext) + .call_in_wasm(wasm, None, "Core_version", &[], &mut ext) .ok() } } diff --git a/primitives/runtime-interface/test/src/lib.rs b/primitives/runtime-interface/test/src/lib.rs index 014a46e9d74..43eb9a80a68 100644 --- a/primitives/runtime-interface/test/src/lib.rs +++ b/primitives/runtime-interface/test/src/lib.rs @@ -40,6 +40,7 @@ fn call_wasm_method(method: &str) -> TestExternalities { ); executor.call_in_wasm( &WASM_BINARY[..], + None, method, &[], &mut ext_ext, @@ -88,7 +89,7 @@ fn test_return_input_public_key() { #[test] #[should_panic( - expected = "\"Instantiation: Export ext_test_api_return_input_version_1 not found\"" + expected = "Instantiation: Export ext_test_api_return_input_version_1 not found" )] fn host_function_not_found() { call_wasm_method::<()>("test_return_data"); diff --git a/primitives/runtime/src/generic/block.rs b/primitives/runtime/src/generic/block.rs index a46396dce08..fb07d6c215d 100644 --- a/primitives/runtime/src/generic/block.rs +++ b/primitives/runtime/src/generic/block.rs @@ -25,7 +25,10 @@ use serde::{Deserialize, Serialize}; use sp_std::prelude::*; use sp_core::RuntimeDebug; use crate::codec::{Codec, Encode, Decode}; -use crate::traits::{self, Member, Block as BlockT, Header as HeaderT, MaybeSerialize, MaybeMallocSizeOf}; +use crate::traits::{ + self, Member, Block as BlockT, Header as HeaderT, MaybeSerialize, MaybeMallocSizeOf, + NumberFor, +}; use crate::Justification; /// Something to identify a block. @@ -35,9 +38,9 @@ use crate::Justification; #[cfg_attr(feature = "std", serde(deny_unknown_fields))] pub enum BlockId { /// Identify by block header hash. - Hash(<::Header as HeaderT>::Hash), + Hash(Block::Hash), /// Identify by block number. - Number(<::Header as HeaderT>::Number), + Number(NumberFor), } impl BlockId { @@ -47,7 +50,7 @@ impl BlockId { } /// Create a block ID from a number. - pub fn number(number: ::Number) -> Self { + pub fn number(number: NumberFor) -> Self { BlockId::Number(number) } } diff --git a/primitives/state-machine/src/backend.rs b/primitives/state-machine/src/backend.rs index ca6612a5e92..4fb59556e3f 100644 --- a/primitives/state-machine/src/backend.rs +++ b/primitives/state-machine/src/backend.rs @@ -18,9 +18,9 @@ use log::warn; use hash_db::Hasher; -use codec::Encode; +use codec::{Decode, Encode}; -use sp_core::storage::{ChildInfo, OwnedChildInfo}; +use sp_core::{traits::RuntimeCode, storage::{ChildInfo, OwnedChildInfo, well_known_keys}}; use sp_trie::{TrieMut, MemoryDB, trie_types::TrieDBMut}; use crate::{ @@ -359,3 +359,42 @@ pub(crate) fn insert_into_memory_db(mdb: &mut MemoryDB, input: I) -> Op Some(root) } + +/// Wrapper to create a [`RuntimeCode`] from a type that implements [`Backend`]. +pub struct BackendRuntimeCode<'a, B, H> { + backend: &'a B, + _marker: std::marker::PhantomData, +} + +impl<'a, B: Backend, H: Hasher> sp_core::traits::FetchRuntimeCode for + BackendRuntimeCode<'a, B, H> +{ + fn fetch_runtime_code<'b>(&'b self) -> Option> { + self.backend.storage(well_known_keys::CODE).ok().flatten().map(Into::into) + } +} + +impl<'a, B: Backend, H: Hasher> BackendRuntimeCode<'a, B, H> where H::Out: Encode { + /// Create a new instance. + pub fn new(backend: &'a B) -> Self { + Self { + backend, + _marker: std::marker::PhantomData, + } + } + + /// Return the [`RuntimeCode`] build from the wrapped `backend`. + pub fn runtime_code(&self) -> Result { + let hash = self.backend.storage_hash(well_known_keys::CODE) + .ok() + .flatten() + .ok_or("`:code` hash not found")? + .encode(); + let heap_pages = self.backend.storage(well_known_keys::HEAP_PAGES) + .ok() + .flatten() + .and_then(|d| Decode::decode(&mut &d[..]).ok()); + + Ok(RuntimeCode { code_fetcher: self, hash, heap_pages }) + } +} diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 7252ae10e90..819244050ba 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -119,14 +119,6 @@ impl Externalities for BasicExternalities { self.storage(key).map(|v| Blake2Hasher::hash(&v).encode()) } - fn original_storage(&self, key: &[u8]) -> Option { - self.storage(key) - } - - fn original_storage_hash(&self, key: &[u8]) -> Option> { - self.storage_hash(key) - } - fn child_storage( &self, storage_key: ChildStorageKey, @@ -145,24 +137,6 @@ impl Externalities for BasicExternalities { self.child_storage(storage_key, child_info, key).map(|v| Blake2Hasher::hash(&v).encode()) } - fn original_child_storage_hash( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option> { - self.child_storage_hash(storage_key, child_info, key) - } - - fn original_child_storage( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option { - Externalities::child_storage(self, storage_key, child_info, key) - } - fn next_storage_key(&self, key: &[u8]) -> Option { let range = (Bound::Excluded(key), Bound::Unbounded); self.inner.top.range::<[u8], _>(range).next().map(|(k, _)| k).cloned() diff --git a/primitives/state-machine/src/ext.rs b/primitives/state-machine/src/ext.rs index 53156cb1861..bbb25355a8c 100644 --- a/primitives/state-machine/src/ext.rs +++ b/primitives/state-machine/src/ext.rs @@ -179,30 +179,6 @@ where result.map(|r| r.encode()) } - fn original_storage(&self, key: &[u8]) -> Option { - let _guard = sp_panic_handler::AbortGuard::force_abort(); - let result = self.backend.storage(key).expect(EXT_NOT_ALLOWED_TO_FAIL); - - trace!(target: "state-trace", "{:04x}: GetOriginal {}={:?}", - self.id, - HexDisplay::from(&key), - result.as_ref().map(HexDisplay::from) - ); - result - } - - fn original_storage_hash(&self, key: &[u8]) -> Option> { - let _guard = sp_panic_handler::AbortGuard::force_abort(); - let result = self.backend.storage_hash(key).expect(EXT_NOT_ALLOWED_TO_FAIL); - - trace!(target: "state-trace", "{:04x}: GetOriginalHash {}={:?}", - self.id, - HexDisplay::from(&key), - result, - ); - result.map(|r| r.encode()) - } - fn child_storage( &self, storage_key: ChildStorageKey, @@ -253,47 +229,6 @@ where result.map(|r| r.encode()) } - fn original_child_storage( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option { - let _guard = sp_panic_handler::AbortGuard::force_abort(); - let result = self.backend - .child_storage(storage_key.as_ref(), child_info, key) - .expect(EXT_NOT_ALLOWED_TO_FAIL); - - trace!(target: "state-trace", "{:04x}: ChildOriginal({}) {}={:?}", - self.id, - HexDisplay::from(&storage_key.as_ref()), - HexDisplay::from(&key), - result.as_ref().map(HexDisplay::from), - ); - - result - } - - fn original_child_storage_hash( - &self, - storage_key: ChildStorageKey, - child_info: ChildInfo, - key: &[u8], - ) -> Option> { - let _guard = sp_panic_handler::AbortGuard::force_abort(); - let result = self.backend - .child_storage_hash(storage_key.as_ref(), child_info, key) - .expect(EXT_NOT_ALLOWED_TO_FAIL); - - trace!(target: "state-trace", "{}: ChildHashOriginal({}) {}={:?}", - self.id, - HexDisplay::from(&storage_key.as_ref()), - HexDisplay::from(&key), - result, - ); - result.map(|r| r.encode()) - } - fn exists_storage(&self, key: &[u8]) -> bool { let _guard = sp_panic_handler::AbortGuard::force_abort(); let result = match self.overlay.storage(key) { @@ -820,21 +755,18 @@ mod tests { let ext = TestExt::new(&mut overlay, &mut cache, &backend, None, None); assert_eq!(ext.child_storage(child(), CHILD_INFO_1, &[10]), Some(vec![10])); - assert_eq!(ext.original_child_storage(child(), CHILD_INFO_1, &[10]), Some(vec![10])); assert_eq!( ext.child_storage_hash(child(), CHILD_INFO_1, &[10]), Some(Blake2Hasher::hash(&[10]).as_ref().to_vec()), ); assert_eq!(ext.child_storage(child(), CHILD_INFO_1, &[20]), None); - assert_eq!(ext.original_child_storage(child(), CHILD_INFO_1, &[20]), Some(vec![20])); assert_eq!( ext.child_storage_hash(child(), CHILD_INFO_1, &[20]), None, ); assert_eq!(ext.child_storage(child(), CHILD_INFO_1, &[30]), Some(vec![31])); - assert_eq!(ext.original_child_storage(child(), CHILD_INFO_1, &[30]), Some(vec![40])); assert_eq!( ext.child_storage_hash(child(), CHILD_INFO_1, &[30]), Some(Blake2Hasher::hash(&[31]).as_ref().to_vec()), diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index ff41237c831..4d80ee37c98 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -23,8 +23,8 @@ use log::{warn, trace}; use hash_db::Hasher; use codec::{Decode, Encode, Codec}; use sp_core::{ - storage::ChildInfo, NativeOrEncoded, NeverNativeValue, - traits::{CodeExecutor, CallInWasmExt}, hexdisplay::HexDisplay, + storage::ChildInfo, NativeOrEncoded, NeverNativeValue, hexdisplay::HexDisplay, + traits::{CodeExecutor, CallInWasmExt, RuntimeCode}, }; use overlayed_changes::OverlayedChangeSet; use sp_externalities::Extensions; @@ -42,7 +42,7 @@ mod trie_backend; mod trie_backend_essence; mod stats; -pub use sp_trie::{trie_types::{Layout, TrieDBMut}, TrieMut, DBValue, MemoryDB}; +pub use sp_trie::{trie_types::{Layout, TrieDBMut}, StorageProof, TrieMut, DBValue, MemoryDB}; pub use testing::TestExternalities; pub use basic::BasicExternalities; pub use ext::Ext; @@ -67,8 +67,7 @@ pub use overlayed_changes::{ StorageCollection, ChildStorageCollection, }; pub use proving_backend::{ - create_proof_check_backend, create_proof_check_backend_storage, merge_storage_proofs, - ProofRecorder, ProvingBackend, ProvingBackendRecorder, StorageProof, + create_proof_check_backend, ProofRecorder, ProvingBackend, ProvingBackendRecorder, }; pub use trie_backend_essence::{TrieBackendStorage, Storage}; pub use trie_backend::TrieBackend; @@ -191,6 +190,7 @@ pub struct StateMachine<'a, B, H, N, Exec> changes_trie_state: Option>, _marker: PhantomData<(H, N)>, storage_transaction_cache: Option<&'a mut StorageTransactionCache>, + runtime_code: &'a RuntimeCode<'a>, } impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where @@ -209,6 +209,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where method: &'a str, call_data: &'a [u8], mut extensions: Extensions, + runtime_code: &'a RuntimeCode, ) -> Self { extensions.register(CallInWasmExt::new(exec.clone())); @@ -222,6 +223,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where changes_trie_state, _marker: PhantomData, storage_transaction_cache: None, + runtime_code, } } @@ -292,6 +294,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where let (result, was_native) = self.exec.call( &mut ext, + self.runtime_code, self.method, self.call_data, use_native, @@ -436,6 +439,7 @@ pub fn prove_execution( exec: &Exec, method: &str, call_data: &[u8], + runtime_code: &RuntimeCode, ) -> Result<(Vec, StorageProof), Box> where B: Backend, @@ -446,7 +450,14 @@ where { let trie_backend = backend.as_trie_backend() .ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box)?; - prove_execution_on_trie_backend::<_, _, N, _>(trie_backend, overlay, exec, method, call_data) + prove_execution_on_trie_backend::<_, _, N, _>( + trie_backend, + overlay, + exec, + method, + call_data, + runtime_code, + ) } /// Prove execution using the given trie backend, overlayed changes, and call executor. @@ -464,6 +475,7 @@ pub fn prove_execution_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], + runtime_code: &RuntimeCode, ) -> Result<(Vec, StorageProof), Box> where S: trie_backend_essence::TrieBackendStorage, @@ -474,7 +486,14 @@ where { let proving_backend = proving_backend::ProvingBackend::new(trie_backend); let mut sm = StateMachine::<_, H, N, Exec>::new( - &proving_backend, None, overlay, exec, method, call_data, Extensions::default(), + &proving_backend, + None, + overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, ); let result = sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -493,6 +512,7 @@ pub fn execution_proof_check( exec: &Exec, method: &str, call_data: &[u8], + runtime_code: &RuntimeCode, ) -> Result, Box> where H: Hasher, @@ -501,7 +521,14 @@ where N: crate::changes_trie::BlockNumber, { let trie_backend = create_proof_check_backend::(root.into(), proof)?; - execution_proof_check_on_trie_backend::<_, N, _>(&trie_backend, overlay, exec, method, call_data) + execution_proof_check_on_trie_backend::<_, N, _>( + &trie_backend, + overlay, + exec, + method, + call_data, + runtime_code, + ) } /// Check execution proof on proving backend, generated by `prove_execution` call. @@ -511,6 +538,7 @@ pub fn execution_proof_check_on_trie_backend( exec: &Exec, method: &str, call_data: &[u8], + runtime_code: &RuntimeCode, ) -> Result, Box> where H: Hasher, @@ -519,7 +547,14 @@ where N: crate::changes_trie::BlockNumber, { let mut sm = StateMachine::<_, H, N, Exec>::new( - trie_backend, None, overlay, exec, method, call_data, Extensions::default(), + trie_backend, + None, + overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, ); sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( @@ -692,7 +727,7 @@ mod tests { use super::*; use super::ext::Ext; use super::changes_trie::Configuration as ChangesTrieConfig; - use sp_core::{map, traits::Externalities, storage::ChildStorageKey}; + use sp_core::{map, traits::{Externalities, RuntimeCode}, storage::ChildStorageKey}; use sp_runtime::traits::BlakeTwo256; #[derive(Clone)] @@ -714,6 +749,7 @@ mod tests { >( &self, ext: &mut dyn Externalities, + _: &RuntimeCode, _method: &str, _data: &[u8], use_native: bool, @@ -755,6 +791,7 @@ mod tests { fn call_in_wasm( &self, _: &[u8], + _: Option>, _: &str, _: &[u8], _: &mut dyn Externalities, @@ -767,6 +804,7 @@ mod tests { fn execute_works() { let backend = trie_backend::tests::test_trie(); let mut overlayed_changes = Default::default(); + let wasm_code = RuntimeCode::empty(); let mut state_machine = StateMachine::new( &backend, @@ -781,6 +819,7 @@ mod tests { "test", &[], Default::default(), + &wasm_code, ); assert_eq!( @@ -794,6 +833,7 @@ mod tests { fn execute_works_with_native_else_wasm() { let backend = trie_backend::tests::test_trie(); let mut overlayed_changes = Default::default(); + let wasm_code = RuntimeCode::empty(); let mut state_machine = StateMachine::new( &backend, @@ -808,6 +848,7 @@ mod tests { "test", &[], Default::default(), + &wasm_code, ); assert_eq!(state_machine.execute(ExecutionStrategy::NativeElseWasm).unwrap(), vec![66]); @@ -818,6 +859,7 @@ mod tests { let mut consensus_failed = false; let backend = trie_backend::tests::test_trie(); let mut overlayed_changes = Default::default(); + let wasm_code = RuntimeCode::empty(); let mut state_machine = StateMachine::new( &backend, @@ -832,6 +874,7 @@ mod tests { "test", &[], Default::default(), + &wasm_code, ); assert!( @@ -864,6 +907,7 @@ mod tests { &executor, "test", &[], + &RuntimeCode::empty(), ).unwrap(); // check proof locally @@ -874,6 +918,7 @@ mod tests { &executor, "test", &[], + &RuntimeCode::empty(), ).unwrap(); // check that both results are correct diff --git a/primitives/state-machine/src/proving_backend.rs b/primitives/state-machine/src/proving_backend.rs index 7b6e8e0e698..119fb59a723 100644 --- a/primitives/state-machine/src/proving_backend.rs +++ b/primitives/state-machine/src/proving_backend.rs @@ -18,19 +18,19 @@ use std::sync::Arc; use parking_lot::RwLock; -use codec::{Decode, Encode, Codec}; +use codec::{Decode, Codec}; use log::debug; use hash_db::{Hasher, HashDB, EMPTY_PREFIX, Prefix}; use sp_trie::{ MemoryDB, default_child_trie_root, read_trie_value_with, read_child_trie_value_with, - record_all_keys + record_all_keys, StorageProof, }; pub use sp_trie::Recorder; pub use sp_trie::trie_types::{Layout, TrieError}; use crate::trie_backend::TrieBackend; use crate::trie_backend_essence::{Ephemeral, TrieBackendEssence, TrieBackendStorage}; use crate::{Error, ExecutionError, Backend}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use crate::DBValue; use sp_core::storage::ChildInfo; @@ -40,82 +40,6 @@ pub struct ProvingBackendRecorder<'a, S: 'a + TrieBackendStorage, H: 'a + Has pub(crate) proof_recorder: &'a mut Recorder, } -/// A proof that some set of key-value pairs are included in the storage trie. The proof contains -/// the storage values so that the partial storage backend can be reconstructed by a verifier that -/// does not already have access to the key-value pairs. -/// -/// The proof consists of the set of serialized nodes in the storage trie accessed when looking up -/// the keys covered by the proof. Verifying the proof requires constructing the partial trie from -/// the serialized nodes and performing the key lookups. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] -pub struct StorageProof { - trie_nodes: Vec>, -} - -impl StorageProof { - /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. - pub fn new(trie_nodes: Vec>) -> Self { - StorageProof { trie_nodes } - } - - /// Returns a new empty proof. - /// - /// An empty proof is capable of only proving trivial statements (ie. that an empty set of - /// key-value pairs exist in storage). - pub fn empty() -> Self { - StorageProof { - trie_nodes: Vec::new(), - } - } - - /// Returns whether this is an empty proof. - pub fn is_empty(&self) -> bool { - self.trie_nodes.is_empty() - } - - /// Create an iterator over trie nodes constructed from the proof. The nodes are not guaranteed - /// to be traversed in any particular order. - pub fn iter_nodes(self) -> StorageProofNodeIterator { - StorageProofNodeIterator::new(self) - } -} - -/// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to -/// be traversed in any particular order. -pub struct StorageProofNodeIterator { - inner: > as IntoIterator>::IntoIter, -} - -impl StorageProofNodeIterator { - fn new(proof: StorageProof) -> Self { - StorageProofNodeIterator { - inner: proof.trie_nodes.into_iter(), - } - } -} - -impl Iterator for StorageProofNodeIterator { - type Item = Vec; - - fn next(&mut self) -> Option { - self.inner.next() - } -} - -/// Merges multiple storage proofs covering potentially different sets of keys into one proof -/// covering all keys. The merged proof output may be smaller than the aggregate size of the input -/// proofs due to deduplication of trie nodes. -pub fn merge_storage_proofs(proofs: I) -> StorageProof - where I: IntoIterator -{ - let trie_nodes = proofs.into_iter() - .flat_map(|proof| proof.iter_nodes()) - .collect::>() - .into_iter() - .collect(); - StorageProof { trie_nodes } -} - impl<'a, S, H> ProvingBackendRecorder<'a, S, H> where S: TrieBackendStorage, @@ -222,7 +146,7 @@ impl<'a, S: 'a + TrieBackendStorage, H: 'a + Hasher> ProvingBackend<'a, S, H> let root = essence.root().clone(); let recorder = ProofRecorderBackend { backend: essence.backend_storage(), - proof_recorder: proof_recorder, + proof_recorder, }; ProvingBackend(TrieBackend::new(recorder, root)) } @@ -370,7 +294,7 @@ where H: Hasher, H::Out: Codec, { - let db = create_proof_check_backend_storage(proof); + let db = proof.into_memory_db(); if db.contains(&root, EMPTY_PREFIX) { Ok(TrieBackend::new(db, root)) @@ -379,20 +303,6 @@ where } } -/// Create in-memory storage of proof check backend. -pub fn create_proof_check_backend_storage( - proof: StorageProof, -) -> MemoryDB -where - H: Hasher, -{ - let mut db = MemoryDB::default(); - for item in proof.iter_nodes() { - db.insert(EMPTY_PREFIX, &item); - } - db -} - #[cfg(test)] mod tests { use crate::InMemoryBackend; diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index f6131c8ed5e..80570a9792b 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -21,6 +21,7 @@ mod error; mod node_header; mod node_codec; +mod storage_proof; mod trie_stream; use sp_std::boxed::Box; @@ -35,6 +36,7 @@ pub use error::Error; pub use trie_stream::TrieStream; /// The Substrate format implementation of `NodeCodec`. pub use node_codec::NodeCodec; +pub use storage_proof::StorageProof; /// Various re-exports from the `trie-db` crate. pub use trie_db::{ Trie, TrieMut, DBValue, Recorder, CError, Query, TrieLayout, TrieConfiguration, nibble_ops, TrieDBIterator, diff --git a/primitives/trie/src/storage_proof.rs b/primitives/trie/src/storage_proof.rs new file mode 100644 index 00000000000..254adc2fcb4 --- /dev/null +++ b/primitives/trie/src/storage_proof.rs @@ -0,0 +1,109 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use sp_std::vec::Vec; +use codec::{Encode, Decode}; +use hash_db::{Hasher, HashDB}; + +/// A proof that some set of key-value pairs are included in the storage trie. The proof contains +/// the storage values so that the partial storage backend can be reconstructed by a verifier that +/// does not already have access to the key-value pairs. +/// +/// The proof consists of the set of serialized nodes in the storage trie accessed when looking up +/// the keys covered by the proof. Verifying the proof requires constructing the partial trie from +/// the serialized nodes and performing the key lookups. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct StorageProof { + trie_nodes: Vec>, +} + +impl StorageProof { + /// Constructs a storage proof from a subset of encoded trie nodes in a storage backend. + pub fn new(trie_nodes: Vec>) -> Self { + StorageProof { trie_nodes } + } + + /// Returns a new empty proof. + /// + /// An empty proof is capable of only proving trivial statements (ie. that an empty set of + /// key-value pairs exist in storage). + pub fn empty() -> Self { + StorageProof { + trie_nodes: Vec::new(), + } + } + + /// Returns whether this is an empty proof. + pub fn is_empty(&self) -> bool { + self.trie_nodes.is_empty() + } + + /// Create an iterator over trie nodes constructed from the proof. The nodes are not guaranteed + /// to be traversed in any particular order. + pub fn iter_nodes(self) -> StorageProofNodeIterator { + StorageProofNodeIterator::new(self) + } + + /// Creates a `MemoryDB` from `Self`. + pub fn into_memory_db(self) -> crate::MemoryDB { + self.into() + } + + /// Merges multiple storage proofs covering potentially different sets of keys into one proof + /// covering all keys. The merged proof output may be smaller than the aggregate size of the input + /// proofs due to deduplication of trie nodes. + pub fn merge(proofs: I) -> Self where I: IntoIterator { + let trie_nodes = proofs.into_iter() + .flat_map(|proof| proof.iter_nodes()) + .collect::>() + .into_iter() + .collect(); + + Self { trie_nodes } + } +} + +/// An iterator over trie nodes constructed from a storage proof. The nodes are not guaranteed to +/// be traversed in any particular order. +pub struct StorageProofNodeIterator { + inner: > as IntoIterator>::IntoIter, +} + +impl StorageProofNodeIterator { + fn new(proof: StorageProof) -> Self { + StorageProofNodeIterator { + inner: proof.trie_nodes.into_iter(), + } + } +} + +impl Iterator for StorageProofNodeIterator { + type Item = Vec; + + fn next(&mut self) -> Option { + self.inner.next() + } +} + +impl From for crate::MemoryDB { + fn from(proof: StorageProof) -> Self { + let mut db = crate::MemoryDB::default(); + for item in proof.iter_nodes() { + db.insert(crate::EMPTY_PREFIX, &item); + } + db + } +} diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index 1e29f789dcb..296dd764800 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -342,7 +342,7 @@ mod tests { use sp_io::TestExternalities; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; use crate::{Header, Transfer, WASM_BINARY}; - use sp_core::{NeverNativeValue, map, traits::CodeExecutor}; + use sp_core::{NeverNativeValue, map, traits::{CodeExecutor, RuntimeCode}}; use sc_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; use sp_io::hashing::twox_128; @@ -405,8 +405,15 @@ mod tests { fn block_import_works_wasm() { block_import_works(|b, ext| { let mut ext = ext.ext(); + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(WASM_BINARY.into()), + hash: Vec::new(), + heap_pages: None, + }; + executor().call:: _>( &mut ext, + &runtime_code, "Core_execute_block", &b.encode(), false, @@ -498,8 +505,15 @@ mod tests { fn block_import_with_transaction_works_wasm() { block_import_with_transaction_works(|b, ext| { let mut ext = ext.ext(); + let runtime_code = RuntimeCode { + code_fetcher: &sp_core::traits::WrappedRuntimeCode(WASM_BINARY.into()), + hash: Vec::new(), + heap_pages: None, + }; + executor().call:: _>( &mut ext, + &runtime_code, "Core_execute_block", &b.encode(), false, diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 93c62c3f965..89143ee9fe0 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -16,5 +16,6 @@ sc-client = { version = "0.8.0-alpha.2", path = "../../../client" } sc-client-db = { version = "0.8.0-alpha.2", path = "../../../client/db" } sc-executor = { version = "0.8.0-alpha.2", path = "../../../client/executor" } sp-runtime = { version = "2.0.0-alpha.2", path = "../../../primitives/runtime" } +sp-state-machine = { version = "0.8.0-alpha.2", path = "../../../primitives/state-machine" } structopt = "0.3.8" codec = { version = "1.2.0", package = "parity-scale-codec" } diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 899419e5de5..02c530abc12 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -121,6 +121,7 @@ impl BenchmarkCmd { self.repeat, ).encode(), Default::default(), + &sp_state_machine::backend::BackendRuntimeCode::new(&state).runtime_code()?, ) .execute(strategy.into()) .map_err(|e| format!("Error executing runtime benchmark: {:?}", e))?; -- GitLab From a184db4ed958a683efdc13c54a143b5c1607a045 Mon Sep 17 00:00:00 2001 From: Ashley Date: Tue, 10 Mar 2020 11:14:20 +0100 Subject: [PATCH 012/220] Use libp2p's implementation of a wasm websocket transport (#5089) * Update to libp2p 0.16.2 * Use libp2ps implementation of a wasm websocket transport * Remove explicit Configuration type in node-cli Co-authored-by: Pierre Krieger --- Cargo.lock | 2 +- bin/node/cli/browser-demo/index.html | 3 +- bin/node/cli/browser-demo/ws.js | 148 --------------------------- bin/node/cli/src/browser.rs | 11 +- utils/browser/Cargo.toml | 2 +- utils/browser/src/lib.rs | 12 +-- 6 files changed, 13 insertions(+), 165 deletions(-) delete mode 100644 bin/node/cli/browser-demo/ws.js diff --git a/Cargo.lock b/Cargo.lock index 5f6d9b41d0b..59627e2cd7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7656,7 +7656,7 @@ dependencies = [ "futures-timer 3.0.2", "js-sys", "kvdb-web", - "libp2p", + "libp2p-wasm-ext", "log 0.4.8", "rand 0.6.5", "rand 0.7.3", diff --git a/bin/node/cli/browser-demo/index.html b/bin/node/cli/browser-demo/index.html index f40863c46e7..60acfde39f5 100644 --- a/bin/node/cli/browser-demo/index.html +++ b/bin/node/cli/browser-demo/index.html @@ -6,7 +6,6 @@