From 57febc42588ad5212eecedd331b861dcec67bcdf Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 26 Aug 2020 10:41:15 +0800 Subject: [PATCH 01/34] add offchain worker api to set reserved nodes. --- Cargo.lock | 1 + client/network/src/lib.rs | 4 ++++ client/network/src/service.rs | 7 ++++++- client/offchain/Cargo.toml | 1 + client/offchain/src/api.rs | 24 ++++++++++++++++++++++++ client/peerset/src/lib.rs | 12 ++++++++++++ primitives/core/src/crypto.rs | 8 ++++++++ primitives/core/src/lib.rs | 1 + primitives/core/src/offchain/mod.rs | 14 +++++++++++++- primitives/core/src/offchain/testing.rs | 4 ++++ primitives/io/src/lib.rs | 9 ++++++++- 11 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65f5935a1e900..71b3d2f67b2f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7030,6 +7030,7 @@ dependencies = [ "sc-client-db", "sc-keystore", "sc-network", + "sc-peerset", "sc-transaction-pool", "sp-api", "sp-core", diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index e01b260263566..1d20b90c12e2c 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -272,6 +272,7 @@ pub use libp2p::{Multiaddr, PeerId}; pub use libp2p::multiaddr; pub use sc_peerset::ReputationChange; +use sc_peerset::PeersetHandle; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// The maximum allowed number of established connections per peer. @@ -296,6 +297,9 @@ pub trait NetworkStateInfo { /// Returns the local Peer ID. fn local_peer_id(&self) -> PeerId; + + /// Returns the peerset + fn peerset(&self) -> PeersetHandle; } /// Overview status of the network. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index c9213d4dde286..44ffc4754c2f6 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -20,7 +20,7 @@ //! //! There are two main structs in this module: [`NetworkWorker`] and [`NetworkService`]. //! The [`NetworkWorker`] *is* the network and implements the `Future` trait. It must be polled in -//! order fo the network to advance. +//! order for the network to advance. //! The [`NetworkService`] is merely a shared version of the [`NetworkWorker`]. You can obtain an //! `Arc` by calling [`NetworkWorker::service`]. //! @@ -1000,6 +1000,11 @@ impl NetworkStateInfo for NetworkService fn local_peer_id(&self) -> PeerId { self.local_peer_id.clone() } + + /// Returns the peerset. + fn peerset(&self) -> PeersetHandle { + self.peerset.clone() + } } /// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol. diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 9f574ff9ebe46..85be77e9e9957 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -29,6 +29,7 @@ rand = "0.7.2" sp-runtime = { version = "2.0.0-rc6", path = "../../primitives/runtime" } sp-utils = { version = "2.0.0-rc6", path = "../../primitives/utils" } sc-network = { version = "0.8.0-rc6", path = "../network" } +sc-peerset = { version = "2.0.0-rc6", path = "../peerset" } sc-keystore = { version = "2.0.0-rc6", path = "../keystore" } [target.'cfg(not(target_os = "unknown"))'.dependencies] diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 5287ac8251eeb..a86c3826e8771 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -19,17 +19,23 @@ use std::{ sync::Arc, convert::TryFrom, thread::sleep, + collections::HashSet, }; use sp_core::offchain::OffchainStorage; use futures::Future; use log::error; use sc_network::{PeerId, Multiaddr, NetworkStateInfo}; +use sc_network::config::identity::{ + ed25519::PublicKey as Ed25519PublicKey, + PublicKey +}; use codec::{Encode, Decode}; use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; +use sp_core::NodePublicKey; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -180,6 +186,24 @@ impl OffchainExt for Api { ) -> Result { self.http.response_read_body(request_id, buffer, deadline) } + + fn set_reserved_nodes(&mut self, nodes: Vec) { + let mut peer_ids: HashSet = nodes.iter() + .filter_map(|node| { + match node { + NodePublicKey::Ed25519(pubkey) => Ed25519PublicKey::decode(&pubkey.0).ok() + } + }) + .map(|pubkey| PublicKey::Ed25519(pubkey).into_peer_id()) + .collect(); + + peer_ids.remove(&self.network_state.local_peer_id()); + + let peerset = self.network_state.peerset(); + peerset.set_reserved_peers(peer_ids); + // Respect reserved peers from runtime, ignore CLI flags for now. + peerset.set_reserved_only(true); + } } /// Information about the local node's network state. diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index 6f28dd036a3cc..fbd0c92e08907 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -45,6 +45,7 @@ const FORGET_AFTER: Duration = Duration::from_secs(3600); enum Action { AddReservedPeer(PeerId), RemoveReservedPeer(PeerId), + SetReservedPeers(HashSet), SetReservedOnly(bool), ReportPeer(PeerId, ReputationChange), SetPriorityGroup(String, HashSet), @@ -102,6 +103,11 @@ impl PeersetHandle { pub fn set_reserved_only(&self, reserved: bool) { let _ = self.tx.unbounded_send(Action::SetReservedOnly(reserved)); } + + /// Set reserved peers to the new peers. + pub fn set_reserved_peers(&self, peer_ids: HashSet) { + let _ = self.tx.unbounded_send(Action::SetReservedPeers(peer_ids)); + } /// Reports an adjustment to the reputation of the given peer. pub fn report_peer(&self, peer_id: PeerId, score_diff: ReputationChange) { @@ -246,6 +252,10 @@ impl Peerset { fn on_remove_reserved_peer(&mut self, peer_id: PeerId) { self.on_remove_from_priority_group(RESERVED_NODES, peer_id); } + + fn on_set_reserved_peers(&mut self, peer_ids: HashSet) { + self.on_set_priority_group(RESERVED_NODES, peer_ids); + } fn on_set_reserved_only(&mut self, reserved_only: bool) { self.reserved_only = reserved_only; @@ -655,6 +665,8 @@ impl Stream for Peerset { self.on_add_reserved_peer(peer_id), Action::RemoveReservedPeer(peer_id) => self.on_remove_reserved_peer(peer_id), + Action::SetReservedPeers(peer_ids) => + self.on_set_reserved_peers(peer_ids), Action::SetReservedOnly(reserved) => self.on_set_reserved_only(reserved), Action::ReportPeer(peer_id, score_diff) => diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index a8d84eb57cff9..634aef6de0542 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -704,6 +704,14 @@ impl sp_std::str::FromStr for AccountId32 { } } +/// Public key of node which can be used for network connection +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, crate::RuntimeDebug)] +pub enum NodePublicKey { + /// An Ed25519 public key + Ed25519(ed25519::Public), +} + #[cfg(feature = "std")] pub use self::dummy::*; diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 2a40972166e14..1fa8492c6824a 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -80,6 +80,7 @@ pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange}; #[cfg(feature = "full_crypto")] pub use crypto::{DeriveJunction, Pair, Public}; +pub use crypto::NodePublicKey; pub use hash_db::Hasher; #[cfg(feature = "std")] pub use self::hasher::blake2::Blake2Hasher; diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index b2ff3552135ce..dc514bacd929e 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -19,7 +19,7 @@ use codec::{Encode, Decode}; use sp_std::{prelude::{Vec, Box}, convert::TryFrom}; -use crate::RuntimeDebug; +use crate::{RuntimeDebug, NodePublicKey}; use sp_runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum}; pub use crate::crypto::KeyTypeId; @@ -495,6 +495,9 @@ pub trait Externalities: Send { buffer: &mut [u8], deadline: Option ) -> Result; + + /// Set the reserved nodes + fn set_reserved_nodes(&mut self, nodes: Vec); } impl Externalities for Box { @@ -573,6 +576,10 @@ impl Externalities for Box { ) -> Result { (&mut **self).http_response_read_body(request_id, buffer, deadline) } + + fn set_reserved_nodes(&mut self, nodes: Vec) { + (&mut **self).set_reserved_nodes(nodes) + } } /// An `OffchainExternalities` implementation with limited capabilities. @@ -691,6 +698,11 @@ impl Externalities for LimitedExternalities { self.check(Capability::Http, "http_response_read_body"); self.externalities.http_response_read_body(request_id, buffer, deadline) } + + fn set_reserved_nodes(&mut self, nodes: Vec) { + self.check(Capability::NetworkState, "set_reserved_nodes"); + self.externalities.set_reserved_nodes(nodes) + } } #[cfg(feature = "std")] diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index c939c5cfccc14..6858e77c74aad 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -36,6 +36,7 @@ use crate::offchain::{ TransactionPool, OffchainStorage, }; +use crate::NodePublicKey; use parking_lot::RwLock; @@ -375,6 +376,9 @@ impl offchain::Externalities for TestOffchainExt { Err(HttpError::IoError) } } + + fn set_reserved_nodes(&mut self, nodes: Vec) { + } } /// The internal state of the fake transaction pool. diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 59d1c4f37ef27..7bea58dc78f90 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -42,7 +42,7 @@ use sp_core::{ }; use sp_core::{ - crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, + crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, NodePublicKey, offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState, }, @@ -960,6 +960,13 @@ pub trait Offchain { .http_response_read_body(request_id, buffer, deadline) .map(|r| r as u32) } + + /// Set the reserved peers + fn set_reserved_nodes(&mut self, nodes: Vec) { + self.extension::() + .expect("set_reserved_nodes can be called only in the offchain worker context") + .set_reserved_nodes(nodes) + } } /// Wasm only interface that provides functions for calling into the allocator. From 3dc7a45dd9dfbe5a936dc3a7bc8864506237494a Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 26 Aug 2020 13:08:31 +0800 Subject: [PATCH 02/34] new offchain api to get node public key. --- Cargo.lock | 68 ++++++++++++++++++------- Cargo.toml | 1 + client/offchain/src/api.rs | 10 +++- client/peerset/src/lib.rs | 2 +- primitives/core/src/crypto.rs | 4 +- primitives/core/src/offchain/mod.rs | 12 +++++ primitives/core/src/offchain/testing.rs | 6 ++- primitives/io/src/lib.rs | 7 +++ 8 files changed, 87 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71b3d2f67b2f4..8bd6a75433de9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "linregress", "parity-scale-codec", "paste", @@ -1604,7 +1604,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "pallet-indices", "pallet-transaction-payment", @@ -2228,12 +2228,31 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +[[package]] +name = "hex-literal" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +dependencies = [ + "hex-literal-impl", + "proc-macro-hack", +] + [[package]] name = "hex-literal" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" +[[package]] +name = "hex-literal-impl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +dependencies = [ + "proc-macro-hack", +] + [[package]] name = "hex_fmt" version = "0.3.0" @@ -3721,7 +3740,7 @@ dependencies = [ "frame-support", "frame-system", "futures 0.3.5", - "hex-literal", + "hex-literal 0.3.1", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -3903,7 +3922,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal", + "hex-literal 0.3.1", "integer-sqrt", "node-primitives", "pallet-authority-discovery", @@ -4387,7 +4406,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "parity-scale-codec", "serde", @@ -4406,7 +4425,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "pallet-contracts-primitives", "pallet-randomness-collective-flip", @@ -4471,7 +4490,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "pallet-scheduler", "parity-scale-codec", @@ -4490,7 +4509,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "parity-scale-codec", "serde", @@ -4507,7 +4526,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "parity-scale-codec", "serde", @@ -4730,6 +4749,21 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-node-authorization" +version = "2.0.0-rc6" +dependencies = [ + "frame-support", + "frame-system", + "hex-literal 0.2.1", + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-offences" version = "2.0.0-rc6" @@ -5103,7 +5137,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.1", "pallet-balances", "parity-scale-codec", "serde", @@ -6402,7 +6436,7 @@ dependencies = [ "fnv", "futures 0.3.5", "hash-db", - "hex-literal", + "hex-literal 0.3.1", "kvdb", "kvdb-memorydb", "lazy_static", @@ -6700,7 +6734,7 @@ version = "0.8.0-rc6" dependencies = [ "assert_matches", "derive_more", - "hex-literal", + "hex-literal 0.3.1", "lazy_static", "libsecp256k1", "log", @@ -7228,7 +7262,7 @@ dependencies = [ "fdlimit", "futures 0.1.29", "futures 0.3.5", - "hex-literal", + "hex-literal 0.3.1", "log", "parity-scale-codec", "parking_lot 0.10.2", @@ -8040,7 +8074,7 @@ dependencies = [ "hash-db", "hash256-std-hasher", "hex", - "hex-literal", + "hex-literal 0.3.1", "impl-serde", "lazy_static", "libsecp256k1", @@ -8368,7 +8402,7 @@ name = "sp-state-machine" version = "0.8.0-rc6" dependencies = [ "hash-db", - "hex-literal", + "hex-literal 0.3.1", "itertools 0.9.0", "log", "num-traits", @@ -8456,7 +8490,7 @@ version = "2.0.0-rc6" dependencies = [ "criterion", "hash-db", - "hex-literal", + "hex-literal 0.3.1", "memory-db", "parity-scale-codec", "sp-core", @@ -9547,7 +9581,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" dependencies = [ - "rand 0.5.6", + "rand 0.7.3", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7589e8d774124..534b71357cc76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,6 +88,7 @@ members = [ "frame/metadata", "frame/multisig", "frame/nicks", + "frame/node-authorization", "frame/offences", "frame/proxy", "frame/randomness-collective-flip", diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index a86c3826e8771..b3af379e7e82f 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -17,7 +17,7 @@ use std::{ str::FromStr, sync::Arc, - convert::TryFrom, + convert::{TryFrom, TryInto}, thread::sleep, collections::HashSet, }; @@ -35,7 +35,7 @@ use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use sp_core::NodePublicKey; +use sp_core::{NodePublicKey, ed25519}; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -187,6 +187,12 @@ impl OffchainExt for Api { self.http.response_read_body(request_id, buffer, deadline) } + fn get_node_public_key(&mut self) -> NodePublicKey { + let peer_id = self.network_state.local_peer_id(); + + NodePublicKey::Ed25519(ed25519::Public(peer_id.as_bytes().try_into().expect("slice with incorrect length"))) + } + fn set_reserved_nodes(&mut self, nodes: Vec) { let mut peer_ids: HashSet = nodes.iter() .filter_map(|node| { diff --git a/client/peerset/src/lib.rs b/client/peerset/src/lib.rs index fbd0c92e08907..575743afa079c 100644 --- a/client/peerset/src/lib.rs +++ b/client/peerset/src/lib.rs @@ -104,7 +104,7 @@ impl PeersetHandle { let _ = self.tx.unbounded_send(Action::SetReservedOnly(reserved)); } - /// Set reserved peers to the new peers. + /// Set reserved peers to the new set. pub fn set_reserved_peers(&self, peer_ids: HashSet) { let _ = self.tx.unbounded_send(Action::SetReservedPeers(peer_ids)); } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 634aef6de0542..95e1d056c74b4 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -39,7 +39,7 @@ use base58::{FromBase58, ToBase58}; use crate::hexdisplay::HexDisplay; #[doc(hidden)] pub use sp_std::ops::Deref; -use sp_runtime_interface::pass_by::PassByInner; +use sp_runtime_interface::pass_by::{PassByInner, PassByCodec}; /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; /// Trait for accessing reference to `SecretString`. @@ -706,7 +706,7 @@ impl sp_std::str::FromStr for AccountId32 { /// Public key of node which can be used for network connection #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, crate::RuntimeDebug)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, crate::RuntimeDebug, PassByCodec)] pub enum NodePublicKey { /// An Ed25519 public key Ed25519(ed25519::Public), diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index dc514bacd929e..4bb8bfdd18b23 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -496,6 +496,9 @@ pub trait Externalities: Send { deadline: Option ) -> Result; + /// Get public key of the node + fn get_node_public_key(&mut self) -> NodePublicKey; + /// Set the reserved nodes fn set_reserved_nodes(&mut self, nodes: Vec); } @@ -577,6 +580,10 @@ impl Externalities for Box { (&mut **self).http_response_read_body(request_id, buffer, deadline) } + fn get_node_public_key(&mut self) -> NodePublicKey { + (&mut **self).get_node_public_key() + } + fn set_reserved_nodes(&mut self, nodes: Vec) { (&mut **self).set_reserved_nodes(nodes) } @@ -699,6 +706,11 @@ impl Externalities for LimitedExternalities { self.externalities.http_response_read_body(request_id, buffer, deadline) } + fn get_node_public_key(&mut self) -> NodePublicKey { + self.check(Capability::NetworkState, "get_node_public_key"); + self.externalities.get_node_public_key() + } + fn set_reserved_nodes(&mut self, nodes: Vec) { self.check(Capability::NetworkState, "set_reserved_nodes"); self.externalities.set_reserved_nodes(nodes) diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 6858e77c74aad..6a4bc4918faf3 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -36,7 +36,7 @@ use crate::offchain::{ TransactionPool, OffchainStorage, }; -use crate::NodePublicKey; +use crate::{NodePublicKey, ed25519}; use parking_lot::RwLock; @@ -377,6 +377,10 @@ impl offchain::Externalities for TestOffchainExt { } } + fn get_node_public_key(&mut self) -> NodePublicKey { + NodePublicKey::Ed25519(ed25519::Public([0u8; 32])) + } + fn set_reserved_nodes(&mut self, nodes: Vec) { } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 7bea58dc78f90..c8b7f5a3a6b4f 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -961,6 +961,13 @@ pub trait Offchain { .map(|r| r as u32) } + /// Get public key of the local node. + fn get_node_public_key(&mut self) -> NodePublicKey { + self.extension::() + .expect("get_node_public_key can be called only in the offchain worker context") + .get_node_public_key() + } + /// Set the reserved peers fn set_reserved_nodes(&mut self, nodes: Vec) { self.extension::() From 3664999ff484ce42fbd1d870e0119b14e0c8d14c Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 26 Aug 2020 19:56:08 +0800 Subject: [PATCH 03/34] node public key from converter --- client/offchain/src/api.rs | 7 +++---- primitives/core/src/crypto.rs | 13 +++++++++++++ primitives/core/src/offchain/mod.rs | 6 +++--- primitives/core/src/offchain/testing.rs | 6 +++--- primitives/io/src/lib.rs | 2 +- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index b3af379e7e82f..11648a04e41cb 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -35,7 +35,7 @@ use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use sp_core::{NodePublicKey, ed25519}; +use sp_core::NodePublicKey; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -187,10 +187,9 @@ impl OffchainExt for Api { self.http.response_read_body(request_id, buffer, deadline) } - fn get_node_public_key(&mut self) -> NodePublicKey { + fn get_node_public_key(&mut self) -> Result { let peer_id = self.network_state.local_peer_id(); - - NodePublicKey::Ed25519(ed25519::Public(peer_id.as_bytes().try_into().expect("slice with incorrect length"))) + peer_id.as_bytes().try_into() } fn set_reserved_nodes(&mut self, nodes: Vec) { diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 95e1d056c74b4..602d9de6e9f0c 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -712,6 +712,19 @@ pub enum NodePublicKey { Ed25519(ed25519::Public), } +impl TryFrom<&[u8]> for NodePublicKey { + type Error = (); + + fn try_from(x: &[u8]) -> Result { + if x.len() != 32 { + return Err(()); + } + let mut public = ed25519::Public::default(); + public.0.copy_from_slice(&x[0..32]); + Ok(NodePublicKey::Ed25519(public)) + } +} + #[cfg(feature = "std")] pub use self::dummy::*; diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 4bb8bfdd18b23..7fd1132001426 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -497,7 +497,7 @@ pub trait Externalities: Send { ) -> Result; /// Get public key of the node - fn get_node_public_key(&mut self) -> NodePublicKey; + fn get_node_public_key(&mut self) -> Result; /// Set the reserved nodes fn set_reserved_nodes(&mut self, nodes: Vec); @@ -580,7 +580,7 @@ impl Externalities for Box { (&mut **self).http_response_read_body(request_id, buffer, deadline) } - fn get_node_public_key(&mut self) -> NodePublicKey { + fn get_node_public_key(&mut self) -> Result { (&mut **self).get_node_public_key() } @@ -706,7 +706,7 @@ impl Externalities for LimitedExternalities { self.externalities.http_response_read_body(request_id, buffer, deadline) } - fn get_node_public_key(&mut self) -> NodePublicKey { + fn get_node_public_key(&mut self) -> Result { self.check(Capability::NetworkState, "get_node_public_key"); self.externalities.get_node_public_key() } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 6a4bc4918faf3..8a178e26d8d1a 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -377,11 +377,11 @@ impl offchain::Externalities for TestOffchainExt { } } - fn get_node_public_key(&mut self) -> NodePublicKey { - NodePublicKey::Ed25519(ed25519::Public([0u8; 32])) + fn get_node_public_key(&mut self) -> Result { + Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) } - fn set_reserved_nodes(&mut self, nodes: Vec) { + fn set_reserved_nodes(&mut self, _nodes: Vec) { } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index c8b7f5a3a6b4f..4b829985e95a7 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -962,7 +962,7 @@ pub trait Offchain { } /// Get public key of the local node. - fn get_node_public_key(&mut self) -> NodePublicKey { + fn get_node_public_key(&mut self) -> Result { self.extension::() .expect("get_node_public_key can be called only in the offchain worker context") .get_node_public_key() From 6b43f9ec81566b613e1e50e55e446df8e96a95d1 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 26 Aug 2020 20:51:47 +0800 Subject: [PATCH 04/34] refactor set reserved nodes ocw api. --- client/offchain/src/api.rs | 19 +++++++++++-------- primitives/core/src/offchain/mod.rs | 10 +++++----- primitives/core/src/offchain/testing.rs | 2 +- primitives/io/src/lib.rs | 4 ++-- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 11648a04e41cb..b23b1b6c86193 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -27,8 +27,8 @@ use futures::Future; use log::error; use sc_network::{PeerId, Multiaddr, NetworkStateInfo}; use sc_network::config::identity::{ - ed25519::PublicKey as Ed25519PublicKey, - PublicKey + ed25519::PublicKey as Ed25519PeerPublicKey, + PublicKey as PeerPublicKey }; use codec::{Encode, Decode}; use sp_core::offchain::{ @@ -192,14 +192,17 @@ impl OffchainExt for Api { peer_id.as_bytes().try_into() } - fn set_reserved_nodes(&mut self, nodes: Vec) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { let mut peer_ids: HashSet = nodes.iter() - .filter_map(|node| { + .filter_map(|node| match node { - NodePublicKey::Ed25519(pubkey) => Ed25519PublicKey::decode(&pubkey.0).ok() + NodePublicKey::Ed25519(public) => + Ed25519PeerPublicKey::decode(&public.0).ok() } - }) - .map(|pubkey| PublicKey::Ed25519(pubkey).into_peer_id()) + ) + .map(|public| + PeerPublicKey::Ed25519(public).into_peer_id() + ) .collect(); peer_ids.remove(&self.network_state.local_peer_id()); @@ -207,7 +210,7 @@ impl OffchainExt for Api { let peerset = self.network_state.peerset(); peerset.set_reserved_peers(peer_ids); // Respect reserved peers from runtime, ignore CLI flags for now. - peerset.set_reserved_only(true); + peerset.set_reserved_only(reserved_only); } } diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 7fd1132001426..094a7de3cf395 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -500,7 +500,7 @@ pub trait Externalities: Send { fn get_node_public_key(&mut self) -> Result; /// Set the reserved nodes - fn set_reserved_nodes(&mut self, nodes: Vec); + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool); } impl Externalities for Box { @@ -584,8 +584,8 @@ impl Externalities for Box { (&mut **self).get_node_public_key() } - fn set_reserved_nodes(&mut self, nodes: Vec) { - (&mut **self).set_reserved_nodes(nodes) + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + (&mut **self).set_reserved_nodes(nodes, reserved_only) } } @@ -711,9 +711,9 @@ impl Externalities for LimitedExternalities { self.externalities.get_node_public_key() } - fn set_reserved_nodes(&mut self, nodes: Vec) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { self.check(Capability::NetworkState, "set_reserved_nodes"); - self.externalities.set_reserved_nodes(nodes) + self.externalities.set_reserved_nodes(nodes, reserved_only) } } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 8a178e26d8d1a..594d3f95dc25e 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -381,7 +381,7 @@ impl offchain::Externalities for TestOffchainExt { Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) } - fn set_reserved_nodes(&mut self, _nodes: Vec) { + fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 4b829985e95a7..cbb7b04143c9b 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -969,10 +969,10 @@ pub trait Offchain { } /// Set the reserved peers - fn set_reserved_nodes(&mut self, nodes: Vec) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { self.extension::() .expect("set_reserved_nodes can be called only in the offchain worker context") - .set_reserved_nodes(nodes) + .set_reserved_nodes(nodes, reserved_only) } } From 4d17e4c5c51740fec934ca98dbb3e085383d5e00 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Thu, 27 Aug 2020 01:35:44 +0800 Subject: [PATCH 05/34] new ndoe authorization pallet --- frame/node-authorization/Cargo.toml | 38 ++ frame/node-authorization/src/lib.rs | 542 ++++++++++++++++++++++++++++ 2 files changed, 580 insertions(+) create mode 100644 frame/node-authorization/Cargo.toml create mode 100644 frame/node-authorization/src/lib.rs diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml new file mode 100644 index 0000000000000..4931ca7d60b4d --- /dev/null +++ b/frame/node-authorization/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "pallet-node-authorization" +version = "2.0.0-rc6" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME pallet for node authorization" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +serde = { version = "1.0.101", optional = true } +codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false, features = ["derive"] } +frame-support = { version = "2.0.0-rc6", default-features = false, path = "../support" } +frame-system = { version = "2.0.0-rc6", default-features = false, path = "../system" } +sp-core = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/core" } +sp-io = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } + +[dev-dependencies] +hex-literal = "0.2.1" + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "frame-support/std", + "frame-system/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] \ No newline at end of file diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs new file mode 100644 index 0000000000000..7ace4eaa607db --- /dev/null +++ b/frame/node-authorization/src/lib.rs @@ -0,0 +1,542 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2020 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Node authorization pallet +//! +//! This pallet manages a configurable set of nodes for a permissioned network. +//! It provides two ways to authorize a node, +//! * a set of the well known nodes across different organizations in which +//! the communication is allowed. +//! * users can claim the ownership for nodes, and manage the communication for the node. +//! +//! A node is optionally to have an owner. If exists, the owner can make additional +//! adaptive change for the connection of the node. If not exists, the node can only +//! participate in the network as a well known node. +//! Only one user can `claim` a specific node. To eliminate falsely claim, the maintainer +//! of the node should claim it before even start the node. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use sp_std::prelude::*; +use sp_core::NodePublicKey; +use frame_support::{ + decl_module, decl_storage, decl_event, decl_error, + debug, ensure, + weights::{DispatchClass, Weight}, + traits::{Get, EnsureOrigin}, +}; +use frame_system::ensure_signed; + +pub trait WeightInfo { + fn add_well_known_node() -> Weight; + fn remove_well_known_node() -> Weight; + fn swap_well_known_node() -> Weight; + fn reset_well_known_nodes() -> Weight; + fn claim_node() -> Weight; +} + +impl WeightInfo for () { + fn add_well_known_node() -> Weight { 50_000_000 } + fn remove_well_known_node() -> Weight { 50_000_000 } + fn swap_well_known_node() -> Weight { 50_000_000 } + fn reset_well_known_nodes() -> Weight { 50_000_000 } + fn claim_node() -> Weight { 50_000_000 } +} + +pub trait Trait: frame_system::Trait { + /// The event type of this module. + type Event: From> + Into<::Event>; + + /// The maximum number of authorized nodes that are allowed to set + type MaxWellKnownNodes: Get; + + /// The origin which can add a authorized node. + type AddOrigin: EnsureOrigin; + + /// The origin which can remove a authorized node. + type RemoveOrigin: EnsureOrigin; + + /// The origin which can swap the authorized nodes. + type SwapOrigin: EnsureOrigin; + + /// The origin which can reset the authorized nodes. + type ResetOrigin: EnsureOrigin; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; +} + +decl_storage! { + trait Store for Module as NodeAuthorization { + /// The current well known nodes. This is stored sorted (just by value). + pub WellKnownNodes get(fn well_known_nodes): Vec; + /// A map that maintains the ownership of each node. + pub Owners get(fn owners): + map hasher(blake2_128_concat) NodePublicKey => T::AccountId; + /// The additional adapative connection for a node. + pub AdditionalConnection get(fn additional_connection): + map hasher(blake2_128_concat) NodePublicKey => Vec; + } +} + +decl_event! { + pub enum Event where + ::AccountId, + { + /// The given node was added. + WellKnownNodeAdded(NodePublicKey, AccountId), + /// The given node was removed. + WellKnownNodeRemoved(NodePublicKey), + /// Two given nodes were swapped; first item is removed, the latter is added. + WellKnownNodeSwapped(NodePublicKey, NodePublicKey, AccountId), + /// The given nodes were reset. + WellKnownNodesReset(Vec<(NodePublicKey, AccountId)>), + /// The given node was claimed by a user. + NodeClaimed(NodePublicKey, AccountId), + ConnectionAdded(NodePublicKey, Vec), + } +} + +decl_error! { + /// Error for the node authorization module. + pub enum Error for Module { + /// Too many authorized nodes. + TooManyNodes, + /// The node is already joined in the list. + AlreadyJoined, + /// The node doesn't exist in the list. + NotExist, + /// The node is already claimed by a user. + AlreadyClaimed, + /// The node hasn't been claimed yet. + NotClaimed, + /// You are not the owner of the node. + NotOwner, + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + /// The maximum number of authorized nodes + const MaxWellKnownNodes: u32 = T::MaxWellKnownNodes::get(); + + type Error = Error; + + fn deposit_event() = default; + + /// Add a node to the set of well known nodes. + /// + /// May only be called from `T::AddOrigin`. + /// + /// - `node_public_key`: identifier of the node. + #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] + pub fn add_well_known_node(origin, node_public_key: NodePublicKey, owner: T::AccountId) { + T::AddOrigin::ensure_origin(origin)?; + + let mut nodes = WellKnownNodes::get(); + ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + + let location = nodes.binary_search(&node_public_key).err().ok_or(Error::::AlreadyJoined)?; + nodes.insert(location, node_public_key.clone()); + + WellKnownNodes::put(&nodes); + >::insert(node_public_key.clone(), owner.clone()); + + Self::deposit_event(RawEvent::WellKnownNodeAdded(node_public_key, owner)); + } + + /// Remove a node from the set of well known nodes. + /// + /// May only be called from `T::RemoveOrigin`. + /// + /// - `node_public_key`: identifier of the node. + #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] + pub fn remove_well_known_node(origin, node_public_key: NodePublicKey) { + T::RemoveOrigin::ensure_origin(origin)?; + + let mut nodes = WellKnownNodes::get(); + + let location = nodes.binary_search(&node_public_key).ok().ok_or(Error::::NotExist)?; + nodes.remove(location); + + WellKnownNodes::put(&nodes); + >::remove(&node_public_key); + AdditionalConnection::remove(&node_public_key); + + Self::deposit_event(RawEvent::WellKnownNodeRemoved(node_public_key)); + } + + /// Swap two nodes. + /// + /// May only be called from `T::SwapOrigin`. + /// + /// - `remove`: the node which will be moved out from the list. + /// - `add`: the node which will be put in the list. + // #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] + // pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { + // T::SwapOrigin::ensure_origin(origin)?; + + // if remove == add { return Ok(()) } + + // let mut nodes = Self::get_allow_list(); + // let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; + // nodes.remove(remove_location); + // let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; + // nodes.insert(add_location, add.clone()); + // Self::put_allow_list(&nodes); + + // Self::deposit_event(Event::NodeSwapped(remove, add)); + // } + + /// Reset all the authorized nodes in the list. + /// + /// May only be called from `T::ResetOrigin`. + /// + /// - `nodes`: the new nodes for the allow list. + // #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] + // pub fn reset_well_known_nodes(origin, nodes: Vec) { + // T::ResetOrigin::ensure_origin(origin)?; + // ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + + // let mut nodes = nodes; + // nodes.sort(); + // Self::put_allow_list(&nodes); + + // Self::deposit_event(Event::NodesReset(nodes)); + // } + + /// Send a transaction to claim the node. + /// + /// - `node_public_key`: identifier of the node. + #[weight = T::WeightInfo::claim_node()] + pub fn claim_node(origin, node_public_key: NodePublicKey) { + let sender = ensure_signed(origin)?; + + ensure!( + !Owners::::contains_key(&node_public_key), + Error::::AlreadyClaimed + ); + + Owners::::insert(&node_public_key, sender.clone()); + Self::deposit_event(RawEvent::NodeClaimed(node_public_key, sender)); + } + + /// Send a transaction to claim the node. + /// + /// - `node_public_key`: identifier of the node. + #[weight = T::WeightInfo::claim_node()] + pub fn add_connection( + origin, + node_public_key: NodePublicKey, + connections: Vec + ) { + let sender = ensure_signed(origin)?; + + ensure!( + Owners::::contains_key(&node_public_key), + Error::::NotClaimed + ); + + ensure!( + Owners::::get(&node_public_key) == sender, + Error::::NotOwner + ); + + let mut nodes = AdditionalConnection::get(&node_public_key); + nodes.extend(connections.clone()); + nodes.sort(); + nodes.dedup(); + + Self::deposit_event(RawEvent::ConnectionAdded(node_public_key, connections)); + } + + fn offchain_worker(now: T::BlockNumber) { + let node_public_key = sp_io::offchain::get_node_public_key(); + match node_public_key { + Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), + Ok(node) => Self::authorize_nodes(node), + } + } + } +} + +impl Module { + fn authorize_nodes(node: NodePublicKey) { + let mut nodes = AdditionalConnection::get(node.clone()); + + let well_known_nodes = WellKnownNodes::get(); + if well_known_nodes.binary_search(&node).is_ok() { + nodes.extend(well_known_nodes); + } + + sp_io::offchain::set_reserved_nodes(nodes, true) + } +} + +// #[cfg(test)] +// mod tests { +// use super::*; + +// use frame_support::{ +// assert_ok, assert_noop, impl_outer_origin, weights::Weight, +// parameter_types, ord_parameter_types, +// }; +// use frame_system::EnsureSignedBy; +// use sp_core::{H256, ed25519::Public}; +// use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; +// use hex_literal::hex; + +// impl_outer_origin! { +// pub enum Origin for Test where system = frame_system {} +// } + +// #[derive(Clone, Eq, PartialEq)] +// pub struct Test; + +// parameter_types! { +// pub const BlockHashCount: u64 = 250; +// pub const MaximumBlockWeight: Weight = 1024; +// pub const MaximumBlockLength: u32 = 2 * 1024; +// pub const AvailableBlockRatio: Perbill = Perbill::one(); +// } +// impl frame_system::Trait for Test { +// type BaseCallFilter = (); +// type Origin = Origin; +// type Index = u64; +// type BlockNumber = u64; +// type Hash = H256; +// type Call = (); +// type Hashing = BlakeTwo256; +// type AccountId = u64; +// type Lookup = IdentityLookup; +// type Header = Header; +// type Event = (); +// type BlockHashCount = BlockHashCount; +// type MaximumBlockWeight = MaximumBlockWeight; +// type DbWeight = (); +// type BlockExecutionWeight = (); +// type ExtrinsicBaseWeight = (); +// type MaximumExtrinsicWeight = MaximumBlockWeight; +// type MaximumBlockLength = MaximumBlockLength; +// type AvailableBlockRatio = AvailableBlockRatio; +// type Version = (); +// type ModuleToIndex = (); +// type AccountData = (); +// type OnNewAccount = (); +// type OnKilledAccount = (); +// type SystemWeightInfo = (); +// } + +// ord_parameter_types! { +// pub const One: u64 = 1; +// pub const Two: u64 = 2; +// pub const Three: u64 = 3; +// pub const Four: u64 = 4; +// } +// parameter_types! { +// pub const MaxWellKnownNodes: u32 = 4; +// } +// impl Trait for Test { +// type Event = (); +// type MaxWellKnownNodes = MaxWellKnownNodes; +// type AddOrigin = EnsureSignedBy; +// type RemoveOrigin = EnsureSignedBy; +// type SwapOrigin = EnsureSignedBy; +// type ResetOrigin = EnsureSignedBy; +// type WeightInfo = (); +// } + +// type NodeAuthorization = Module; + +// fn new_test_ext() -> sp_io::TestExternalities { +// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000009") +// )); +// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000013") +// )); +// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000001d") +// )); + +// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); +// GenesisConfig { +// nodes: vec![pub10, pub20, pub30], +// }.assimilate_storage(&mut t).unwrap(); +// t.into() +// } + +// #[test] +// fn add_node_works() { +// new_test_ext().execute_with(|| { +// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000009") +// )); +// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000000e") +// )); +// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000013") +// )); +// let pub25: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000018") +// )); +// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000001d") +// )); + +// assert_noop!(NodeAuthorization::add_well_known_node(Origin::signed(2), pub15.clone()), BadOrigin); +// assert_noop!( +// NodeAuthorization::add_well_known_node(Origin::signed(1), pub20.clone()), +// Error::::AlreadyJoined +// ); + +// assert_ok!(NodeAuthorization::add_well_known_node(Origin::signed(1), pub15.clone())); +// assert_eq!( +// NodeAuthorization::get_allow_list(), +// vec![pub10.clone(), pub15.clone(), pub20.clone(), pub30.clone()] +// ); + +// assert_noop!( +// NodeAuthorization::add_well_known_node(Origin::signed(1), pub25.clone()), +// Error::::TooManyNodes +// ); +// }); +// } + +// #[test] +// fn remove_node_works() { +// new_test_ext().execute_with(|| { +// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000009") +// )); +// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000013") +// )); +// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000001d") +// )); +// let pub40: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000027") +// )); + +// assert_noop!( +// NodeAuthorization::remove_well_known_node(Origin::signed(3), pub20.clone()), +// BadOrigin +// ); +// assert_noop!( +// NodeAuthorization::remove_well_known_node(Origin::signed(2), pub40.clone()), +// Error::::NotExist +// ); + +// assert_ok!(NodeAuthorization::remove_well_known_node(Origin::signed(2), pub20.clone())); +// assert_eq!(NodeAuthorization::get_allow_list(), vec![pub10.clone(), pub30.clone()]); +// }); +// } + +// #[test] +// fn swap_node_works() { +// new_test_ext().execute_with(|| { +// let pub5: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000004") +// )); +// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000009") +// )); +// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000000e") +// )); +// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000013") +// )); +// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000001d") +// )); + +// assert_noop!( +// NodeAuthorization::swap_well_known_node(Origin::signed(4), pub20.clone(), pub5.clone()), +// BadOrigin +// ); + +// assert_ok!(NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub20.clone())); +// assert_eq!( +// NodeAuthorization::get_allow_list(), +// vec![pub10.clone(), pub20.clone(), pub30.clone()] +// ); + +// assert_noop!( +// NodeAuthorization::swap_well_known_node(Origin::signed(3), pub15.clone(), pub5.clone()), +// Error::::NotExist +// ); +// assert_noop!( +// NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub30.clone()), +// Error::::AlreadyJoined +// ); + +// assert_ok!(NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub5.clone())); +// assert_eq!( +// NodeAuthorization::get_allow_list(), +// vec![pub5.clone(), pub10.clone(), pub30.clone()] +// ); +// }); +// } + +// #[test] +// fn reset_nodes_works() { +// new_test_ext().execute_with(|| { +// let pub5: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000004") +// )); +// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("000000000000000000000000000000000000000000000000000000000000000e") +// )); +// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000013") +// )); +// let pub25: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( +// hex!("0000000000000000000000000000000000000000000000000000000000000018") +// )); + +// assert_noop!( +// NodeAuthorization::reset_well_known_nodes( +// Origin::signed(3), +// vec![pub15.clone(), pub5.clone(), pub20.clone()] +// ), +// BadOrigin +// ); +// assert_noop!( +// NodeAuthorization::reset_well_known_nodes( +// Origin::signed(4), +// vec![pub15.clone(), pub5.clone(), pub20.clone(), pub25.clone()] +// ), +// Error::::TooManyNodes +// ); + +// assert_ok!( +// NodeAuthorization::reset_well_known_nodes( +// Origin::signed(4), +// vec![pub15.clone(), pub5.clone(), pub20.clone()] +// ) +// ); +// assert_eq!( +// NodeAuthorization::get_allow_list(), +// vec![pub5.clone(), pub15.clone(), pub20.clone()] +// ); +// }); +// } +// } \ No newline at end of file From 46b40784fe43ca6398edb26a47474d23e69aa8c8 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Fri, 28 Aug 2020 11:48:40 +0800 Subject: [PATCH 06/34] remove unnecessary clone and more. --- Cargo.lock | 2 ++ client/network/src/lib.rs | 4 ++++ client/network/src/service.rs | 15 ++++++++++-- client/offchain/src/api.rs | 9 ++++--- frame/node-authorization/src/lib.rs | 37 ++++++++++++++++++++--------- primitives/core/src/crypto.rs | 14 ++++------- 6 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bd6a75433de9..b2e50950ce551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3756,6 +3756,7 @@ dependencies = [ "pallet-grandpa", "pallet-im-online", "pallet-indices", + "pallet-node-authorization", "pallet-staking", "pallet-timestamp", "pallet-transaction-payment", @@ -3942,6 +3943,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-multisig", + "pallet-node-authorization", "pallet-offences", "pallet-offences-benchmarking", "pallet-proxy", diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 1d20b90c12e2c..a3671986141b4 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -274,6 +274,7 @@ pub use libp2p::multiaddr; pub use sc_peerset::ReputationChange; use sc_peerset::PeersetHandle; use sp_runtime::traits::{Block as BlockT, NumberFor}; +use config::identity::PublicKey; /// The maximum allowed number of established connections per peer. /// @@ -298,6 +299,9 @@ pub trait NetworkStateInfo { /// Returns the local Peer ID. fn local_peer_id(&self) -> PeerId; + /// Returns the local Peer PublicKey. + fn local_public_key(&self) -> PublicKey; + /// Returns the peerset fn peerset(&self) -> PeersetHandle; } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 44ffc4754c2f6..60df20e5f5dca 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -30,7 +30,10 @@ use crate::{ ExHashT, NetworkStateInfo, behaviour::{Behaviour, BehaviourOut}, - config::{parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig}, + config::{ + parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig, + identity::PublicKey, + }, DhtEvent, discovery::DiscoveryConfig, error::Error, @@ -91,6 +94,8 @@ pub struct NetworkService { is_major_syncing: Arc, /// Local copy of the `PeerId` of the local node. local_peer_id: PeerId, + /// Local copy of the `PublicKey` of the local node. + local_public_key: PublicKey, /// Bandwidth logging system. Can be queried to know the average bandwidth consumed. bandwidth: Arc, /// Peerset manager (PSM); manages the reputation of nodes and indicates the network which @@ -313,7 +318,7 @@ impl NetworkWorker { protocol, params.role, user_agent, - local_public, + local_public.clone(), block_requests, finality_proof_requests, light_client_handler, @@ -383,6 +388,7 @@ impl NetworkWorker { is_major_syncing: is_major_syncing.clone(), peerset: peerset_handle, local_peer_id, + local_public_key: local_public, to_worker, peers_notifications_sinks: peers_notifications_sinks.clone(), protocol_name_by_engine, @@ -1001,6 +1007,11 @@ impl NetworkStateInfo for NetworkService self.local_peer_id.clone() } + /// Returns the PublicKey of local peer. + fn local_public_key(&self) -> PublicKey { + self.local_public_key.clone() + } + /// Returns the peerset. fn peerset(&self) -> PeersetHandle { self.peerset.clone() diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index b23b1b6c86193..347002f5402bf 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -17,7 +17,7 @@ use std::{ str::FromStr, sync::Arc, - convert::{TryFrom, TryInto}, + convert::TryFrom, thread::sleep, collections::HashSet, }; @@ -188,8 +188,11 @@ impl OffchainExt for Api { } fn get_node_public_key(&mut self) -> Result { - let peer_id = self.network_state.local_peer_id(); - peer_id.as_bytes().try_into() + let public_key = self.network_state.local_public_key(); + match public_key { + PeerPublicKey::Ed25519(public) => Ok(public.encode().into()), + _ => Err(()), + } } fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 7ace4eaa607db..5b289c84765c0 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -23,11 +23,10 @@ //! the communication is allowed. //! * users can claim the ownership for nodes, and manage the communication for the node. //! -//! A node is optionally to have an owner. If exists, the owner can make additional -//! adaptive change for the connection of the node. If not exists, the node can only -//! participate in the network as a well known node. -//! Only one user can `claim` a specific node. To eliminate falsely claim, the maintainer -//! of the node should claim it before even start the node. +//! A node must have an owner. The owner then can make additional adaptive adaptive +//! change for the connection of the node. Only one user can `claim` a specific node. +//! To eliminate falsely claim, the maintainer of the node should claim it before +//! even start the node. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -92,6 +91,19 @@ decl_storage! { pub AdditionalConnection get(fn additional_connection): map hasher(blake2_128_concat) NodePublicKey => Vec; } + add_extra_genesis { + config(nodes): Vec<(NodePublicKey, T::AccountId)>; + build(|config: &GenesisConfig| { + WellKnownNodes::put( + config.nodes.iter() + .map(|item| item.0.clone()) + .collect::>() + ); + for (node, who) in config.nodes.iter() { + Owners::::insert(node, who); + } + }) + } } decl_event! { @@ -108,7 +120,8 @@ decl_event! { WellKnownNodesReset(Vec<(NodePublicKey, AccountId)>), /// The given node was claimed by a user. NodeClaimed(NodePublicKey, AccountId), - ConnectionAdded(NodePublicKey, Vec), + /// New connections were added to a node. + ConnectionsAdded(NodePublicKey, Vec), } } @@ -132,7 +145,7 @@ decl_error! { decl_module! { pub struct Module for enum Call where origin: T::Origin { - /// The maximum number of authorized nodes + /// The maximum number of authorized well known nodes const MaxWellKnownNodes: u32 = T::MaxWellKnownNodes::get(); type Error = Error; @@ -155,7 +168,7 @@ decl_module! { nodes.insert(location, node_public_key.clone()); WellKnownNodes::put(&nodes); - >::insert(node_public_key.clone(), owner.clone()); + >::insert(&node_public_key, &owner); Self::deposit_event(RawEvent::WellKnownNodeAdded(node_public_key, owner)); } @@ -232,7 +245,7 @@ decl_module! { Error::::AlreadyClaimed ); - Owners::::insert(&node_public_key, sender.clone()); + Owners::::insert(&node_public_key, &sender); Self::deposit_event(RawEvent::NodeClaimed(node_public_key, sender)); } @@ -261,8 +274,10 @@ decl_module! { nodes.extend(connections.clone()); nodes.sort(); nodes.dedup(); + + AdditionalConnection::insert(&node_public_key, nodes); - Self::deposit_event(RawEvent::ConnectionAdded(node_public_key, connections)); + Self::deposit_event(RawEvent::ConnectionsAdded(node_public_key, connections)); } fn offchain_worker(now: T::BlockNumber) { @@ -277,7 +292,7 @@ decl_module! { impl Module { fn authorize_nodes(node: NodePublicKey) { - let mut nodes = AdditionalConnection::get(node.clone()); + let mut nodes = AdditionalConnection::get(&node); let well_known_nodes = WellKnownNodes::get(); if well_known_nodes.binary_search(&node).is_ok() { diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 602d9de6e9f0c..e65c7b7353881 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -712,16 +712,10 @@ pub enum NodePublicKey { Ed25519(ed25519::Public), } -impl TryFrom<&[u8]> for NodePublicKey { - type Error = (); - - fn try_from(x: &[u8]) -> Result { - if x.len() != 32 { - return Err(()); - } - let mut public = ed25519::Public::default(); - public.0.copy_from_slice(&x[0..32]); - Ok(NodePublicKey::Ed25519(public)) +impl From<[u8; 32]> for NodePublicKey { + fn from(x: [u8; 32]) -> NodePublicKey { + let public = ed25519::Public(x); + NodePublicKey::Ed25519(public) } } From 70e616e88b439dca989a3fa93e3ab9c81bc7399f Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Mon, 31 Aug 2020 01:27:28 +0800 Subject: [PATCH 07/34] more --- frame/node-authorization/src/lib.rs | 144 +++++++++++++++------------- 1 file changed, 80 insertions(+), 64 deletions(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 5b289c84765c0..d78b7edb55b57 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -19,13 +19,13 @@ //! //! This pallet manages a configurable set of nodes for a permissioned network. //! It provides two ways to authorize a node, -//! * a set of the well known nodes across different organizations in which -//! the communication is allowed. -//! * users can claim the ownership for nodes, and manage the communication for the node. +//! * a set of well known nodes across different organizations in which +//! the connections are allowed. +//! * users can claim the ownership for each node, then manage the connection of the node. //! -//! A node must have an owner. The owner then can make additional adaptive adaptive -//! change for the connection of the node. Only one user can `claim` a specific node. -//! To eliminate falsely claim, the maintainer of the node should claim it before +//! A node must have an owner. The owner can make additional adaptive change for +//! the connection of the node. Only one user can `claim` a specific node. +//! To eliminate false claim, the maintainer of the node should claim it before //! even start the node. // Ensure we're `no_std` when compiling for Wasm. @@ -61,19 +61,19 @@ pub trait Trait: frame_system::Trait { /// The event type of this module. type Event: From> + Into<::Event>; - /// The maximum number of authorized nodes that are allowed to set + /// The maximum number of well known nodes that are allowed to set type MaxWellKnownNodes: Get; - /// The origin which can add a authorized node. + /// The origin which can add a well known node. type AddOrigin: EnsureOrigin; - /// The origin which can remove a authorized node. + /// The origin which can remove a well known node. type RemoveOrigin: EnsureOrigin; - /// The origin which can swap the authorized nodes. + /// The origin which can swap the well known nodes. type SwapOrigin: EnsureOrigin; - /// The origin which can reset the authorized nodes. + /// The origin which can reset the well known nodes. type ResetOrigin: EnsureOrigin; /// Weight information for extrinsics in this pallet. @@ -82,13 +82,13 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as NodeAuthorization { - /// The current well known nodes. This is stored sorted (just by value). + /// The set of well known nodes. This is stored sorted (just by value). pub WellKnownNodes get(fn well_known_nodes): Vec; /// A map that maintains the ownership of each node. pub Owners get(fn owners): map hasher(blake2_128_concat) NodePublicKey => T::AccountId; - /// The additional adapative connection for a node. - pub AdditionalConnection get(fn additional_connection): + /// The additional adapative connections of a node. + pub AdditionalConnections get(fn additional_connection): map hasher(blake2_128_concat) NodePublicKey => Vec; } add_extra_genesis { @@ -110,14 +110,15 @@ decl_event! { pub enum Event where ::AccountId, { - /// The given node was added. - WellKnownNodeAdded(NodePublicKey, AccountId), - /// The given node was removed. - WellKnownNodeRemoved(NodePublicKey), - /// Two given nodes were swapped; first item is removed, the latter is added. - WellKnownNodeSwapped(NodePublicKey, NodePublicKey, AccountId), - /// The given nodes were reset. - WellKnownNodesReset(Vec<(NodePublicKey, AccountId)>), + /// The given well known node was added. + NodeAdded(NodePublicKey, AccountId), + /// The given well known node was removed. + NodeRemoved(NodePublicKey), + /// Two given well known node were swapped; first item is removed, + /// the latter is added. + NodeSwapped(NodePublicKey, NodePublicKey), + /// The given well known nodes were reset. + NodesReset(Vec<(NodePublicKey, AccountId)>), /// The given node was claimed by a user. NodeClaimed(NodePublicKey, AccountId), /// New connections were added to a node. @@ -128,7 +129,7 @@ decl_event! { decl_error! { /// Error for the node authorization module. pub enum Error for Module { - /// Too many authorized nodes. + /// Too many well known nodes. TooManyNodes, /// The node is already joined in the list. AlreadyJoined, @@ -152,86 +153,89 @@ decl_module! { fn deposit_event() = default; - /// Add a node to the set of well known nodes. + /// Add a node to the set of well known nodes. If the node is already claimed, the owner + /// will be updated and keep the existing additional connection unchanged. /// /// May only be called from `T::AddOrigin`. /// - /// - `node_public_key`: identifier of the node. + /// - `node`: identifier of the node. #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] - pub fn add_well_known_node(origin, node_public_key: NodePublicKey, owner: T::AccountId) { + pub fn add_well_known_node(origin, node: NodePublicKey, owner: T::AccountId) { T::AddOrigin::ensure_origin(origin)?; let mut nodes = WellKnownNodes::get(); ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - let location = nodes.binary_search(&node_public_key).err().ok_or(Error::::AlreadyJoined)?; - nodes.insert(location, node_public_key.clone()); + let location = nodes.binary_search(&node).err().ok_or(Error::::AlreadyJoined)?; + nodes.insert(location, node.clone()); WellKnownNodes::put(&nodes); - >::insert(&node_public_key, &owner); + >::insert(&node, &owner); - Self::deposit_event(RawEvent::WellKnownNodeAdded(node_public_key, owner)); + Self::deposit_event(RawEvent::NodeAdded(node, owner)); } - /// Remove a node from the set of well known nodes. + /// Remove a node from the set of well known nodes. The ownership and additional + /// connections of the node will also be removed. /// /// May only be called from `T::RemoveOrigin`. /// - /// - `node_public_key`: identifier of the node. + /// - `node`: identifier of the node. #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] - pub fn remove_well_known_node(origin, node_public_key: NodePublicKey) { + pub fn remove_well_known_node(origin, node: NodePublicKey) { T::RemoveOrigin::ensure_origin(origin)?; let mut nodes = WellKnownNodes::get(); - let location = nodes.binary_search(&node_public_key).ok().ok_or(Error::::NotExist)?; + let location = nodes.binary_search(&node).ok().ok_or(Error::::NotExist)?; nodes.remove(location); WellKnownNodes::put(&nodes); - >::remove(&node_public_key); - AdditionalConnection::remove(&node_public_key); + >::remove(&node); + AdditionalConnections::remove(&node); - Self::deposit_event(RawEvent::WellKnownNodeRemoved(node_public_key)); + Self::deposit_event(RawEvent::NodeRemoved(node)); } - /// Swap two nodes. + /// Swap one well know node to another. Both the ownership and additonal connections + /// stay untouched. /// /// May only be called from `T::SwapOrigin`. /// /// - `remove`: the node which will be moved out from the list. /// - `add`: the node which will be put in the list. - // #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] - // pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { - // T::SwapOrigin::ensure_origin(origin)?; + #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] + pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { + T::SwapOrigin::ensure_origin(origin)?; - // if remove == add { return Ok(()) } + if remove == add { return Ok(()) } - // let mut nodes = Self::get_allow_list(); - // let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; - // nodes.remove(remove_location); - // let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; - // nodes.insert(add_location, add.clone()); - // Self::put_allow_list(&nodes); - - // Self::deposit_event(Event::NodeSwapped(remove, add)); - // } + let mut nodes = WellKnownNodes::get(); + let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; + nodes.remove(remove_location); + let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; + nodes.insert(add_location, add.clone()); + WellKnownNodes::put(&nodes); + + Self::deposit_event(RawEvent::NodeSwapped(remove, add)); + } - /// Reset all the authorized nodes in the list. + /// Reset all the well known nodes. This will not remove the ownership and additional + /// connections for the removed nodes. The node owner can perform furthur cleaning if + /// they decide to leave the network. /// /// May only be called from `T::ResetOrigin`. /// /// - `nodes`: the new nodes for the allow list. - // #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] - // pub fn reset_well_known_nodes(origin, nodes: Vec) { - // T::ResetOrigin::ensure_origin(origin)?; - // ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] + pub fn reset_well_known_nodes(origin, nodes: Vec<(NodePublicKey, T::AccountId)>) { + T::ResetOrigin::ensure_origin(origin)?; + ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - // let mut nodes = nodes; - // nodes.sort(); - // Self::put_allow_list(&nodes); + Self::initialize_nodes(nodes.clone()); - // Self::deposit_event(Event::NodesReset(nodes)); - // } + Self::deposit_event(RawEvent::NodesReset(nodes)); + } /// Send a transaction to claim the node. /// @@ -270,12 +274,12 @@ decl_module! { Error::::NotOwner ); - let mut nodes = AdditionalConnection::get(&node_public_key); + let mut nodes = AdditionalConnections::get(&node_public_key); nodes.extend(connections.clone()); nodes.sort(); nodes.dedup(); - AdditionalConnection::insert(&node_public_key, nodes); + AdditionalConnections::insert(&node_public_key, nodes); Self::deposit_event(RawEvent::ConnectionsAdded(node_public_key, connections)); } @@ -291,8 +295,20 @@ decl_module! { } impl Module { + fn initialize_nodes(nodes: Vec<(NodePublicKey, T::AccountId)>) { + let mut node_public_keys = nodes.iter() + .map(|item| item.0.clone()) + .collect::>(); + node_public_keys.sort(); + WellKnownNodes::put(&node_public_keys); + + for (node, who) in nodes.iter() { + Owners::::insert(node, who); + } + } + fn authorize_nodes(node: NodePublicKey) { - let mut nodes = AdditionalConnection::get(&node); + let mut nodes = AdditionalConnections::get(&node); let well_known_nodes = WellKnownNodes::get(); if well_known_nodes.binary_search(&node).is_ok() { From 613a84df6b0f494555ee16c3921fa753c921dcf5 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Mon, 31 Aug 2020 14:12:16 +0800 Subject: [PATCH 08/34] tests for node authorization pallet --- frame/node-authorization/src/lib.rs | 745 +++++++++++++++++----------- 1 file changed, 455 insertions(+), 290 deletions(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index d78b7edb55b57..31fd93062055e 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -19,8 +19,8 @@ //! //! This pallet manages a configurable set of nodes for a permissioned network. //! It provides two ways to authorize a node, -//! * a set of well known nodes across different organizations in which -//! the connections are allowed. +//! * a set of well known nodes across different organizations in which the +//! connections are allowed. //! * users can claim the ownership for each node, then manage the connection of the node. //! //! A node must have an owner. The owner can make additional adaptive change for @@ -47,6 +47,10 @@ pub trait WeightInfo { fn swap_well_known_node() -> Weight; fn reset_well_known_nodes() -> Weight; fn claim_node() -> Weight; + fn remove_claim() -> Weight; + fn transfer_node() -> Weight; + fn add_connections() -> Weight; + fn remove_connections() -> Weight; } impl WeightInfo for () { @@ -55,6 +59,10 @@ impl WeightInfo for () { fn swap_well_known_node() -> Weight { 50_000_000 } fn reset_well_known_nodes() -> Weight { 50_000_000 } fn claim_node() -> Weight { 50_000_000 } + fn remove_claim() -> Weight { 50_000_000 } + fn transfer_node() -> Weight { 50_000_000 } + fn add_connections() -> Weight { 50_000_000 } + fn remove_connections() -> Weight { 50_000_000 } } pub trait Trait: frame_system::Trait { @@ -94,14 +102,7 @@ decl_storage! { add_extra_genesis { config(nodes): Vec<(NodePublicKey, T::AccountId)>; build(|config: &GenesisConfig| { - WellKnownNodes::put( - config.nodes.iter() - .map(|item| item.0.clone()) - .collect::>() - ); - for (node, who) in config.nodes.iter() { - Owners::::insert(node, who); - } + >::initialize_nodes(&config.nodes) }) } } @@ -121,8 +122,14 @@ decl_event! { NodesReset(Vec<(NodePublicKey, AccountId)>), /// The given node was claimed by a user. NodeClaimed(NodePublicKey, AccountId), - /// New connections were added to a node. + /// The given claim was remove by its owner. + ClaimRemoved(NodePublicKey, AccountId), + /// The node was transferred to another account. + NodeTransferred(NodePublicKey, AccountId, AccountId), + /// The allowed connections were added to a node. ConnectionsAdded(NodePublicKey, Vec), + /// The allowed connections were removed from a node. + ConnectionsRemoved(NodePublicKey, Vec), } } @@ -141,6 +148,8 @@ decl_error! { NotClaimed, /// You are not the owner of the node. NotOwner, + /// No permisson to perform specific operation. + PermissionDenied, } } @@ -215,7 +224,10 @@ decl_module! { nodes.remove(remove_location); let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; nodes.insert(add_location, add.clone()); + WellKnownNodes::put(&nodes); + Owners::::swap(&remove, &add); + AdditionalConnections::swap(&remove, &add); Self::deposit_event(RawEvent::NodeSwapped(remove, add)); } @@ -232,70 +244,123 @@ decl_module! { T::ResetOrigin::ensure_origin(origin)?; ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - Self::initialize_nodes(nodes.clone()); + Self::initialize_nodes(&nodes); Self::deposit_event(RawEvent::NodesReset(nodes)); } - /// Send a transaction to claim the node. + /// A given node can be claimed by anyone. The owner should be the first to know its + /// public key, so claim it right away! /// - /// - `node_public_key`: identifier of the node. + /// - `node`: identifier of the node. #[weight = T::WeightInfo::claim_node()] - pub fn claim_node(origin, node_public_key: NodePublicKey) { + pub fn claim_node(origin, node: NodePublicKey) { let sender = ensure_signed(origin)?; + ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); - ensure!( - !Owners::::contains_key(&node_public_key), - Error::::AlreadyClaimed - ); + Owners::::insert(&node, &sender); + Self::deposit_event(RawEvent::NodeClaimed(node, sender)); + } + + /// A claim can be removed by its owner and get back the reservation. The additional + /// connections are also removed. You can't remove a claim on well known nodes, as it + /// needs to reach consensus among the network participants. + /// + /// - `node`: identifier of the node. + #[weight = T::WeightInfo::remove_claim()] + pub fn remove_claim(origin, node: NodePublicKey) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + ensure!(!WellKnownNodes::get().contains(&node), Error::::PermissionDenied); + + Owners::::remove(&node); + AdditionalConnections::remove(&node); - Owners::::insert(&node_public_key, &sender); - Self::deposit_event(RawEvent::NodeClaimed(node_public_key, sender)); + Self::deposit_event(RawEvent::ClaimRemoved(node, sender)); } - /// Send a transaction to claim the node. + /// A node can be transferred to a new owner. /// - /// - `node_public_key`: identifier of the node. - #[weight = T::WeightInfo::claim_node()] - pub fn add_connection( + /// - `node`: identifier of the node. + /// - `owner`: new owner of the node. + #[weight = T::WeightInfo::transfer_node()] + pub fn transfer_node(origin, node: NodePublicKey, owner: T::AccountId) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + + Owners::::insert(&node, &owner); + + Self::deposit_event(RawEvent::NodeTransferred(node, sender, owner)); + } + + /// Add additional connections to a given node. + /// + /// - `node`: identifier of the node. + /// - `connections`: additonal nodes from which the connections are allowed. + #[weight = T::WeightInfo::add_connections()] + pub fn add_connections( origin, - node_public_key: NodePublicKey, + node: NodePublicKey, connections: Vec ) { let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); - ensure!( - Owners::::contains_key(&node_public_key), - Error::::NotClaimed - ); + let mut nodes = AdditionalConnections::get(&node); - ensure!( - Owners::::get(&node_public_key) == sender, - Error::::NotOwner - ); + for add_node in connections.iter() { + if let Err(add_location) = nodes.binary_search(&add_node) { + nodes.insert(add_location, add_node.clone()); + } + } + + AdditionalConnections::insert(&node, nodes); + + Self::deposit_event(RawEvent::ConnectionsAdded(node, connections)); + } - let mut nodes = AdditionalConnections::get(&node_public_key); - nodes.extend(connections.clone()); - nodes.sort(); - nodes.dedup(); + /// Remove additional connections of a given node. + /// + /// - `node`: identifier of the node. + /// - `connections`: additonal nodes from which the connections are not allowed anymore. + #[weight = T::WeightInfo::remove_connections()] + pub fn remove_connections( + origin, + node: NodePublicKey, + connections: Vec + ) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + + let mut nodes = AdditionalConnections::get(&node); + + for remove_node in connections.iter() { + if let Ok(remove_location) = nodes.binary_search(&remove_node) { + nodes.remove(remove_location); + } + } - AdditionalConnections::insert(&node_public_key, nodes); + AdditionalConnections::insert(&node, nodes); - Self::deposit_event(RawEvent::ConnectionsAdded(node_public_key, connections)); + Self::deposit_event(RawEvent::ConnectionsRemoved(node, connections)); } fn offchain_worker(now: T::BlockNumber) { let node_public_key = sp_io::offchain::get_node_public_key(); match node_public_key { Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), - Ok(node) => Self::authorize_nodes(node), + Ok(node) => Self::authorize_nodes(&node), } } } } impl Module { - fn initialize_nodes(nodes: Vec<(NodePublicKey, T::AccountId)>) { + fn initialize_nodes(nodes: &Vec<(NodePublicKey, T::AccountId)>) { let mut node_public_keys = nodes.iter() .map(|item| item.0.clone()) .collect::>(); @@ -307,11 +372,11 @@ impl Module { } } - fn authorize_nodes(node: NodePublicKey) { - let mut nodes = AdditionalConnections::get(&node); + fn authorize_nodes(node: &NodePublicKey) { + let mut nodes = AdditionalConnections::get(node); let well_known_nodes = WellKnownNodes::get(); - if well_known_nodes.binary_search(&node).is_ok() { + if well_known_nodes.binary_search(node).is_ok() { nodes.extend(well_known_nodes); } @@ -319,255 +384,355 @@ impl Module { } } -// #[cfg(test)] -// mod tests { -// use super::*; - -// use frame_support::{ -// assert_ok, assert_noop, impl_outer_origin, weights::Weight, -// parameter_types, ord_parameter_types, -// }; -// use frame_system::EnsureSignedBy; -// use sp_core::{H256, ed25519::Public}; -// use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; -// use hex_literal::hex; - -// impl_outer_origin! { -// pub enum Origin for Test where system = frame_system {} -// } - -// #[derive(Clone, Eq, PartialEq)] -// pub struct Test; - -// parameter_types! { -// pub const BlockHashCount: u64 = 250; -// pub const MaximumBlockWeight: Weight = 1024; -// pub const MaximumBlockLength: u32 = 2 * 1024; -// pub const AvailableBlockRatio: Perbill = Perbill::one(); -// } -// impl frame_system::Trait for Test { -// type BaseCallFilter = (); -// type Origin = Origin; -// type Index = u64; -// type BlockNumber = u64; -// type Hash = H256; -// type Call = (); -// type Hashing = BlakeTwo256; -// type AccountId = u64; -// type Lookup = IdentityLookup; -// type Header = Header; -// type Event = (); -// type BlockHashCount = BlockHashCount; -// type MaximumBlockWeight = MaximumBlockWeight; -// type DbWeight = (); -// type BlockExecutionWeight = (); -// type ExtrinsicBaseWeight = (); -// type MaximumExtrinsicWeight = MaximumBlockWeight; -// type MaximumBlockLength = MaximumBlockLength; -// type AvailableBlockRatio = AvailableBlockRatio; -// type Version = (); -// type ModuleToIndex = (); -// type AccountData = (); -// type OnNewAccount = (); -// type OnKilledAccount = (); -// type SystemWeightInfo = (); -// } - -// ord_parameter_types! { -// pub const One: u64 = 1; -// pub const Two: u64 = 2; -// pub const Three: u64 = 3; -// pub const Four: u64 = 4; -// } -// parameter_types! { -// pub const MaxWellKnownNodes: u32 = 4; -// } -// impl Trait for Test { -// type Event = (); -// type MaxWellKnownNodes = MaxWellKnownNodes; -// type AddOrigin = EnsureSignedBy; -// type RemoveOrigin = EnsureSignedBy; -// type SwapOrigin = EnsureSignedBy; -// type ResetOrigin = EnsureSignedBy; -// type WeightInfo = (); -// } - -// type NodeAuthorization = Module; - -// fn new_test_ext() -> sp_io::TestExternalities { -// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000009") -// )); -// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000013") -// )); -// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000001d") -// )); - -// let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); -// GenesisConfig { -// nodes: vec![pub10, pub20, pub30], -// }.assimilate_storage(&mut t).unwrap(); -// t.into() -// } - -// #[test] -// fn add_node_works() { -// new_test_ext().execute_with(|| { -// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000009") -// )); -// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000000e") -// )); -// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000013") -// )); -// let pub25: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000018") -// )); -// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000001d") -// )); - -// assert_noop!(NodeAuthorization::add_well_known_node(Origin::signed(2), pub15.clone()), BadOrigin); -// assert_noop!( -// NodeAuthorization::add_well_known_node(Origin::signed(1), pub20.clone()), -// Error::::AlreadyJoined -// ); +#[cfg(test)] +mod tests { + use super::*; + + use frame_support::{ + assert_ok, assert_noop, impl_outer_origin, weights::Weight, + parameter_types, ord_parameter_types, + }; + use frame_system::EnsureSignedBy; + use sp_core::{H256, ed25519::Public}; + use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; + use hex_literal::hex; + + impl_outer_origin! { + pub enum Origin for Test where system = frame_system {} + } + + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: Weight = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl frame_system::Trait for Test { + type BaseCallFilter = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = (); + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type DbWeight = (); + type BlockExecutionWeight = (); + type ExtrinsicBaseWeight = (); + type MaximumExtrinsicWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + type ModuleToIndex = (); + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + } + + ord_parameter_types! { + pub const One: u64 = 1; + pub const Two: u64 = 2; + pub const Three: u64 = 3; + pub const Four: u64 = 4; + } + parameter_types! { + pub const MaxWellKnownNodes: u32 = 4; + } + impl Trait for Test { + type Event = (); + type MaxWellKnownNodes = MaxWellKnownNodes; + type AddOrigin = EnsureSignedBy; + type RemoveOrigin = EnsureSignedBy; + type SwapOrigin = EnsureSignedBy; + type ResetOrigin = EnsureSignedBy; + type WeightInfo = (); + } + + type NodeAuthorization = Module; + + fn test_node(id: u8) -> NodePublicKey { + let mut arr = [0u8; 32]; + arr[31] = id; + NodePublicKey::Ed25519(Public::from_raw(arr)) + } + + fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + GenesisConfig:: { + nodes: vec![(test_node(10), 10), (test_node(20), 20), (test_node(30), 30)], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + + #[test] + fn add_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), + BadOrigin + ); + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), + Error::::AlreadyJoined + ); -// assert_ok!(NodeAuthorization::add_well_known_node(Origin::signed(1), pub15.clone())); -// assert_eq!( -// NodeAuthorization::get_allow_list(), -// vec![pub10.clone(), pub15.clone(), pub20.clone(), pub30.clone()] -// ); + assert_ok!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(15), 15) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(10), test_node(15), test_node(20), test_node(30)] + ); + assert_eq!(Owners::::get(test_node(10)), 10); + assert_eq!(Owners::::get(test_node(20)), 20); + assert_eq!(Owners::::get(test_node(30)), 30); + assert_eq!(Owners::::get(test_node(15)), 15); + + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(25), 25), + Error::::TooManyNodes + ); + }); + } + + #[test] + fn remove_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), + BadOrigin + ); + assert_noop!( + NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), + Error::::NotExist + ); -// assert_noop!( -// NodeAuthorization::add_well_known_node(Origin::signed(1), pub25.clone()), -// Error::::TooManyNodes -// ); -// }); -// } - -// #[test] -// fn remove_node_works() { -// new_test_ext().execute_with(|| { -// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000009") -// )); -// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000013") -// )); -// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000001d") -// )); -// let pub40: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000027") -// )); - -// assert_noop!( -// NodeAuthorization::remove_well_known_node(Origin::signed(3), pub20.clone()), -// BadOrigin -// ); -// assert_noop!( -// NodeAuthorization::remove_well_known_node(Origin::signed(2), pub40.clone()), -// Error::::NotExist -// ); + AdditionalConnections::insert(test_node(20), vec![test_node(40)]); + assert!(AdditionalConnections::contains_key(test_node(20))); + + assert_ok!( + NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20)) + ); + assert_eq!(WellKnownNodes::get(), vec![test_node(10), test_node(30)]); + assert!(!Owners::::contains_key(test_node(20))); + assert!(!AdditionalConnections::contains_key(test_node(20))); + }); + } + + #[test] + fn swap_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(4), test_node(20), test_node(5) + ), + BadOrigin + ); -// assert_ok!(NodeAuthorization::remove_well_known_node(Origin::signed(2), pub20.clone())); -// assert_eq!(NodeAuthorization::get_allow_list(), vec![pub10.clone(), pub30.clone()]); -// }); -// } - -// #[test] -// fn swap_node_works() { -// new_test_ext().execute_with(|| { -// let pub5: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000004") -// )); -// let pub10: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000009") -// )); -// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000000e") -// )); -// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000013") -// )); -// let pub30: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000001d") -// )); + assert_ok!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(20) + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(10), test_node(20), test_node(30)] + ); + + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(15), test_node(5) + ), + Error::::NotExist + ); + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(30) + ), + Error::::AlreadyJoined + ); -// assert_noop!( -// NodeAuthorization::swap_well_known_node(Origin::signed(4), pub20.clone(), pub5.clone()), -// BadOrigin -// ); + AdditionalConnections::insert(test_node(20), vec![test_node(15)]); + assert_ok!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(5) + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(5), test_node(10), test_node(30)] + ); + assert!(!Owners::::contains_key(test_node(20))); + assert_eq!(Owners::::get(test_node(5)), 20); + assert!(!AdditionalConnections::contains_key(test_node(20))); + assert_eq!(AdditionalConnections::get(test_node(5)), vec![test_node(15)]); + }); + } + + #[test] + fn reset_well_known_nodes_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(3), + vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] + ), + BadOrigin + ); + assert_noop!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(4), + vec![ + (test_node(15), 15), + (test_node(5), 5), + (test_node(20), 20), + (test_node(25), 25), + ] + ), + Error::::TooManyNodes + ); -// assert_ok!(NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub20.clone())); -// assert_eq!( -// NodeAuthorization::get_allow_list(), -// vec![pub10.clone(), pub20.clone(), pub30.clone()] -// ); - -// assert_noop!( -// NodeAuthorization::swap_well_known_node(Origin::signed(3), pub15.clone(), pub5.clone()), -// Error::::NotExist -// ); -// assert_noop!( -// NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub30.clone()), -// Error::::AlreadyJoined -// ); + assert_ok!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(4), + vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(5), test_node(15), test_node(20)] + ); + assert_eq!(Owners::::get(test_node(5)), 5); + assert_eq!(Owners::::get(test_node(15)), 15); + assert_eq!(Owners::::get(test_node(20)), 20); + }); + } + + #[test] + fn claim_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), + Error::::AlreadyClaimed + ); -// assert_ok!(NodeAuthorization::swap_well_known_node(Origin::signed(3), pub20.clone(), pub5.clone())); -// assert_eq!( -// NodeAuthorization::get_allow_list(), -// vec![pub5.clone(), pub10.clone(), pub30.clone()] -// ); -// }); -// } - -// #[test] -// fn reset_nodes_works() { -// new_test_ext().execute_with(|| { -// let pub5: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000004") -// )); -// let pub15: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("000000000000000000000000000000000000000000000000000000000000000e") -// )); -// let pub20: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000013") -// )); -// let pub25: NodePublicKey = NodePublicKey::Ed25519(Public::from_raw( -// hex!("0000000000000000000000000000000000000000000000000000000000000018") -// )); - -// assert_noop!( -// NodeAuthorization::reset_well_known_nodes( -// Origin::signed(3), -// vec![pub15.clone(), pub5.clone(), pub20.clone()] -// ), -// BadOrigin -// ); -// assert_noop!( -// NodeAuthorization::reset_well_known_nodes( -// Origin::signed(4), -// vec![pub15.clone(), pub5.clone(), pub20.clone(), pub25.clone()] -// ), -// Error::::TooManyNodes -// ); + assert_ok!(NodeAuthorization::claim_node(Origin::signed(15), test_node(15))); + assert_eq!(Owners::::get(test_node(15)), 15); + }); + } + + #[test] + fn remove_claim_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(15), test_node(20)), + Error::::NotOwner + ); + + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(20), test_node(20)), + Error::::PermissionDenied + ); -// assert_ok!( -// NodeAuthorization::reset_well_known_nodes( -// Origin::signed(4), -// vec![pub15.clone(), pub5.clone(), pub20.clone()] -// ) -// ); -// assert_eq!( -// NodeAuthorization::get_allow_list(), -// vec![pub5.clone(), pub15.clone(), pub20.clone()] -// ); -// }); -// } -// } \ No newline at end of file + Owners::::insert(test_node(15), 15); + AdditionalConnections::insert(test_node(15), vec![test_node(20)]); + assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); + assert!(!Owners::::contains_key(test_node(15))); + assert!(!AdditionalConnections::contains_key(test_node(15))); + }); + } + + #[test] + fn transfer_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::transfer_node(Origin::signed(15), test_node(20), 10), + Error::::NotOwner + ); + + assert_ok!(NodeAuthorization::transfer_node(Origin::signed(20), test_node(20), 15)); + assert_eq!(Owners::::get(test_node(20)), 15); + }); + } + + #[test] + fn add_connections_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::add_connections( + Origin::signed(15), test_node(15), vec![test_node(5)] + ), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::add_connections( + Origin::signed(15), test_node(20), vec![test_node(5)] + ), + Error::::NotOwner + ); + + assert_ok!( + NodeAuthorization::add_connections( + Origin::signed(20), + test_node(20), + vec![test_node(15), test_node(5), test_node(25)] + ) + ); + assert_eq!( + AdditionalConnections::get(test_node(20)), + vec![test_node(5), test_node(15), test_node(25)] + ); + }); + } + + #[test] + fn remove_connections_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_connections( + Origin::signed(15), test_node(15), vec![test_node(5)] + ), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::remove_connections( + Origin::signed(15), test_node(20), vec![test_node(5)] + ), + Error::::NotOwner + ); + + AdditionalConnections::insert( + test_node(20), vec![test_node(5), test_node(15), test_node(25)] + ); + assert_ok!( + NodeAuthorization::remove_connections( + Origin::signed(20), + test_node(20), + vec![test_node(15), test_node(5)] + ) + ); + assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); + }); + } +} \ No newline at end of file From 27152b9fab41f1bbe39b5776c697b3c73ab9a89b Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Mon, 31 Aug 2020 14:22:09 +0800 Subject: [PATCH 09/34] remove dependency --- Cargo.lock | 54 +++++++++-------------------- frame/node-authorization/Cargo.toml | 4 +-- frame/node-authorization/src/lib.rs | 1 - 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b2e50950ce551..cbce10b495754 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "linregress", "parity-scale-codec", "paste", @@ -1604,7 +1604,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "pallet-indices", "pallet-transaction-payment", @@ -2228,31 +2228,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -[[package]] -name = "hex-literal" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] - [[package]] name = "hex-literal" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" -[[package]] -name = "hex-literal-impl" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" -dependencies = [ - "proc-macro-hack", -] - [[package]] name = "hex_fmt" version = "0.3.0" @@ -3740,7 +3721,7 @@ dependencies = [ "frame-support", "frame-system", "futures 0.3.5", - "hex-literal 0.3.1", + "hex-literal", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -3756,7 +3737,6 @@ dependencies = [ "pallet-grandpa", "pallet-im-online", "pallet-indices", - "pallet-node-authorization", "pallet-staking", "pallet-timestamp", "pallet-transaction-payment", @@ -3923,7 +3903,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal 0.3.1", + "hex-literal", "integer-sqrt", "node-primitives", "pallet-authority-discovery", @@ -3943,7 +3923,6 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-multisig", - "pallet-node-authorization", "pallet-offences", "pallet-offences-benchmarking", "pallet-proxy", @@ -4408,7 +4387,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "parity-scale-codec", "serde", @@ -4427,7 +4406,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "pallet-contracts-primitives", "pallet-randomness-collective-flip", @@ -4492,7 +4471,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "pallet-scheduler", "parity-scale-codec", @@ -4511,7 +4490,7 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "parity-scale-codec", "serde", @@ -4528,7 +4507,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "parity-scale-codec", "serde", @@ -4757,7 +4736,6 @@ version = "2.0.0-rc6" dependencies = [ "frame-support", "frame-system", - "hex-literal 0.2.1", "parity-scale-codec", "serde", "sp-core", @@ -5139,7 +5117,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex-literal 0.3.1", + "hex-literal", "pallet-balances", "parity-scale-codec", "serde", @@ -6438,7 +6416,7 @@ dependencies = [ "fnv", "futures 0.3.5", "hash-db", - "hex-literal 0.3.1", + "hex-literal", "kvdb", "kvdb-memorydb", "lazy_static", @@ -6736,7 +6714,7 @@ version = "0.8.0-rc6" dependencies = [ "assert_matches", "derive_more", - "hex-literal 0.3.1", + "hex-literal", "lazy_static", "libsecp256k1", "log", @@ -7264,7 +7242,7 @@ dependencies = [ "fdlimit", "futures 0.1.29", "futures 0.3.5", - "hex-literal 0.3.1", + "hex-literal", "log", "parity-scale-codec", "parking_lot 0.10.2", @@ -8076,7 +8054,7 @@ dependencies = [ "hash-db", "hash256-std-hasher", "hex", - "hex-literal 0.3.1", + "hex-literal", "impl-serde", "lazy_static", "libsecp256k1", @@ -8404,7 +8382,7 @@ name = "sp-state-machine" version = "0.8.0-rc6" dependencies = [ "hash-db", - "hex-literal 0.3.1", + "hex-literal", "itertools 0.9.0", "log", "num-traits", @@ -8492,7 +8470,7 @@ version = "2.0.0-rc6" dependencies = [ "criterion", "hash-db", - "hex-literal 0.3.1", + "hex-literal", "memory-db", "parity-scale-codec", "sp-core", diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 4931ca7d60b4d..943b128f23d86 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -18,11 +18,10 @@ frame-support = { version = "2.0.0-rc6", default-features = false, path = "../su frame-system = { version = "2.0.0-rc6", default-features = false, path = "../system" } sp-core = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/core" } sp-io = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } [dev-dependencies] -hex-literal = "0.2.1" +sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } [features] default = ["std"] @@ -33,6 +32,5 @@ std = [ "frame-system/std", "sp-core/std", "sp-io/std", - "sp-runtime/std", "sp-std/std", ] \ No newline at end of file diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 31fd93062055e..98a4c7abbd9ab 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -395,7 +395,6 @@ mod tests { use frame_system::EnsureSignedBy; use sp_core::{H256, ed25519::Public}; use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; - use hex_literal::hex; impl_outer_origin! { pub enum Origin for Test where system = frame_system {} From acbc8d6ebf70511a01d0fb67a6c1bb21e5696893 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 1 Sep 2020 00:14:26 +0800 Subject: [PATCH 10/34] fix build --- .../authority-discovery/src/worker/tests.rs | 16 +++++++ client/network/src/lib.rs | 2 +- client/offchain/src/api.rs | 30 ++++++++---- client/offchain/src/lib.rs | 17 ++++++- frame/node-authorization/Cargo.toml | 2 +- frame/node-authorization/src/lib.rs | 47 ++++++++++--------- 6 files changed, 80 insertions(+), 34 deletions(-) diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index baa6bd0fc7d62..851adaaa540fe 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -28,6 +28,8 @@ use futures::task::LocalSpawn; use futures::poll; use libp2p::{kad, core::multiaddr, PeerId}; +use sc_network::config::identity; +use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; use sp_api::{ProvideRuntimeApi, ApiRef}; use sp_core::{crypto::Public, testing::KeyStore}; use sp_runtime::traits::{Zero, Block as BlockT, NumberFor}; @@ -219,6 +221,20 @@ impl NetworkStateInfo for TestNetwork { fn external_addresses(&self) -> Vec { self.external_addresses.clone() } + + fn local_public_key(&self) -> identity::PublicKey { + identity::Keypair::generate_ed25519().public() + } + + fn peerset(&self) -> PeersetHandle { + Peerset::from_config(PeersetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: vec![], + reserved_only: false, + priority_groups: vec![], + }).1 + } } #[test] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index a3671986141b4..d90fc24fa824c 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -272,9 +272,9 @@ pub use libp2p::{Multiaddr, PeerId}; pub use libp2p::multiaddr; pub use sc_peerset::ReputationChange; +use config::identity::PublicKey; use sc_peerset::PeersetHandle; use sp_runtime::traits::{Block as BlockT, NumberFor}; -use config::identity::PublicKey; /// The maximum allowed number of established connections per peer. /// diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 347002f5402bf..78a407d4cac13 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -25,11 +25,7 @@ use std::{ use sp_core::offchain::OffchainStorage; use futures::Future; use log::error; -use sc_network::{PeerId, Multiaddr, NetworkStateInfo}; -use sc_network::config::identity::{ - ed25519::PublicKey as Ed25519PeerPublicKey, - PublicKey as PeerPublicKey -}; +use sc_network::{config::identity, PeerId, Multiaddr, NetworkStateInfo}; use codec::{Encode, Decode}; use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, @@ -190,7 +186,8 @@ impl OffchainExt for Api { fn get_node_public_key(&mut self) -> Result { let public_key = self.network_state.local_public_key(); match public_key { - PeerPublicKey::Ed25519(public) => Ok(public.encode().into()), + identity::PublicKey::Ed25519(public) => + Ok(public.encode().into()), _ => Err(()), } } @@ -200,11 +197,11 @@ impl OffchainExt for Api { .filter_map(|node| match node { NodePublicKey::Ed25519(public) => - Ed25519PeerPublicKey::decode(&public.0).ok() + identity::ed25519::PublicKey::decode(&public.0).ok() } ) .map(|public| - PeerPublicKey::Ed25519(public).into_peer_id() + identity::PublicKey::Ed25519(public).into_peer_id() ) .collect(); @@ -212,7 +209,6 @@ impl OffchainExt for Api { let peerset = self.network_state.peerset(); peerset.set_reserved_peers(peer_ids); - // Respect reserved peers from runtime, ignore CLI flags for now. peerset.set_reserved_only(reserved_only); } } @@ -327,7 +323,7 @@ mod tests { use super::*; use std::{convert::{TryFrom, TryInto}, time::SystemTime}; use sc_client_db::offchain::LocalStorage; - use sc_network::PeerId; + use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; struct MockNetworkStateInfo(); @@ -339,6 +335,20 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } + + fn local_public_key(&self) -> identity::PublicKey { + identity::Keypair::generate_ed25519().public() + } + + fn peerset(&self) -> PeersetHandle { + Peerset::from_config(PeersetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: vec![], + reserved_only: false, + priority_groups: vec![], + }).1 + } } fn offchain_api() -> (Api, AsyncApi) { diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 3b17c14f19652..aa78468884a30 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -208,7 +208,8 @@ pub async fn notification_future( mod tests { use super::*; use std::sync::Arc; - use sc_network::{Multiaddr, PeerId}; + use sc_network::{Multiaddr, PeerId, config::identity}; + use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; use substrate_test_runtime_client::{TestClient, runtime::Block}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_transaction_pool::{TransactionPool, InPoolTransaction}; @@ -223,6 +224,20 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } + + fn local_public_key(&self) -> identity::PublicKey { + identity::Keypair::generate_ed25519().public() + } + + fn peerset(&self) -> PeersetHandle { + Peerset::from_config(PeersetConfig { + in_peers: 25, + out_peers: 25, + bootnodes: vec![], + reserved_only: false, + priority_groups: vec![], + }).1 + } } struct TestPool( diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 943b128f23d86..02e49e7d5677e 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -33,4 +33,4 @@ std = [ "sp-core/std", "sp-io/std", "sp-std/std", -] \ No newline at end of file +] diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 98a4c7abbd9ab..cab142e69f654 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -19,14 +19,17 @@ //! //! This pallet manages a configurable set of nodes for a permissioned network. //! It provides two ways to authorize a node, -//! * a set of well known nodes across different organizations in which the +//! +//! - a set of well known nodes across different organizations in which the //! connections are allowed. -//! * users can claim the ownership for each node, then manage the connection of the node. +//! - users can claim the ownership for each node, then manage the connections of +//! the node. //! -//! A node must have an owner. The owner can make additional adaptive change for -//! the connection of the node. Only one user can `claim` a specific node. -//! To eliminate false claim, the maintainer of the node should claim it before -//! even start the node. +//! A node must have an owner. The owner can additionally change the connections +//! for the node. Only one user is allowed to claim a specific node. To eliminate +//! false claim, the maintainer of the node should claim it before even start the +//! node. This pallet use offchain work to set reserved nodes, if the node is not +//! an authority, make sure to enable offchain worker with the right CLI flag. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] @@ -95,7 +98,7 @@ decl_storage! { /// A map that maintains the ownership of each node. pub Owners get(fn owners): map hasher(blake2_128_concat) NodePublicKey => T::AccountId; - /// The additional adapative connections of a node. + /// The additional adapative connections of each node. pub AdditionalConnections get(fn additional_connection): map hasher(blake2_128_concat) NodePublicKey => Vec; } @@ -115,14 +118,14 @@ decl_event! { NodeAdded(NodePublicKey, AccountId), /// The given well known node was removed. NodeRemoved(NodePublicKey), - /// Two given well known node were swapped; first item is removed, - /// the latter is added. + /// The given well known node was swapped; first item was removed, + /// the latter was added. NodeSwapped(NodePublicKey, NodePublicKey), /// The given well known nodes were reset. NodesReset(Vec<(NodePublicKey, AccountId)>), /// The given node was claimed by a user. NodeClaimed(NodePublicKey, AccountId), - /// The given claim was remove by its owner. + /// The given claim was removed by its owner. ClaimRemoved(NodePublicKey, AccountId), /// The node was transferred to another account. NodeTransferred(NodePublicKey, AccountId, AccountId), @@ -206,7 +209,7 @@ decl_module! { Self::deposit_event(RawEvent::NodeRemoved(node)); } - /// Swap one well know node to another. Both the ownership and additonal connections + /// Swap a well known node to another. Both the ownership and additional connections /// stay untouched. /// /// May only be called from `T::SwapOrigin`. @@ -233,7 +236,7 @@ decl_module! { } /// Reset all the well known nodes. This will not remove the ownership and additional - /// connections for the removed nodes. The node owner can perform furthur cleaning if + /// connections for the removed nodes. The node owner can perform further cleaning if /// they decide to leave the network. /// /// May only be called from `T::ResetOrigin`. @@ -349,6 +352,8 @@ decl_module! { Self::deposit_event(RawEvent::ConnectionsRemoved(node, connections)); } + /// Set reserved node every block. If may not be enabled depends on the offchain + /// worker CLI flag. fn offchain_worker(now: T::BlockNumber) { let node_public_key = sp_io::offchain::get_node_public_key(); match node_public_key { @@ -408,8 +413,8 @@ mod tests { pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - impl frame_system::Trait for Test { + } + impl frame_system::Trait for Test { type BaseCallFilter = (); type Origin = Origin; type Index = u64; @@ -434,15 +439,15 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); - type SystemWeightInfo = (); - } - + type SystemWeightInfo = (); + } + ord_parameter_types! { pub const One: u64 = 1; pub const Two: u64 = 2; pub const Three: u64 = 3; - pub const Four: u64 = 4; - } + pub const Four: u64 = 4; + } parameter_types! { pub const MaxWellKnownNodes: u32 = 4; } @@ -455,7 +460,7 @@ mod tests { type ResetOrigin = EnsureSignedBy; type WeightInfo = (); } - + type NodeAuthorization = Module; fn test_node(id: u8) -> NodePublicKey { @@ -734,4 +739,4 @@ mod tests { assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); }); } -} \ No newline at end of file +} From d4e5ae8d166d41e83ab4c7581b3f68b41e62375e Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 1 Sep 2020 10:02:50 +0800 Subject: [PATCH 11/34] more tests. --- client/offchain/src/api.rs | 12 +++++++-- frame/node-authorization/src/lib.rs | 35 +++++++++++++++++++------ primitives/core/src/offchain/mod.rs | 6 +++-- primitives/core/src/offchain/testing.rs | 3 +-- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 78a407d4cac13..5ef6aed5b2246 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -205,8 +205,6 @@ impl OffchainExt for Api { ) .collect(); - peer_ids.remove(&self.network_state.local_peer_id()); - let peerset = self.network_state.peerset(); peerset.set_reserved_peers(peer_ids); peerset.set_reserved_only(reserved_only); @@ -474,4 +472,14 @@ mod tests { // then assert_ne!(seed, [0; 32]); } + + #[test] + fn should_get_node_public_key() { + // given + let mut api = offchain_api().0; + let node_public_key = api.get_node_public_key(); + + // then + assert!(node_public_key.is_ok()); + } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index cab142e69f654..d66ec80b5fe52 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -315,7 +315,10 @@ decl_module! { let mut nodes = AdditionalConnections::get(&node); for add_node in connections.iter() { - if let Err(add_location) = nodes.binary_search(&add_node) { + if *add_node == node { + continue; + } + if let Err(add_location) = nodes.binary_search(add_node) { nodes.insert(add_location, add_node.clone()); } } @@ -342,7 +345,7 @@ decl_module! { let mut nodes = AdditionalConnections::get(&node); for remove_node in connections.iter() { - if let Ok(remove_location) = nodes.binary_search(&remove_node) { + if let Ok(remove_location) = nodes.binary_search(remove_node) { nodes.remove(remove_location); } } @@ -358,7 +361,9 @@ decl_module! { let node_public_key = sp_io::offchain::get_node_public_key(); match node_public_key { Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), - Ok(node) => Self::authorize_nodes(&node), + Ok(node) => sp_io::offchain::set_reserved_nodes( + Self::get_authorized_nodes(&node), true + ), } } } @@ -377,15 +382,16 @@ impl Module { } } - fn authorize_nodes(node: &NodePublicKey) { + fn get_authorized_nodes(node: &NodePublicKey) -> Vec { let mut nodes = AdditionalConnections::get(node); - let well_known_nodes = WellKnownNodes::get(); - if well_known_nodes.binary_search(node).is_ok() { + let mut well_known_nodes = WellKnownNodes::get(); + if let Ok(location) = well_known_nodes.binary_search(node) { + well_known_nodes.remove(location); nodes.extend(well_known_nodes); } - sp_io::offchain::set_reserved_nodes(nodes, true) + nodes } } @@ -699,7 +705,7 @@ mod tests { NodeAuthorization::add_connections( Origin::signed(20), test_node(20), - vec![test_node(15), test_node(5), test_node(25)] + vec![test_node(15), test_node(5), test_node(25), test_node(20)] ) ); assert_eq!( @@ -739,4 +745,17 @@ mod tests { assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); }); } + + #[test] + fn get_authorize_nodes_worker() { + new_test_ext().execute_with(|| { + AdditionalConnections::insert( + test_node(20), vec![test_node(5), test_node(15), test_node(25)] + ); + assert_eq!( + Module::::get_authorized_nodes(&test_node(20)), + vec![test_node(5), test_node(15), test_node(25), test_node(10), test_node(30)] + ); + }); + } } diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 094a7de3cf395..3931ecfb3ae6f 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -277,6 +277,8 @@ pub enum Capability { OffchainWorkerDbRead = 32, /// Access to offchain worker DB (writes). OffchainWorkerDbWrite = 64, + /// Manage the reserved nodes + NodesReservation = 128, } /// A set of capabilities @@ -707,12 +709,12 @@ impl Externalities for LimitedExternalities { } fn get_node_public_key(&mut self) -> Result { - self.check(Capability::NetworkState, "get_node_public_key"); + self.check(Capability::NodesReservation, "get_node_public_key"); self.externalities.get_node_public_key() } fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { - self.check(Capability::NetworkState, "set_reserved_nodes"); + self.check(Capability::NodesReservation, "set_reserved_nodes"); self.externalities.set_reserved_nodes(nodes, reserved_only) } } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 594d3f95dc25e..603bb55464e76 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -381,8 +381,7 @@ impl offchain::Externalities for TestOffchainExt { Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) } - fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { - } + fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) {} } /// The internal state of the fake transaction pool. From 7e2a026093b2a80ca53eb5663f34aed70c291def Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 1 Sep 2020 10:09:20 +0800 Subject: [PATCH 12/34] refactor --- client/offchain/src/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 5ef6aed5b2246..7acb6e71818b3 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -193,7 +193,7 @@ impl OffchainExt for Api { } fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { - let mut peer_ids: HashSet = nodes.iter() + let peer_ids: HashSet = nodes.iter() .filter_map(|node| match node { NodePublicKey::Ed25519(public) => From 03ab075872e15eb6fac6ce5da718d3a056c9a0b6 Mon Sep 17 00:00:00 2001 From: kaichao Date: Tue, 1 Sep 2020 17:15:52 +0800 Subject: [PATCH 13/34] Update primitives/core/src/offchain/testing.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Drwięga --- primitives/core/src/offchain/testing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 603bb55464e76..3ba11fdb3e841 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -381,7 +381,7 @@ impl offchain::Externalities for TestOffchainExt { Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) } - fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) {} + fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { unimplemented!() } } /// The internal state of the fake transaction pool. From 6d659f5a056a475b39582656951b53c9fdc88876 Mon Sep 17 00:00:00 2001 From: kaichao Date: Tue, 1 Sep 2020 17:16:12 +0800 Subject: [PATCH 14/34] Update frame/node-authorization/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Drwięga --- frame/node-authorization/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index d66ec80b5fe52..b4d54b7195e8c 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -27,7 +27,7 @@ //! //! A node must have an owner. The owner can additionally change the connections //! for the node. Only one user is allowed to claim a specific node. To eliminate -//! false claim, the maintainer of the node should claim it before even start the +//! false claim, the maintainer of the node should claim it before even starting the //! node. This pallet use offchain work to set reserved nodes, if the node is not //! an authority, make sure to enable offchain worker with the right CLI flag. From 0c325fee284b09a5b68975a387ab6ea909ab4e1e Mon Sep 17 00:00:00 2001 From: kaichao Date: Tue, 1 Sep 2020 17:16:33 +0800 Subject: [PATCH 15/34] Update frame/node-authorization/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Drwięga --- frame/node-authorization/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index b4d54b7195e8c..e1fe8d09db09c 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -28,7 +28,7 @@ //! A node must have an owner. The owner can additionally change the connections //! for the node. Only one user is allowed to claim a specific node. To eliminate //! false claim, the maintainer of the node should claim it before even starting the -//! node. This pallet use offchain work to set reserved nodes, if the node is not +//! node. This pallet uses offchain worker to set reserved nodes, if the node is not //! an authority, make sure to enable offchain worker with the right CLI flag. // Ensure we're `no_std` when compiling for Wasm. From 5cc6ae132fa403df134cbb18a4ae078787ac9129 Mon Sep 17 00:00:00 2001 From: kaichao Date: Tue, 1 Sep 2020 17:26:31 +0800 Subject: [PATCH 16/34] Update frame/node-authorization/src/lib.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tomasz Drwięga --- frame/node-authorization/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index e1fe8d09db09c..752dd99bf5ebc 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -259,7 +259,7 @@ decl_module! { #[weight = T::WeightInfo::claim_node()] pub fn claim_node(origin, node: NodePublicKey) { let sender = ensure_signed(origin)?; - ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); + ensure!(!Owners::::contains_key(&node), Error::::AlreadyClaimed); Owners::::insert(&node, &sender); Self::deposit_event(RawEvent::NodeClaimed(node, sender)); From 4c269a5b609033eac6d42ae5432ac5b89f0b9091 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 1 Sep 2020 21:39:02 +0800 Subject: [PATCH 17/34] format code --- client/offchain/src/api.rs | 4 +- frame/node-authorization/src/lib.rs | 1300 +++++++++++------------ primitives/core/src/crypto.rs | 7 - primitives/core/src/offchain/testing.rs | 4 +- 4 files changed, 655 insertions(+), 660 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 7acb6e71818b3..dcd1fcde6395d 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -31,7 +31,7 @@ use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use sp_core::NodePublicKey; +use sp_core::{NodePublicKey, ed25519}; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -187,7 +187,7 @@ impl OffchainExt for Api { let public_key = self.network_state.local_public_key(); match public_key { identity::PublicKey::Ed25519(public) => - Ok(public.encode().into()), + Ok(NodePublicKey::Ed25519(ed25519::Public(public.encode()))), _ => Err(()), } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 752dd99bf5ebc..44112dba21f41 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -37,390 +37,390 @@ use sp_std::prelude::*; use sp_core::NodePublicKey; use frame_support::{ - decl_module, decl_storage, decl_event, decl_error, - debug, ensure, - weights::{DispatchClass, Weight}, - traits::{Get, EnsureOrigin}, + decl_module, decl_storage, decl_event, decl_error, + debug, ensure, + weights::{DispatchClass, Weight}, + traits::{Get, EnsureOrigin}, }; use frame_system::ensure_signed; pub trait WeightInfo { - fn add_well_known_node() -> Weight; - fn remove_well_known_node() -> Weight; - fn swap_well_known_node() -> Weight; - fn reset_well_known_nodes() -> Weight; - fn claim_node() -> Weight; - fn remove_claim() -> Weight; - fn transfer_node() -> Weight; - fn add_connections() -> Weight; - fn remove_connections() -> Weight; + fn add_well_known_node() -> Weight; + fn remove_well_known_node() -> Weight; + fn swap_well_known_node() -> Weight; + fn reset_well_known_nodes() -> Weight; + fn claim_node() -> Weight; + fn remove_claim() -> Weight; + fn transfer_node() -> Weight; + fn add_connections() -> Weight; + fn remove_connections() -> Weight; } impl WeightInfo for () { - fn add_well_known_node() -> Weight { 50_000_000 } - fn remove_well_known_node() -> Weight { 50_000_000 } - fn swap_well_known_node() -> Weight { 50_000_000 } - fn reset_well_known_nodes() -> Weight { 50_000_000 } - fn claim_node() -> Weight { 50_000_000 } - fn remove_claim() -> Weight { 50_000_000 } - fn transfer_node() -> Weight { 50_000_000 } - fn add_connections() -> Weight { 50_000_000 } - fn remove_connections() -> Weight { 50_000_000 } + fn add_well_known_node() -> Weight { 50_000_000 } + fn remove_well_known_node() -> Weight { 50_000_000 } + fn swap_well_known_node() -> Weight { 50_000_000 } + fn reset_well_known_nodes() -> Weight { 50_000_000 } + fn claim_node() -> Weight { 50_000_000 } + fn remove_claim() -> Weight { 50_000_000 } + fn transfer_node() -> Weight { 50_000_000 } + fn add_connections() -> Weight { 50_000_000 } + fn remove_connections() -> Weight { 50_000_000 } } pub trait Trait: frame_system::Trait { - /// The event type of this module. + /// The event type of this module. type Event: From> + Into<::Event>; - /// The maximum number of well known nodes that are allowed to set - type MaxWellKnownNodes: Get; + /// The maximum number of well known nodes that are allowed to set + type MaxWellKnownNodes: Get; - /// The origin which can add a well known node. - type AddOrigin: EnsureOrigin; + /// The origin which can add a well known node. + type AddOrigin: EnsureOrigin; - /// The origin which can remove a well known node. - type RemoveOrigin: EnsureOrigin; + /// The origin which can remove a well known node. + type RemoveOrigin: EnsureOrigin; - /// The origin which can swap the well known nodes. - type SwapOrigin: EnsureOrigin; + /// The origin which can swap the well known nodes. + type SwapOrigin: EnsureOrigin; - /// The origin which can reset the well known nodes. - type ResetOrigin: EnsureOrigin; + /// The origin which can reset the well known nodes. + type ResetOrigin: EnsureOrigin; - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } decl_storage! { - trait Store for Module as NodeAuthorization { - /// The set of well known nodes. This is stored sorted (just by value). - pub WellKnownNodes get(fn well_known_nodes): Vec; - /// A map that maintains the ownership of each node. - pub Owners get(fn owners): - map hasher(blake2_128_concat) NodePublicKey => T::AccountId; - /// The additional adapative connections of each node. - pub AdditionalConnections get(fn additional_connection): - map hasher(blake2_128_concat) NodePublicKey => Vec; - } - add_extra_genesis { - config(nodes): Vec<(NodePublicKey, T::AccountId)>; - build(|config: &GenesisConfig| { - >::initialize_nodes(&config.nodes) - }) - } + trait Store for Module as NodeAuthorization { + /// The set of well known nodes. This is stored sorted (just by value). + pub WellKnownNodes get(fn well_known_nodes): Vec; + /// A map that maintains the ownership of each node. + pub Owners get(fn owners): + map hasher(blake2_128_concat) NodePublicKey => T::AccountId; + /// The additional adapative connections of each node. + pub AdditionalConnections get(fn additional_connection): + map hasher(blake2_128_concat) NodePublicKey => Vec; + } + add_extra_genesis { + config(nodes): Vec<(NodePublicKey, T::AccountId)>; + build(|config: &GenesisConfig| { + >::initialize_nodes(&config.nodes) + }) + } } decl_event! { - pub enum Event where - ::AccountId, - { - /// The given well known node was added. - NodeAdded(NodePublicKey, AccountId), - /// The given well known node was removed. - NodeRemoved(NodePublicKey), - /// The given well known node was swapped; first item was removed, - /// the latter was added. - NodeSwapped(NodePublicKey, NodePublicKey), - /// The given well known nodes were reset. - NodesReset(Vec<(NodePublicKey, AccountId)>), - /// The given node was claimed by a user. - NodeClaimed(NodePublicKey, AccountId), - /// The given claim was removed by its owner. - ClaimRemoved(NodePublicKey, AccountId), - /// The node was transferred to another account. - NodeTransferred(NodePublicKey, AccountId, AccountId), - /// The allowed connections were added to a node. - ConnectionsAdded(NodePublicKey, Vec), - /// The allowed connections were removed from a node. - ConnectionsRemoved(NodePublicKey, Vec), - } + pub enum Event where + ::AccountId, + { + /// The given well known node was added. + NodeAdded(NodePublicKey, AccountId), + /// The given well known node was removed. + NodeRemoved(NodePublicKey), + /// The given well known node was swapped; first item was removed, + /// the latter was added. + NodeSwapped(NodePublicKey, NodePublicKey), + /// The given well known nodes were reset. + NodesReset(Vec<(NodePublicKey, AccountId)>), + /// The given node was claimed by a user. + NodeClaimed(NodePublicKey, AccountId), + /// The given claim was removed by its owner. + ClaimRemoved(NodePublicKey, AccountId), + /// The node was transferred to another account. + NodeTransferred(NodePublicKey, AccountId, AccountId), + /// The allowed connections were added to a node. + ConnectionsAdded(NodePublicKey, Vec), + /// The allowed connections were removed from a node. + ConnectionsRemoved(NodePublicKey, Vec), + } } decl_error! { - /// Error for the node authorization module. - pub enum Error for Module { - /// Too many well known nodes. - TooManyNodes, - /// The node is already joined in the list. - AlreadyJoined, - /// The node doesn't exist in the list. - NotExist, - /// The node is already claimed by a user. - AlreadyClaimed, - /// The node hasn't been claimed yet. - NotClaimed, - /// You are not the owner of the node. - NotOwner, - /// No permisson to perform specific operation. - PermissionDenied, - } + /// Error for the node authorization module. + pub enum Error for Module { + /// Too many well known nodes. + TooManyNodes, + /// The node is already joined in the list. + AlreadyJoined, + /// The node doesn't exist in the list. + NotExist, + /// The node is already claimed by a user. + AlreadyClaimed, + /// The node hasn't been claimed yet. + NotClaimed, + /// You are not the owner of the node. + NotOwner, + /// No permisson to perform specific operation. + PermissionDenied, + } } decl_module! { - pub struct Module for enum Call where origin: T::Origin { - /// The maximum number of authorized well known nodes - const MaxWellKnownNodes: u32 = T::MaxWellKnownNodes::get(); - - type Error = Error; - - fn deposit_event() = default; - - /// Add a node to the set of well known nodes. If the node is already claimed, the owner - /// will be updated and keep the existing additional connection unchanged. - /// - /// May only be called from `T::AddOrigin`. - /// - /// - `node`: identifier of the node. - #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] - pub fn add_well_known_node(origin, node: NodePublicKey, owner: T::AccountId) { - T::AddOrigin::ensure_origin(origin)?; - - let mut nodes = WellKnownNodes::get(); - ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - - let location = nodes.binary_search(&node).err().ok_or(Error::::AlreadyJoined)?; - nodes.insert(location, node.clone()); - - WellKnownNodes::put(&nodes); - >::insert(&node, &owner); - - Self::deposit_event(RawEvent::NodeAdded(node, owner)); - } - - /// Remove a node from the set of well known nodes. The ownership and additional - /// connections of the node will also be removed. - /// - /// May only be called from `T::RemoveOrigin`. - /// - /// - `node`: identifier of the node. - #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] - pub fn remove_well_known_node(origin, node: NodePublicKey) { - T::RemoveOrigin::ensure_origin(origin)?; - - let mut nodes = WellKnownNodes::get(); - - let location = nodes.binary_search(&node).ok().ok_or(Error::::NotExist)?; - nodes.remove(location); - - WellKnownNodes::put(&nodes); - >::remove(&node); - AdditionalConnections::remove(&node); - - Self::deposit_event(RawEvent::NodeRemoved(node)); - } - - /// Swap a well known node to another. Both the ownership and additional connections - /// stay untouched. - /// - /// May only be called from `T::SwapOrigin`. - /// - /// - `remove`: the node which will be moved out from the list. - /// - `add`: the node which will be put in the list. - #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] - pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { - T::SwapOrigin::ensure_origin(origin)?; - - if remove == add { return Ok(()) } - - let mut nodes = WellKnownNodes::get(); - let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; - nodes.remove(remove_location); - let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; - nodes.insert(add_location, add.clone()); - - WellKnownNodes::put(&nodes); - Owners::::swap(&remove, &add); - AdditionalConnections::swap(&remove, &add); - - Self::deposit_event(RawEvent::NodeSwapped(remove, add)); - } - - /// Reset all the well known nodes. This will not remove the ownership and additional - /// connections for the removed nodes. The node owner can perform further cleaning if - /// they decide to leave the network. - /// - /// May only be called from `T::ResetOrigin`. - /// - /// - `nodes`: the new nodes for the allow list. - #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] - pub fn reset_well_known_nodes(origin, nodes: Vec<(NodePublicKey, T::AccountId)>) { - T::ResetOrigin::ensure_origin(origin)?; - ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - - Self::initialize_nodes(&nodes); - - Self::deposit_event(RawEvent::NodesReset(nodes)); - } - - /// A given node can be claimed by anyone. The owner should be the first to know its - /// public key, so claim it right away! - /// - /// - `node`: identifier of the node. - #[weight = T::WeightInfo::claim_node()] - pub fn claim_node(origin, node: NodePublicKey) { - let sender = ensure_signed(origin)?; - ensure!(!Owners::::contains_key(&node), Error::::AlreadyClaimed); - - Owners::::insert(&node, &sender); - Self::deposit_event(RawEvent::NodeClaimed(node, sender)); - } - - /// A claim can be removed by its owner and get back the reservation. The additional - /// connections are also removed. You can't remove a claim on well known nodes, as it - /// needs to reach consensus among the network participants. - /// - /// - `node`: identifier of the node. - #[weight = T::WeightInfo::remove_claim()] - pub fn remove_claim(origin, node: NodePublicKey) { - let sender = ensure_signed(origin)?; - ensure!(Owners::::contains_key(&node), Error::::NotClaimed); - ensure!(Owners::::get(&node) == sender, Error::::NotOwner); - ensure!(!WellKnownNodes::get().contains(&node), Error::::PermissionDenied); - - Owners::::remove(&node); - AdditionalConnections::remove(&node); - - Self::deposit_event(RawEvent::ClaimRemoved(node, sender)); - } - - /// A node can be transferred to a new owner. - /// - /// - `node`: identifier of the node. - /// - `owner`: new owner of the node. - #[weight = T::WeightInfo::transfer_node()] - pub fn transfer_node(origin, node: NodePublicKey, owner: T::AccountId) { - let sender = ensure_signed(origin)?; - ensure!(Owners::::contains_key(&node), Error::::NotClaimed); - ensure!(Owners::::get(&node) == sender, Error::::NotOwner); - - Owners::::insert(&node, &owner); - - Self::deposit_event(RawEvent::NodeTransferred(node, sender, owner)); - } - - /// Add additional connections to a given node. - /// - /// - `node`: identifier of the node. - /// - `connections`: additonal nodes from which the connections are allowed. - #[weight = T::WeightInfo::add_connections()] - pub fn add_connections( - origin, - node: NodePublicKey, - connections: Vec - ) { - let sender = ensure_signed(origin)?; - ensure!(Owners::::contains_key(&node), Error::::NotClaimed); - ensure!(Owners::::get(&node) == sender, Error::::NotOwner); - - let mut nodes = AdditionalConnections::get(&node); - - for add_node in connections.iter() { - if *add_node == node { - continue; - } - if let Err(add_location) = nodes.binary_search(add_node) { - nodes.insert(add_location, add_node.clone()); - } - } - - AdditionalConnections::insert(&node, nodes); - - Self::deposit_event(RawEvent::ConnectionsAdded(node, connections)); - } - - /// Remove additional connections of a given node. - /// - /// - `node`: identifier of the node. - /// - `connections`: additonal nodes from which the connections are not allowed anymore. - #[weight = T::WeightInfo::remove_connections()] - pub fn remove_connections( - origin, - node: NodePublicKey, - connections: Vec - ) { - let sender = ensure_signed(origin)?; - ensure!(Owners::::contains_key(&node), Error::::NotClaimed); - ensure!(Owners::::get(&node) == sender, Error::::NotOwner); - - let mut nodes = AdditionalConnections::get(&node); - - for remove_node in connections.iter() { - if let Ok(remove_location) = nodes.binary_search(remove_node) { - nodes.remove(remove_location); - } - } - - AdditionalConnections::insert(&node, nodes); - - Self::deposit_event(RawEvent::ConnectionsRemoved(node, connections)); - } - - /// Set reserved node every block. If may not be enabled depends on the offchain - /// worker CLI flag. - fn offchain_worker(now: T::BlockNumber) { - let node_public_key = sp_io::offchain::get_node_public_key(); - match node_public_key { - Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), - Ok(node) => sp_io::offchain::set_reserved_nodes( - Self::get_authorized_nodes(&node), true - ), - } - } - } + pub struct Module for enum Call where origin: T::Origin { + /// The maximum number of authorized well known nodes + const MaxWellKnownNodes: u32 = T::MaxWellKnownNodes::get(); + + type Error = Error; + + fn deposit_event() = default; + + /// Add a node to the set of well known nodes. If the node is already claimed, the owner + /// will be updated and keep the existing additional connection unchanged. + /// + /// May only be called from `T::AddOrigin`. + /// + /// - `node`: identifier of the node. + #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] + pub fn add_well_known_node(origin, node: NodePublicKey, owner: T::AccountId) { + T::AddOrigin::ensure_origin(origin)?; + + let mut nodes = WellKnownNodes::get(); + ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + + let location = nodes.binary_search(&node).err().ok_or(Error::::AlreadyJoined)?; + nodes.insert(location, node.clone()); + + WellKnownNodes::put(&nodes); + >::insert(&node, &owner); + + Self::deposit_event(RawEvent::NodeAdded(node, owner)); + } + + /// Remove a node from the set of well known nodes. The ownership and additional + /// connections of the node will also be removed. + /// + /// May only be called from `T::RemoveOrigin`. + /// + /// - `node`: identifier of the node. + #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] + pub fn remove_well_known_node(origin, node: NodePublicKey) { + T::RemoveOrigin::ensure_origin(origin)?; + + let mut nodes = WellKnownNodes::get(); + + let location = nodes.binary_search(&node).ok().ok_or(Error::::NotExist)?; + nodes.remove(location); + + WellKnownNodes::put(&nodes); + >::remove(&node); + AdditionalConnections::remove(&node); + + Self::deposit_event(RawEvent::NodeRemoved(node)); + } + + /// Swap a well known node to another. Both the ownership and additional connections + /// stay untouched. + /// + /// May only be called from `T::SwapOrigin`. + /// + /// - `remove`: the node which will be moved out from the list. + /// - `add`: the node which will be put in the list. + #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] + pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { + T::SwapOrigin::ensure_origin(origin)?; + + if remove == add { return Ok(()) } + + let mut nodes = WellKnownNodes::get(); + let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; + nodes.remove(remove_location); + let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; + nodes.insert(add_location, add.clone()); + + WellKnownNodes::put(&nodes); + Owners::::swap(&remove, &add); + AdditionalConnections::swap(&remove, &add); + + Self::deposit_event(RawEvent::NodeSwapped(remove, add)); + } + + /// Reset all the well known nodes. This will not remove the ownership and additional + /// connections for the removed nodes. The node owner can perform further cleaning if + /// they decide to leave the network. + /// + /// May only be called from `T::ResetOrigin`. + /// + /// - `nodes`: the new nodes for the allow list. + #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] + pub fn reset_well_known_nodes(origin, nodes: Vec<(NodePublicKey, T::AccountId)>) { + T::ResetOrigin::ensure_origin(origin)?; + ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + + Self::initialize_nodes(&nodes); + + Self::deposit_event(RawEvent::NodesReset(nodes)); + } + + /// A given node can be claimed by anyone. The owner should be the first to know its + /// public key, so claim it right away! + /// + /// - `node`: identifier of the node. + #[weight = T::WeightInfo::claim_node()] + pub fn claim_node(origin, node: NodePublicKey) { + let sender = ensure_signed(origin)?; + ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); + + Owners::::insert(&node, &sender); + Self::deposit_event(RawEvent::NodeClaimed(node, sender)); + } + + /// A claim can be removed by its owner and get back the reservation. The additional + /// connections are also removed. You can't remove a claim on well known nodes, as it + /// needs to reach consensus among the network participants. + /// + /// - `node`: identifier of the node. + #[weight = T::WeightInfo::remove_claim()] + pub fn remove_claim(origin, node: NodePublicKey) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + ensure!(!WellKnownNodes::get().contains(&node), Error::::PermissionDenied); + + Owners::::remove(&node); + AdditionalConnections::remove(&node); + + Self::deposit_event(RawEvent::ClaimRemoved(node, sender)); + } + + /// A node can be transferred to a new owner. + /// + /// - `node`: identifier of the node. + /// - `owner`: new owner of the node. + #[weight = T::WeightInfo::transfer_node()] + pub fn transfer_node(origin, node: NodePublicKey, owner: T::AccountId) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + + Owners::::insert(&node, &owner); + + Self::deposit_event(RawEvent::NodeTransferred(node, sender, owner)); + } + + /// Add additional connections to a given node. + /// + /// - `node`: identifier of the node. + /// - `connections`: additonal nodes from which the connections are allowed. + #[weight = T::WeightInfo::add_connections()] + pub fn add_connections( + origin, + node: NodePublicKey, + connections: Vec + ) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + + let mut nodes = AdditionalConnections::get(&node); + + for add_node in connections.iter() { + if *add_node == node { + continue; + } + if let Err(add_location) = nodes.binary_search(add_node) { + nodes.insert(add_location, add_node.clone()); + } + } + + AdditionalConnections::insert(&node, nodes); + + Self::deposit_event(RawEvent::ConnectionsAdded(node, connections)); + } + + /// Remove additional connections of a given node. + /// + /// - `node`: identifier of the node. + /// - `connections`: additonal nodes from which the connections are not allowed anymore. + #[weight = T::WeightInfo::remove_connections()] + pub fn remove_connections( + origin, + node: NodePublicKey, + connections: Vec + ) { + let sender = ensure_signed(origin)?; + ensure!(Owners::::contains_key(&node), Error::::NotClaimed); + ensure!(Owners::::get(&node) == sender, Error::::NotOwner); + + let mut nodes = AdditionalConnections::get(&node); + + for remove_node in connections.iter() { + if let Ok(remove_location) = nodes.binary_search(remove_node) { + nodes.remove(remove_location); + } + } + + AdditionalConnections::insert(&node, nodes); + + Self::deposit_event(RawEvent::ConnectionsRemoved(node, connections)); + } + + /// Set reserved node every block. If may not be enabled depends on the offchain + /// worker CLI flag. + fn offchain_worker(now: T::BlockNumber) { + let node_public_key = sp_io::offchain::get_node_public_key(); + match node_public_key { + Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), + Ok(node) => sp_io::offchain::set_reserved_nodes( + Self::get_authorized_nodes(&node), true + ), + } + } + } } impl Module { - fn initialize_nodes(nodes: &Vec<(NodePublicKey, T::AccountId)>) { - let mut node_public_keys = nodes.iter() - .map(|item| item.0.clone()) - .collect::>(); - node_public_keys.sort(); - WellKnownNodes::put(&node_public_keys); - - for (node, who) in nodes.iter() { - Owners::::insert(node, who); - } - } - - fn get_authorized_nodes(node: &NodePublicKey) -> Vec { - let mut nodes = AdditionalConnections::get(node); - - let mut well_known_nodes = WellKnownNodes::get(); - if let Ok(location) = well_known_nodes.binary_search(node) { - well_known_nodes.remove(location); - nodes.extend(well_known_nodes); - } - - nodes - } + fn initialize_nodes(nodes: &Vec<(NodePublicKey, T::AccountId)>) { + let mut node_public_keys = nodes.iter() + .map(|item| item.0.clone()) + .collect::>(); + node_public_keys.sort(); + WellKnownNodes::put(&node_public_keys); + + for (node, who) in nodes.iter() { + Owners::::insert(node, who); + } + } + + fn get_authorized_nodes(node: &NodePublicKey) -> Vec { + let mut nodes = AdditionalConnections::get(node); + + let mut well_known_nodes = WellKnownNodes::get(); + if let Ok(location) = well_known_nodes.binary_search(node) { + well_known_nodes.remove(location); + nodes.extend(well_known_nodes); + } + + nodes + } } #[cfg(test)] mod tests { - use super::*; + use super::*; - use frame_support::{ - assert_ok, assert_noop, impl_outer_origin, weights::Weight, - parameter_types, ord_parameter_types, - }; - use frame_system::EnsureSignedBy; - use sp_core::{H256, ed25519::Public}; - use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; + use frame_support::{ + assert_ok, assert_noop, impl_outer_origin, weights::Weight, + parameter_types, ord_parameter_types, + }; + use frame_system::EnsureSignedBy; + use sp_core::{H256, ed25519::Public}; + use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; - impl_outer_origin! { - pub enum Origin for Test where system = frame_system {} - } + impl_outer_origin! { + pub enum Origin for Test where system = frame_system {} + } - #[derive(Clone, Eq, PartialEq)] - pub struct Test; + #[derive(Clone, Eq, PartialEq)] + pub struct Test; - parameter_types! { + parameter_types! { pub const BlockHashCount: u64 = 250; pub const MaximumBlockWeight: Weight = 1024; pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - impl frame_system::Trait for Test { + } + impl frame_system::Trait for Test { type BaseCallFilter = (); type Origin = Origin; type Index = u64; @@ -445,317 +445,317 @@ mod tests { type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); - type SystemWeightInfo = (); - } - - ord_parameter_types! { + type SystemWeightInfo = (); + } + + ord_parameter_types! { pub const One: u64 = 1; pub const Two: u64 = 2; pub const Three: u64 = 3; - pub const Four: u64 = 4; - } - parameter_types! { - pub const MaxWellKnownNodes: u32 = 4; - } - impl Trait for Test { - type Event = (); - type MaxWellKnownNodes = MaxWellKnownNodes; - type AddOrigin = EnsureSignedBy; - type RemoveOrigin = EnsureSignedBy; - type SwapOrigin = EnsureSignedBy; - type ResetOrigin = EnsureSignedBy; - type WeightInfo = (); - } - - type NodeAuthorization = Module; - - fn test_node(id: u8) -> NodePublicKey { - let mut arr = [0u8; 32]; - arr[31] = id; - NodePublicKey::Ed25519(Public::from_raw(arr)) - } - - fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - GenesisConfig:: { - nodes: vec![(test_node(10), 10), (test_node(20), 20), (test_node(30), 30)], - }.assimilate_storage(&mut t).unwrap(); - t.into() - } - - #[test] - fn add_well_known_node_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), - BadOrigin - ); - assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), - Error::::AlreadyJoined - ); - - assert_ok!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(15), 15) - ); - assert_eq!( - WellKnownNodes::get(), - vec![test_node(10), test_node(15), test_node(20), test_node(30)] - ); - assert_eq!(Owners::::get(test_node(10)), 10); - assert_eq!(Owners::::get(test_node(20)), 20); - assert_eq!(Owners::::get(test_node(30)), 30); - assert_eq!(Owners::::get(test_node(15)), 15); - - assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(25), 25), - Error::::TooManyNodes - ); - }); - } - - #[test] - fn remove_well_known_node_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), - BadOrigin - ); - assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), - Error::::NotExist - ); - - AdditionalConnections::insert(test_node(20), vec![test_node(40)]); - assert!(AdditionalConnections::contains_key(test_node(20))); - - assert_ok!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20)) - ); - assert_eq!(WellKnownNodes::get(), vec![test_node(10), test_node(30)]); - assert!(!Owners::::contains_key(test_node(20))); - assert!(!AdditionalConnections::contains_key(test_node(20))); - }); - } - - #[test] - fn swap_well_known_node_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::swap_well_known_node( - Origin::signed(4), test_node(20), test_node(5) - ), - BadOrigin - ); - - assert_ok!( - NodeAuthorization::swap_well_known_node( - Origin::signed(3), test_node(20), test_node(20) - ) - ); - assert_eq!( - WellKnownNodes::get(), - vec![test_node(10), test_node(20), test_node(30)] - ); - - assert_noop!( - NodeAuthorization::swap_well_known_node( - Origin::signed(3), test_node(15), test_node(5) - ), - Error::::NotExist - ); - assert_noop!( - NodeAuthorization::swap_well_known_node( - Origin::signed(3), test_node(20), test_node(30) - ), - Error::::AlreadyJoined - ); - - AdditionalConnections::insert(test_node(20), vec![test_node(15)]); - assert_ok!( - NodeAuthorization::swap_well_known_node( - Origin::signed(3), test_node(20), test_node(5) - ) - ); - assert_eq!( - WellKnownNodes::get(), - vec![test_node(5), test_node(10), test_node(30)] - ); - assert!(!Owners::::contains_key(test_node(20))); - assert_eq!(Owners::::get(test_node(5)), 20); - assert!(!AdditionalConnections::contains_key(test_node(20))); - assert_eq!(AdditionalConnections::get(test_node(5)), vec![test_node(15)]); - }); - } - - #[test] - fn reset_well_known_nodes_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::reset_well_known_nodes( - Origin::signed(3), - vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] - ), - BadOrigin - ); - assert_noop!( - NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), - vec![ - (test_node(15), 15), - (test_node(5), 5), - (test_node(20), 20), - (test_node(25), 25), - ] - ), - Error::::TooManyNodes - ); - - assert_ok!( - NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), - vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] - ) - ); - assert_eq!( - WellKnownNodes::get(), - vec![test_node(5), test_node(15), test_node(20)] - ); - assert_eq!(Owners::::get(test_node(5)), 5); - assert_eq!(Owners::::get(test_node(15)), 15); - assert_eq!(Owners::::get(test_node(20)), 20); - }); - } - - #[test] - fn claim_node_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), - Error::::AlreadyClaimed - ); - - assert_ok!(NodeAuthorization::claim_node(Origin::signed(15), test_node(15))); - assert_eq!(Owners::::get(test_node(15)), 15); - }); - } - - #[test] - fn remove_claim_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), - Error::::NotClaimed - ); - - assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(20)), - Error::::NotOwner - ); - - assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(20), test_node(20)), - Error::::PermissionDenied - ); - - Owners::::insert(test_node(15), 15); - AdditionalConnections::insert(test_node(15), vec![test_node(20)]); - assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); - assert!(!Owners::::contains_key(test_node(15))); - assert!(!AdditionalConnections::contains_key(test_node(15))); - }); - } - - #[test] - fn transfer_node_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), - Error::::NotClaimed - ); - - assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(20), 10), - Error::::NotOwner - ); - - assert_ok!(NodeAuthorization::transfer_node(Origin::signed(20), test_node(20), 15)); - assert_eq!(Owners::::get(test_node(20)), 15); - }); - } - - #[test] - fn add_connections_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::add_connections( - Origin::signed(15), test_node(15), vec![test_node(5)] - ), - Error::::NotClaimed - ); - - assert_noop!( - NodeAuthorization::add_connections( - Origin::signed(15), test_node(20), vec![test_node(5)] - ), - Error::::NotOwner - ); - - assert_ok!( - NodeAuthorization::add_connections( - Origin::signed(20), - test_node(20), - vec![test_node(15), test_node(5), test_node(25), test_node(20)] - ) - ); - assert_eq!( - AdditionalConnections::get(test_node(20)), - vec![test_node(5), test_node(15), test_node(25)] - ); - }); - } - - #[test] - fn remove_connections_works() { - new_test_ext().execute_with(|| { - assert_noop!( - NodeAuthorization::remove_connections( - Origin::signed(15), test_node(15), vec![test_node(5)] - ), - Error::::NotClaimed - ); - - assert_noop!( - NodeAuthorization::remove_connections( - Origin::signed(15), test_node(20), vec![test_node(5)] - ), - Error::::NotOwner - ); - - AdditionalConnections::insert( - test_node(20), vec![test_node(5), test_node(15), test_node(25)] - ); - assert_ok!( - NodeAuthorization::remove_connections( - Origin::signed(20), - test_node(20), - vec![test_node(15), test_node(5)] - ) - ); - assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); - }); - } - - #[test] - fn get_authorize_nodes_worker() { - new_test_ext().execute_with(|| { - AdditionalConnections::insert( - test_node(20), vec![test_node(5), test_node(15), test_node(25)] - ); - assert_eq!( - Module::::get_authorized_nodes(&test_node(20)), - vec![test_node(5), test_node(15), test_node(25), test_node(10), test_node(30)] - ); - }); - } + pub const Four: u64 = 4; + } + parameter_types! { + pub const MaxWellKnownNodes: u32 = 4; + } + impl Trait for Test { + type Event = (); + type MaxWellKnownNodes = MaxWellKnownNodes; + type AddOrigin = EnsureSignedBy; + type RemoveOrigin = EnsureSignedBy; + type SwapOrigin = EnsureSignedBy; + type ResetOrigin = EnsureSignedBy; + type WeightInfo = (); + } + + type NodeAuthorization = Module; + + fn test_node(id: u8) -> NodePublicKey { + let mut arr = [0u8; 32]; + arr[31] = id; + NodePublicKey::Ed25519(Public::from_raw(arr)) + } + + fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + GenesisConfig:: { + nodes: vec![(test_node(10), 10), (test_node(20), 20), (test_node(30), 30)], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + + #[test] + fn add_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), + BadOrigin + ); + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), + Error::::AlreadyJoined + ); + + assert_ok!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(15), 15) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(10), test_node(15), test_node(20), test_node(30)] + ); + assert_eq!(Owners::::get(test_node(10)), 10); + assert_eq!(Owners::::get(test_node(20)), 20); + assert_eq!(Owners::::get(test_node(30)), 30); + assert_eq!(Owners::::get(test_node(15)), 15); + + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(25), 25), + Error::::TooManyNodes + ); + }); + } + + #[test] + fn remove_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), + BadOrigin + ); + assert_noop!( + NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), + Error::::NotExist + ); + + AdditionalConnections::insert(test_node(20), vec![test_node(40)]); + assert!(AdditionalConnections::contains_key(test_node(20))); + + assert_ok!( + NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20)) + ); + assert_eq!(WellKnownNodes::get(), vec![test_node(10), test_node(30)]); + assert!(!Owners::::contains_key(test_node(20))); + assert!(!AdditionalConnections::contains_key(test_node(20))); + }); + } + + #[test] + fn swap_well_known_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(4), test_node(20), test_node(5) + ), + BadOrigin + ); + + assert_ok!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(20) + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(10), test_node(20), test_node(30)] + ); + + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(15), test_node(5) + ), + Error::::NotExist + ); + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(30) + ), + Error::::AlreadyJoined + ); + + AdditionalConnections::insert(test_node(20), vec![test_node(15)]); + assert_ok!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), test_node(5) + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(5), test_node(10), test_node(30)] + ); + assert!(!Owners::::contains_key(test_node(20))); + assert_eq!(Owners::::get(test_node(5)), 20); + assert!(!AdditionalConnections::contains_key(test_node(20))); + assert_eq!(AdditionalConnections::get(test_node(5)), vec![test_node(15)]); + }); + } + + #[test] + fn reset_well_known_nodes_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(3), + vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] + ), + BadOrigin + ); + assert_noop!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(4), + vec![ + (test_node(15), 15), + (test_node(5), 5), + (test_node(20), 20), + (test_node(25), 25), + ] + ), + Error::::TooManyNodes + ); + + assert_ok!( + NodeAuthorization::reset_well_known_nodes( + Origin::signed(4), + vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] + ) + ); + assert_eq!( + WellKnownNodes::get(), + vec![test_node(5), test_node(15), test_node(20)] + ); + assert_eq!(Owners::::get(test_node(5)), 5); + assert_eq!(Owners::::get(test_node(15)), 15); + assert_eq!(Owners::::get(test_node(20)), 20); + }); + } + + #[test] + fn claim_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), + Error::::AlreadyClaimed + ); + + assert_ok!(NodeAuthorization::claim_node(Origin::signed(15), test_node(15))); + assert_eq!(Owners::::get(test_node(15)), 15); + }); + } + + #[test] + fn remove_claim_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(15), test_node(20)), + Error::::NotOwner + ); + + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(20), test_node(20)), + Error::::PermissionDenied + ); + + Owners::::insert(test_node(15), 15); + AdditionalConnections::insert(test_node(15), vec![test_node(20)]); + assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); + assert!(!Owners::::contains_key(test_node(15))); + assert!(!AdditionalConnections::contains_key(test_node(15))); + }); + } + + #[test] + fn transfer_node_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::transfer_node(Origin::signed(15), test_node(20), 10), + Error::::NotOwner + ); + + assert_ok!(NodeAuthorization::transfer_node(Origin::signed(20), test_node(20), 15)); + assert_eq!(Owners::::get(test_node(20)), 15); + }); + } + + #[test] + fn add_connections_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::add_connections( + Origin::signed(15), test_node(15), vec![test_node(5)] + ), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::add_connections( + Origin::signed(15), test_node(20), vec![test_node(5)] + ), + Error::::NotOwner + ); + + assert_ok!( + NodeAuthorization::add_connections( + Origin::signed(20), + test_node(20), + vec![test_node(15), test_node(5), test_node(25), test_node(20)] + ) + ); + assert_eq!( + AdditionalConnections::get(test_node(20)), + vec![test_node(5), test_node(15), test_node(25)] + ); + }); + } + + #[test] + fn remove_connections_works() { + new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_connections( + Origin::signed(15), test_node(15), vec![test_node(5)] + ), + Error::::NotClaimed + ); + + assert_noop!( + NodeAuthorization::remove_connections( + Origin::signed(15), test_node(20), vec![test_node(5)] + ), + Error::::NotOwner + ); + + AdditionalConnections::insert( + test_node(20), vec![test_node(5), test_node(15), test_node(25)] + ); + assert_ok!( + NodeAuthorization::remove_connections( + Origin::signed(20), + test_node(20), + vec![test_node(15), test_node(5)] + ) + ); + assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); + }); + } + + #[test] + fn get_authorize_nodes_worker() { + new_test_ext().execute_with(|| { + AdditionalConnections::insert( + test_node(20), vec![test_node(5), test_node(15), test_node(25)] + ); + assert_eq!( + Module::::get_authorized_nodes(&test_node(20)), + vec![test_node(5), test_node(15), test_node(25), test_node(10), test_node(30)] + ); + }); + } } diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index e65c7b7353881..95e1d056c74b4 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -712,13 +712,6 @@ pub enum NodePublicKey { Ed25519(ed25519::Public), } -impl From<[u8; 32]> for NodePublicKey { - fn from(x: [u8; 32]) -> NodePublicKey { - let public = ed25519::Public(x); - NodePublicKey::Ed25519(public) - } -} - #[cfg(feature = "std")] pub use self::dummy::*; diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 3ba11fdb3e841..a09f5ec4a9b86 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -381,7 +381,9 @@ impl offchain::Externalities for TestOffchainExt { Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) } - fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { unimplemented!() } + fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { + unimplemented!() + } } /// The internal state of the fake transaction pool. From 4907592337b4d53d38ce5f69fbcb7dc119cba501 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 13:37:42 +0800 Subject: [PATCH 18/34] expose NetworkService --- Cargo.lock | 17 +++ Cargo.toml | 1 + .../authority-discovery/src/worker/tests.rs | 16 --- client/network/src/lib.rs | 8 -- client/network/src/service.rs | 21 ++-- client/offchain/Cargo.toml | 1 + client/offchain/src/api.rs | 40 +++--- client/offchain/src/lib.rs | 31 +++-- client/service/src/builder.rs | 3 +- test-utils/runtime/network/Cargo.toml | 24 ++++ test-utils/runtime/network/src/lib.rs | 117 ++++++++++++++++++ 11 files changed, 201 insertions(+), 78 deletions(-) create mode 100644 test-utils/runtime/network/Cargo.toml create mode 100644 test-utils/runtime/network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 20aa35fc44ef0..218fc3770077b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7054,6 +7054,7 @@ dependencies = [ "sp-transaction-pool", "sp-utils", "substrate-test-runtime-client", + "substrate-test-runtime-network", "threadpool", "tokio 0.2.22", ] @@ -8831,6 +8832,22 @@ dependencies = [ "substrate-test-runtime", ] +[[package]] +name = "substrate-test-runtime-network" +version = "2.0.0-rc6" +dependencies = [ + "async-std", + "futures 0.3.5", + "rand 0.7.3", + "sc-network", + "sc-service", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "substrate-test-runtime-client", +] + [[package]] name = "substrate-test-runtime-transaction-pool" version = "2.0.0-rc6" diff --git a/Cargo.toml b/Cargo.toml index 534b71357cc76..87d4bffc86651 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -175,6 +175,7 @@ members = [ "test-utils/derive", "test-utils/runtime", "test-utils/runtime/client", + "test-utils/runtime/network", "test-utils/runtime/transaction-pool", "test-utils/test-crate", "utils/browser", diff --git a/client/authority-discovery/src/worker/tests.rs b/client/authority-discovery/src/worker/tests.rs index 851adaaa540fe..baa6bd0fc7d62 100644 --- a/client/authority-discovery/src/worker/tests.rs +++ b/client/authority-discovery/src/worker/tests.rs @@ -28,8 +28,6 @@ use futures::task::LocalSpawn; use futures::poll; use libp2p::{kad, core::multiaddr, PeerId}; -use sc_network::config::identity; -use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; use sp_api::{ProvideRuntimeApi, ApiRef}; use sp_core::{crypto::Public, testing::KeyStore}; use sp_runtime::traits::{Zero, Block as BlockT, NumberFor}; @@ -221,20 +219,6 @@ impl NetworkStateInfo for TestNetwork { fn external_addresses(&self) -> Vec { self.external_addresses.clone() } - - fn local_public_key(&self) -> identity::PublicKey { - identity::Keypair::generate_ed25519().public() - } - - fn peerset(&self) -> PeersetHandle { - Peerset::from_config(PeersetConfig { - in_peers: 25, - out_peers: 25, - bootnodes: vec![], - reserved_only: false, - priority_groups: vec![], - }).1 - } } #[test] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index da2b097bc269d..326d73c372110 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -270,8 +270,6 @@ pub use protocol::{event::{DhtEvent, Event, ObservedRole}, sync::SyncState, Peer pub use service::{NetworkService, NetworkWorker, RequestFailure, OutboundFailure}; pub use sc_peerset::ReputationChange; -use config::identity::PublicKey; -use sc_peerset::PeersetHandle; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// The maximum allowed number of established connections per peer. @@ -296,12 +294,6 @@ pub trait NetworkStateInfo { /// Returns the local Peer ID. fn local_peer_id(&self) -> PeerId; - - /// Returns the local Peer PublicKey. - fn local_public_key(&self) -> PublicKey; - - /// Returns the peerset - fn peerset(&self) -> PeersetHandle; } /// Overview status of the network. diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 5f9d1a3c8b1eb..bf3287989a43d 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -602,6 +602,17 @@ impl NetworkService { &self.local_peer_id } + /// Returns the local node `PublicKey`. + pub fn local_public_key(&self) -> &PublicKey { + &self.local_public_key + } + + /// Set reserved peers and reserved_only flag. + pub fn set_reserved_peers(&self, peers: HashSet, reserved_only: bool) { + self.peerset.set_reserved_peers(peers); + self.peerset.set_reserved_only(reserved_only) + } + /// Appends a notification to the buffer of pending outgoing notifications with the given peer. /// Has no effect if the notifications channel with this protocol name is not open. /// @@ -1060,16 +1071,6 @@ impl NetworkStateInfo for NetworkService fn local_peer_id(&self) -> PeerId { self.local_peer_id.clone() } - - /// Returns the PublicKey of local peer. - fn local_public_key(&self) -> PublicKey { - self.local_public_key.clone() - } - - /// Returns the peerset. - fn peerset(&self) -> PeersetHandle { - self.peerset.clone() - } } /// A `NotificationSender` allows for sending notifications to a peer with a chosen protocol. diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index 85be77e9e9957..ffc65b370b725 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -42,6 +42,7 @@ sc-client-db = { version = "0.8.0-rc6", default-features = true, path = "../db/" sc-transaction-pool = { version = "2.0.0-rc6", path = "../../client/transaction-pool" } sp-transaction-pool = { version = "2.0.0-rc6", path = "../../primitives/transaction-pool" } substrate-test-runtime-client = { version = "2.0.0-rc6", path = "../../test-utils/runtime/client" } +substrate-test-runtime-network = { version = "2.0.0-rc6", path = "../../test-utils/runtime/network" } tokio = "0.2" lazy_static = "1.4.0" diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index dcd1fcde6395d..d9729f8bfb660 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -25,13 +25,14 @@ use std::{ use sp_core::offchain::OffchainStorage; use futures::Future; use log::error; -use sc_network::{config::identity, PeerId, Multiaddr, NetworkStateInfo}; +use sc_network::{config::identity, PeerId, Multiaddr, NetworkService, NetworkStateInfo}; use codec::{Encode, Decode}; use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; use sp_core::{NodePublicKey, ed25519}; +use sp_runtime::traits::Block as BlockT; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -48,11 +49,13 @@ mod timestamp; /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). -pub(crate) struct Api { +pub(crate) struct Api { /// Offchain Workers database. db: Storage, /// A NetworkState provider. network_state: Arc, + /// A NetworkService provider. + network_service: Arc::Hash>>, /// Is this node a potential validator? is_validator: bool, /// Everything HTTP-related is handled by a different struct. @@ -69,7 +72,7 @@ fn unavailable_yet(name: &str) -> R { const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; -impl OffchainExt for Api { +impl OffchainExt for Api { fn is_validator(&self) -> bool { self.is_validator } @@ -184,7 +187,7 @@ impl OffchainExt for Api { } fn get_node_public_key(&mut self) -> Result { - let public_key = self.network_state.local_public_key(); + let public_key = self.network_service.local_public_key(); match public_key { identity::PublicKey::Ed25519(public) => Ok(NodePublicKey::Ed25519(ed25519::Public(public.encode()))), @@ -205,9 +208,7 @@ impl OffchainExt for Api { ) .collect(); - let peerset = self.network_state.peerset(); - peerset.set_reserved_peers(peer_ids); - peerset.set_reserved_only(reserved_only); + self.network_service.set_reserved_peers(peer_ids, reserved_only); } } @@ -286,17 +287,19 @@ pub(crate) struct AsyncApi { impl AsyncApi { /// Creates new Offchain extensions API implementation an the asynchronous processing part. - pub fn new( + pub fn new( db: S, network_state: Arc, + network_service: Arc::Hash>>, is_validator: bool, shared_client: SharedClient, - ) -> (Api, Self) { + ) -> (Api, Self) { let (http_api, http_worker) = http::http(shared_client); let api = Api { db, network_state, + network_service, is_validator, http: http_api, }; @@ -321,7 +324,6 @@ mod tests { use super::*; use std::{convert::{TryFrom, TryInto}, time::SystemTime}; use sc_client_db::offchain::LocalStorage; - use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; struct MockNetworkStateInfo(); @@ -333,32 +335,18 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } - - fn local_public_key(&self) -> identity::PublicKey { - identity::Keypair::generate_ed25519().public() - } - - fn peerset(&self) -> PeersetHandle { - Peerset::from_config(PeersetConfig { - in_peers: 25, - out_peers: 25, - bootnodes: vec![], - reserved_only: false, - priority_groups: vec![], - }).1 - } } - fn offchain_api() -> (Api, AsyncApi) { + fn offchain_api() -> (Api, AsyncApi) { let _ = env_logger::try_init(); let db = LocalStorage::new_test(); let mock = Arc::new(MockNetworkStateInfo()); let shared_client = SharedClient::new(); - AsyncApi::new( db, mock, + substrate_test_runtime_network::build_network_service(), false, shared_client, ) diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index aa78468884a30..9449fc0aae45b 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -41,6 +41,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use futures::future::Future; use log::{debug, warn}; use sc_network::NetworkStateInfo; +use sc_network::NetworkService; use sp_core::{offchain::{self, OffchainStorage}, ExecutionContext, traits::SpawnNamed}; use sp_runtime::{generic::BlockId, traits::{self, Header}}; use futures::{prelude::*, future::ready}; @@ -99,6 +100,7 @@ impl OffchainWorkers< &self, header: &Block::Header, network_state: Arc, + network_service: Arc::Hash>>, is_validator: bool, ) -> impl Future { let runtime = self.client.runtime_api(); @@ -123,6 +125,7 @@ impl OffchainWorkers< let (api, runner) = api::AsyncApi::new( self.db.clone(), network_state.clone(), + network_service, is_validator, self.shared_client.clone(), ); @@ -174,6 +177,7 @@ pub async fn notification_future( offchain: Arc>, spawner: Spawner, network_state_info: Arc, + network_service: Arc::Hash>>, ) where Block: traits::Block, @@ -189,6 +193,7 @@ pub async fn notification_future( offchain.on_block_imported( &n.header, network_state_info.clone(), + network_service.clone(), is_validator, ).boxed(), ); @@ -208,8 +213,7 @@ pub async fn notification_future( mod tests { use super::*; use std::sync::Arc; - use sc_network::{Multiaddr, PeerId, config::identity}; - use sc_peerset::{Peerset, PeersetConfig, PeersetHandle}; + use sc_network::{Multiaddr, PeerId}; use substrate_test_runtime_client::{TestClient, runtime::Block}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_transaction_pool::{TransactionPool, InPoolTransaction}; @@ -224,20 +228,6 @@ mod tests { fn local_peer_id(&self) -> PeerId { PeerId::random() } - - fn local_public_key(&self) -> identity::PublicKey { - identity::Keypair::generate_ed25519().public() - } - - fn peerset(&self) -> PeersetHandle { - Peerset::from_config(PeersetConfig { - in_peers: 25, - out_peers: 25, - bootnodes: vec![], - reserved_only: false, - priority_groups: vec![], - }).1 - } } struct TestPool( @@ -275,7 +265,14 @@ mod tests { // when let offchain = OffchainWorkers::new(client, db); - futures::executor::block_on(offchain.on_block_imported(&header, network_state, false)); + futures::executor::block_on( + offchain.on_block_imported( + &header, + network_state, + substrate_test_runtime_network::build_network_service(), + false + ) + ); // then assert_eq!(pool.0.status().ready, 1); diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 5faf0899aa2e3..f38cd49ad6a06 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -431,7 +431,8 @@ pub fn build_offchain_workers( client.clone(), offchain, Clone::clone(&spawn_handle), - network.clone() + network.clone(), + network.clone(), ) ); } diff --git a/test-utils/runtime/network/Cargo.toml b/test-utils/runtime/network/Cargo.toml new file mode 100644 index 0000000000000..c6b98d86a7c21 --- /dev/null +++ b/test-utils/runtime/network/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "substrate-test-runtime-network" +version = "2.0.0-rc6" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +async-std = { version = "1.6.2", features = ["unstable"] } +futures = "0.3.4" +rand = "0.7.2" +sc-service = { version = "0.8.0-rc6", default-features = false, path = "../../../client/service" } +sc-network = { version = "0.8.0-rc6", path = "../../../client/network" } +sp-blockchain = { version = "2.0.0-rc6", path = "../../../primitives/blockchain" } +sp-consensus = { version = "0.8.0-rc6", path = "../../../primitives/consensus/common" } +sp-core = { version = "2.0.0-rc6", path = "../../../primitives/core" } +sp-runtime = { version = "2.0.0-rc6", path = "../../../primitives/runtime" } +substrate-test-runtime-client = { version = "2.0.0-rc6", path = "../../runtime/client" } diff --git a/test-utils/runtime/network/src/lib.rs b/test-utils/runtime/network/src/lib.rs new file mode 100644 index 0000000000000..6cb36c9e8698f --- /dev/null +++ b/test-utils/runtime/network/src/lib.rs @@ -0,0 +1,117 @@ +use std::sync::Arc; +use futures::prelude::*; +use sc_network::{config, Event, NetworkService, NetworkWorker}; +use sp_runtime::traits::{Block as BlockT, Header as _}; +use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; + +pub type TestNetworkService = NetworkService< + substrate_test_runtime_client::runtime::Block, + substrate_test_runtime_client::runtime::Hash, +>; + +/// Builds a full node to be used for testing. Returns the node service and its associated events +/// stream. +/// +/// > **Note**: We return the events stream in order to not possibly lose events between the +/// > construction of the service and the moment the events stream is grabbed. +pub fn build_test_full_node(config: config::NetworkConfiguration) + -> (Arc, impl Stream) +{ + let client = Arc::new( + TestClientBuilder::with_default_backend() + .build_with_longest_chain() + .0, + ); + + #[derive(Clone)] + struct PassThroughVerifier(bool); + impl sp_consensus::import_queue::Verifier for PassThroughVerifier { + fn verify( + &mut self, + origin: sp_consensus::BlockOrigin, + header: B::Header, + justification: Option, + body: Option>, + ) -> Result< + ( + sp_consensus::BlockImportParams, + Option)>>, + ), + String, + > { + let maybe_keys = header + .digest() + .log(|l| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) + .or_else(|| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"babe")) + }) + }) + .map(|blob| { + vec![( + sp_blockchain::well_known_cache_keys::AUTHORITIES, + blob.to_vec(), + )] + }); + + let mut import = sp_consensus::BlockImportParams::new(origin, header); + import.body = body; + import.finalized = self.0; + import.justification = justification; + import.fork_choice = Some(sp_consensus::ForkChoiceStrategy::LongestChain); + Ok((import, maybe_keys)) + } + } + + let import_queue = Box::new(sp_consensus::import_queue::BasicQueue::new( + PassThroughVerifier(false), + Box::new(client.clone()), + None, + None, + &sp_core::testing::TaskExecutor::new(), + None, + )); + + let worker = NetworkWorker::new(config::Params { + role: config::Role::Full, + executor: None, + network_config: config, + chain: client.clone(), + finality_proof_provider: None, + finality_proof_request_builder: None, + on_demand: None, + transaction_pool: Arc::new(config::EmptyTransactionPool), + protocol_id: config::ProtocolId::from("/test-protocol-name"), + import_queue, + block_announce_validator: Box::new( + sp_consensus::block_validation::DefaultBlockAnnounceValidator, + ), + metrics_registry: None, + }) + .unwrap(); + + let service = worker.service().clone(); + let event_stream = service.event_stream("test"); + + async_std::task::spawn(async move { + futures::pin_mut!(worker); + let _ = worker.await; + }); + + (service, event_stream) +} + +const ENGINE_ID: sp_runtime::ConsensusEngineId = *b"foo\0"; + +/// Build a NetworkService +pub fn build_network_service() -> Arc { + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + build_test_full_node( + config::NetworkConfiguration { + notifications_protocols: vec![(ENGINE_ID, From::from("/foo"))], + listen_addresses: vec![listen_addr.clone()], + transport: config::TransportConfig::MemoryOnly, + .. config::NetworkConfiguration::new_local() + } + ).0 +} From f112fa76514b058dba319d8845b256bc0137cad7 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 15:36:23 +0800 Subject: [PATCH 19/34] remove NetworkStateInfo in offchain --- client/offchain/src/api.rs | 22 ++-------------------- client/offchain/src/lib.rs | 20 -------------------- client/service/src/builder.rs | 1 - 3 files changed, 2 insertions(+), 41 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index d9729f8bfb660..1cb6af77006a9 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -52,8 +52,6 @@ mod timestamp; pub(crate) struct Api { /// Offchain Workers database. db: Storage, - /// A NetworkState provider. - network_state: Arc, /// A NetworkService provider. network_service: Arc::Hash>>, /// Is this node a potential validator? @@ -78,10 +76,10 @@ impl OffchainExt for Api Result { - let external_addresses = self.network_state.external_addresses(); + let external_addresses = self.network_service.external_addresses(); let state = NetworkState::new( - self.network_state.local_peer_id(), + self.network_service.local_peer_id().clone(), external_addresses, ); Ok(OpaqueNetworkState::from(state)) @@ -289,7 +287,6 @@ impl AsyncApi { /// Creates new Offchain extensions API implementation an the asynchronous processing part. pub fn new( db: S, - network_state: Arc, network_service: Arc::Hash>>, is_validator: bool, shared_client: SharedClient, @@ -298,7 +295,6 @@ impl AsyncApi { let api = Api { db, - network_state, network_service, is_validator, http: http_api, @@ -325,27 +321,13 @@ mod tests { use std::{convert::{TryFrom, TryInto}, time::SystemTime}; use sc_client_db::offchain::LocalStorage; - struct MockNetworkStateInfo(); - - impl NetworkStateInfo for MockNetworkStateInfo { - fn external_addresses(&self) -> Vec { - Vec::new() - } - - fn local_peer_id(&self) -> PeerId { - PeerId::random() - } - } - fn offchain_api() -> (Api, AsyncApi) { let _ = env_logger::try_init(); let db = LocalStorage::new_test(); - let mock = Arc::new(MockNetworkStateInfo()); let shared_client = SharedClient::new(); AsyncApi::new( db, - mock, substrate_test_runtime_network::build_network_service(), false, shared_client, diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 9449fc0aae45b..349906aa337a4 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -40,7 +40,6 @@ use threadpool::ThreadPool; use sp_api::{ApiExt, ProvideRuntimeApi}; use futures::future::Future; use log::{debug, warn}; -use sc_network::NetworkStateInfo; use sc_network::NetworkService; use sp_core::{offchain::{self, OffchainStorage}, ExecutionContext, traits::SpawnNamed}; use sp_runtime::{generic::BlockId, traits::{self, Header}}; @@ -99,7 +98,6 @@ impl OffchainWorkers< pub fn on_block_imported( &self, header: &Block::Header, - network_state: Arc, network_service: Arc::Hash>>, is_validator: bool, ) -> impl Future { @@ -124,7 +122,6 @@ impl OffchainWorkers< if version > 0 { let (api, runner) = api::AsyncApi::new( self.db.clone(), - network_state.clone(), network_service, is_validator, self.shared_client.clone(), @@ -176,7 +173,6 @@ pub async fn notification_future( client: Arc, offchain: Arc>, spawner: Spawner, - network_state_info: Arc, network_service: Arc::Hash>>, ) where @@ -192,7 +188,6 @@ pub async fn notification_future( "offchain-on-block", offchain.on_block_imported( &n.header, - network_state_info.clone(), network_service.clone(), is_validator, ).boxed(), @@ -213,23 +208,10 @@ pub async fn notification_future( mod tests { use super::*; use std::sync::Arc; - use sc_network::{Multiaddr, PeerId}; use substrate_test_runtime_client::{TestClient, runtime::Block}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_transaction_pool::{TransactionPool, InPoolTransaction}; - struct MockNetworkStateInfo(); - - impl NetworkStateInfo for MockNetworkStateInfo { - fn external_addresses(&self) -> Vec { - Vec::new() - } - - fn local_peer_id(&self) -> PeerId { - PeerId::random() - } - } - struct TestPool( Arc, Block>> ); @@ -260,7 +242,6 @@ mod tests { client.clone(), )); let db = sc_client_db::offchain::LocalStorage::new_test(); - let network_state = Arc::new(MockNetworkStateInfo()); let header = client.header(&BlockId::number(0)).unwrap().unwrap(); // when @@ -268,7 +249,6 @@ mod tests { futures::executor::block_on( offchain.on_block_imported( &header, - network_state, substrate_test_runtime_network::build_network_service(), false ) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f38cd49ad6a06..aba3e6afd0dcd 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -432,7 +432,6 @@ pub fn build_offchain_workers( offchain, Clone::clone(&spawn_handle), network.clone(), - network.clone(), ) ); } From 420072f20f554871813306435a719fec61d6539a Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 17:55:48 +0800 Subject: [PATCH 20/34] replace NodePublicKey with PeerId. --- client/offchain/src/api.rs | 34 +-------- frame/node-authorization/src/lib.rs | 93 +++++++++++++------------ primitives/core/src/crypto.rs | 8 --- primitives/core/src/lib.rs | 1 - primitives/core/src/offchain/mod.rs | 20 ++---- primitives/core/src/offchain/testing.rs | 7 +- primitives/io/src/lib.rs | 11 +-- 7 files changed, 58 insertions(+), 116 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 1cb6af77006a9..501566d8d0aba 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -25,13 +25,12 @@ use std::{ use sp_core::offchain::OffchainStorage; use futures::Future; use log::error; -use sc_network::{config::identity, PeerId, Multiaddr, NetworkService, NetworkStateInfo}; +use sc_network::{PeerId, Multiaddr, NetworkService, NetworkStateInfo}; use codec::{Encode, Decode}; use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, }; -use sp_core::{NodePublicKey, ed25519}; use sp_runtime::traits::Block as BlockT; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -184,26 +183,9 @@ impl OffchainExt for Api Result { - let public_key = self.network_service.local_public_key(); - match public_key { - identity::PublicKey::Ed25519(public) => - Ok(NodePublicKey::Ed25519(ed25519::Public(public.encode()))), - _ => Err(()), - } - } - - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { let peer_ids: HashSet = nodes.iter() - .filter_map(|node| - match node { - NodePublicKey::Ed25519(public) => - identity::ed25519::PublicKey::decode(&public.0).ok() - } - ) - .map(|public| - identity::PublicKey::Ed25519(public).into_peer_id() - ) + .filter_map(|node| PeerId::from_bytes(node.clone()).ok()) .collect(); self.network_service.set_reserved_peers(peer_ids, reserved_only); @@ -442,14 +424,4 @@ mod tests { // then assert_ne!(seed, [0; 32]); } - - #[test] - fn should_get_node_public_key() { - // given - let mut api = offchain_api().0; - let node_public_key = api.get_node_public_key(); - - // then - assert!(node_public_key.is_ok()); - } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 44112dba21f41..1bf0bac20e2ab 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -18,7 +18,8 @@ //! # Node authorization pallet //! //! This pallet manages a configurable set of nodes for a permissioned network. -//! It provides two ways to authorize a node, +//! Each node is dentified by a PeerId (i.e. Vec). It provides two ways to +//! authorize a node, //! //! - a set of well known nodes across different organizations in which the //! connections are allowed. @@ -29,13 +30,14 @@ //! for the node. Only one user is allowed to claim a specific node. To eliminate //! false claim, the maintainer of the node should claim it before even starting the //! node. This pallet uses offchain worker to set reserved nodes, if the node is not -//! an authority, make sure to enable offchain worker with the right CLI flag. +//! an authority, make sure to enable offchain worker with the right CLI flag. The +//! node can be lagged with the latest block, in this case you need to disable offchain +//! worker and manually set reserved nodes when starting it. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] use sp_std::prelude::*; -use sp_core::NodePublicKey; use frame_support::{ decl_module, decl_storage, decl_event, decl_error, debug, ensure, @@ -44,6 +46,8 @@ use frame_support::{ }; use frame_system::ensure_signed; +type PeerId = Vec; + pub trait WeightInfo { fn add_well_known_node() -> Weight; fn remove_well_known_node() -> Weight; @@ -94,16 +98,16 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as NodeAuthorization { /// The set of well known nodes. This is stored sorted (just by value). - pub WellKnownNodes get(fn well_known_nodes): Vec; + pub WellKnownNodes get(fn well_known_nodes): Vec; /// A map that maintains the ownership of each node. pub Owners get(fn owners): - map hasher(blake2_128_concat) NodePublicKey => T::AccountId; + map hasher(blake2_128_concat) PeerId => T::AccountId; /// The additional adapative connections of each node. pub AdditionalConnections get(fn additional_connection): - map hasher(blake2_128_concat) NodePublicKey => Vec; + map hasher(blake2_128_concat) PeerId => Vec; } add_extra_genesis { - config(nodes): Vec<(NodePublicKey, T::AccountId)>; + config(nodes): Vec<(PeerId, T::AccountId)>; build(|config: &GenesisConfig| { >::initialize_nodes(&config.nodes) }) @@ -115,24 +119,24 @@ decl_event! { ::AccountId, { /// The given well known node was added. - NodeAdded(NodePublicKey, AccountId), + NodeAdded(PeerId, AccountId), /// The given well known node was removed. - NodeRemoved(NodePublicKey), + NodeRemoved(PeerId), /// The given well known node was swapped; first item was removed, /// the latter was added. - NodeSwapped(NodePublicKey, NodePublicKey), + NodeSwapped(PeerId, PeerId), /// The given well known nodes were reset. - NodesReset(Vec<(NodePublicKey, AccountId)>), + NodesReset(Vec<(PeerId, AccountId)>), /// The given node was claimed by a user. - NodeClaimed(NodePublicKey, AccountId), + NodeClaimed(PeerId, AccountId), /// The given claim was removed by its owner. - ClaimRemoved(NodePublicKey, AccountId), + ClaimRemoved(PeerId, AccountId), /// The node was transferred to another account. - NodeTransferred(NodePublicKey, AccountId, AccountId), + NodeTransferred(PeerId, AccountId, AccountId), /// The allowed connections were added to a node. - ConnectionsAdded(NodePublicKey, Vec), + ConnectionsAdded(PeerId, Vec), /// The allowed connections were removed from a node. - ConnectionsRemoved(NodePublicKey, Vec), + ConnectionsRemoved(PeerId, Vec), } } @@ -172,7 +176,7 @@ decl_module! { /// /// - `node`: identifier of the node. #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] - pub fn add_well_known_node(origin, node: NodePublicKey, owner: T::AccountId) { + pub fn add_well_known_node(origin, node: PeerId, owner: T::AccountId) { T::AddOrigin::ensure_origin(origin)?; let mut nodes = WellKnownNodes::get(); @@ -194,7 +198,7 @@ decl_module! { /// /// - `node`: identifier of the node. #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] - pub fn remove_well_known_node(origin, node: NodePublicKey) { + pub fn remove_well_known_node(origin, node: PeerId) { T::RemoveOrigin::ensure_origin(origin)?; let mut nodes = WellKnownNodes::get(); @@ -217,7 +221,7 @@ decl_module! { /// - `remove`: the node which will be moved out from the list. /// - `add`: the node which will be put in the list. #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] - pub fn swap_well_known_node(origin, remove: NodePublicKey, add: NodePublicKey) { + pub fn swap_well_known_node(origin, remove: PeerId, add: PeerId) { T::SwapOrigin::ensure_origin(origin)?; if remove == add { return Ok(()) } @@ -243,7 +247,7 @@ decl_module! { /// /// - `nodes`: the new nodes for the allow list. #[weight = (T::WeightInfo::reset_well_known_nodes(), DispatchClass::Operational)] - pub fn reset_well_known_nodes(origin, nodes: Vec<(NodePublicKey, T::AccountId)>) { + pub fn reset_well_known_nodes(origin, nodes: Vec<(PeerId, T::AccountId)>) { T::ResetOrigin::ensure_origin(origin)?; ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); @@ -253,11 +257,11 @@ decl_module! { } /// A given node can be claimed by anyone. The owner should be the first to know its - /// public key, so claim it right away! + /// PeerId, so claim it right away! /// /// - `node`: identifier of the node. #[weight = T::WeightInfo::claim_node()] - pub fn claim_node(origin, node: NodePublicKey) { + pub fn claim_node(origin, node: PeerId) { let sender = ensure_signed(origin)?; ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); @@ -271,7 +275,7 @@ decl_module! { /// /// - `node`: identifier of the node. #[weight = T::WeightInfo::remove_claim()] - pub fn remove_claim(origin, node: NodePublicKey) { + pub fn remove_claim(origin, node: PeerId) { let sender = ensure_signed(origin)?; ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -288,7 +292,7 @@ decl_module! { /// - `node`: identifier of the node. /// - `owner`: new owner of the node. #[weight = T::WeightInfo::transfer_node()] - pub fn transfer_node(origin, node: NodePublicKey, owner: T::AccountId) { + pub fn transfer_node(origin, node: PeerId, owner: T::AccountId) { let sender = ensure_signed(origin)?; ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -305,8 +309,8 @@ decl_module! { #[weight = T::WeightInfo::add_connections()] pub fn add_connections( origin, - node: NodePublicKey, - connections: Vec + node: PeerId, + connections: Vec ) { let sender = ensure_signed(origin)?; ensure!(Owners::::contains_key(&node), Error::::NotClaimed); @@ -335,8 +339,8 @@ decl_module! { #[weight = T::WeightInfo::remove_connections()] pub fn remove_connections( origin, - node: NodePublicKey, - connections: Vec + node: PeerId, + connections: Vec ) { let sender = ensure_signed(origin)?; ensure!(Owners::::contains_key(&node), Error::::NotClaimed); @@ -358,11 +362,12 @@ decl_module! { /// Set reserved node every block. If may not be enabled depends on the offchain /// worker CLI flag. fn offchain_worker(now: T::BlockNumber) { - let node_public_key = sp_io::offchain::get_node_public_key(); - match node_public_key { - Err(_) => debug::error!("Error: failed to get public key of node at {:?}", now), - Ok(node) => sp_io::offchain::set_reserved_nodes( - Self::get_authorized_nodes(&node), true + let network_state = sp_io::offchain::network_state(); + match network_state { + Err(_) => debug::error!("Error: failed to get network state of node at {:?}", now), + Ok(state) => sp_io::offchain::set_reserved_nodes( + Self::get_authorized_nodes(&state.peer_id.0), + true ), } } @@ -370,19 +375,19 @@ decl_module! { } impl Module { - fn initialize_nodes(nodes: &Vec<(NodePublicKey, T::AccountId)>) { - let mut node_public_keys = nodes.iter() + fn initialize_nodes(nodes: &Vec<(PeerId, T::AccountId)>) { + let mut peer_ids = nodes.iter() .map(|item| item.0.clone()) - .collect::>(); - node_public_keys.sort(); - WellKnownNodes::put(&node_public_keys); + .collect::>(); + peer_ids.sort(); + WellKnownNodes::put(&peer_ids); for (node, who) in nodes.iter() { Owners::::insert(node, who); } } - fn get_authorized_nodes(node: &NodePublicKey) -> Vec { + fn get_authorized_nodes(node: &PeerId) -> Vec { let mut nodes = AdditionalConnections::get(node); let mut well_known_nodes = WellKnownNodes::get(); @@ -404,7 +409,7 @@ mod tests { parameter_types, ord_parameter_types, }; use frame_system::EnsureSignedBy; - use sp_core::{H256, ed25519::Public}; + use sp_core::H256; use sp_runtime::{Perbill, traits::{BlakeTwo256, IdentityLookup, BadOrigin}, testing::Header}; impl_outer_origin! { @@ -469,10 +474,8 @@ mod tests { type NodeAuthorization = Module; - fn test_node(id: u8) -> NodePublicKey { - let mut arr = [0u8; 32]; - arr[31] = id; - NodePublicKey::Ed25519(Public::from_raw(arr)) + fn test_node(id: u8) -> PeerId { + vec![id] } fn new_test_ext() -> sp_io::TestExternalities { @@ -747,7 +750,7 @@ mod tests { } #[test] - fn get_authorize_nodes_worker() { + fn get_authorize_nodes_works() { new_test_ext().execute_with(|| { AdditionalConnections::insert( test_node(20), vec![test_node(5), test_node(15), test_node(25)] diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 95e1d056c74b4..b3c16d4754141 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -704,14 +704,6 @@ impl sp_std::str::FromStr for AccountId32 { } } -/// Public key of node which can be used for network connection -#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, crate::RuntimeDebug, PassByCodec)] -pub enum NodePublicKey { - /// An Ed25519 public key - Ed25519(ed25519::Public), -} - #[cfg(feature = "std")] pub use self::dummy::*; diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 1fa8492c6824a..2a40972166e14 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -80,7 +80,6 @@ pub use changes_trie::{ChangesTrieConfiguration, ChangesTrieConfigurationRange}; #[cfg(feature = "full_crypto")] pub use crypto::{DeriveJunction, Pair, Public}; -pub use crypto::NodePublicKey; pub use hash_db::Hasher; #[cfg(feature = "std")] pub use self::hasher::blake2::Blake2Hasher; diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 3931ecfb3ae6f..21e918d5371e7 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -19,7 +19,7 @@ use codec::{Encode, Decode}; use sp_std::{prelude::{Vec, Box}, convert::TryFrom}; -use crate::{RuntimeDebug, NodePublicKey}; +use crate::RuntimeDebug; use sp_runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum}; pub use crate::crypto::KeyTypeId; @@ -498,11 +498,8 @@ pub trait Externalities: Send { deadline: Option ) -> Result; - /// Get public key of the node - fn get_node_public_key(&mut self) -> Result; - /// Set the reserved nodes - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool); + fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool); } impl Externalities for Box { @@ -582,11 +579,7 @@ impl Externalities for Box { (&mut **self).http_response_read_body(request_id, buffer, deadline) } - fn get_node_public_key(&mut self) -> Result { - (&mut **self).get_node_public_key() - } - - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { (&mut **self).set_reserved_nodes(nodes, reserved_only) } } @@ -708,12 +701,7 @@ impl Externalities for LimitedExternalities { self.externalities.http_response_read_body(request_id, buffer, deadline) } - fn get_node_public_key(&mut self) -> Result { - self.check(Capability::NodesReservation, "get_node_public_key"); - self.externalities.get_node_public_key() - } - - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { self.check(Capability::NodesReservation, "set_reserved_nodes"); self.externalities.set_reserved_nodes(nodes, reserved_only) } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index a09f5ec4a9b86..43721028b180c 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -36,7 +36,6 @@ use crate::offchain::{ TransactionPool, OffchainStorage, }; -use crate::{NodePublicKey, ed25519}; use parking_lot::RwLock; @@ -377,11 +376,7 @@ impl offchain::Externalities for TestOffchainExt { } } - fn get_node_public_key(&mut self) -> Result { - Ok(NodePublicKey::Ed25519(ed25519::Public([0u8; 32]))) - } - - fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { + fn set_reserved_nodes(&mut self, _nodes: Vec>, _reserved_only: bool) { unimplemented!() } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index cbb7b04143c9b..eb92892d10549 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -42,7 +42,7 @@ use sp_core::{ }; use sp_core::{ - crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, NodePublicKey, + crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState, }, @@ -961,15 +961,8 @@ pub trait Offchain { .map(|r| r as u32) } - /// Get public key of the local node. - fn get_node_public_key(&mut self) -> Result { - self.extension::() - .expect("get_node_public_key can be called only in the offchain worker context") - .get_node_public_key() - } - /// Set the reserved peers - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { self.extension::() .expect("set_reserved_nodes can be called only in the offchain worker context") .set_reserved_nodes(nodes, reserved_only) From e0dce842b5918f148374fa5636f5c9a37a647f5f Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 18:33:01 +0800 Subject: [PATCH 21/34] set max length of peer id. --- frame/node-authorization/src/lib.rs | 70 ++++++++++++++++++++++++++++- primitives/core/src/crypto.rs | 2 +- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 1bf0bac20e2ab..81dde8ad9c5a6 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -79,6 +79,9 @@ pub trait Trait: frame_system::Trait { /// The maximum number of well known nodes that are allowed to set type MaxWellKnownNodes: Get; + /// The maximum length in bytes of PeerId + type MaxPeerIdLength: Get; + /// The origin which can add a well known node. type AddOrigin: EnsureOrigin; @@ -143,6 +146,8 @@ decl_event! { decl_error! { /// Error for the node authorization module. pub enum Error for Module { + /// The PeerId is too long. + PeerIdTooLong, /// Too many well known nodes. TooManyNodes, /// The node is already joined in the list. @@ -165,6 +170,9 @@ decl_module! { /// The maximum number of authorized well known nodes const MaxWellKnownNodes: u32 = T::MaxWellKnownNodes::get(); + /// The maximum length in bytes of PeerId + const MaxPeerIdLength: u32 = T::MaxPeerIdLength::get(); + type Error = Error; fn deposit_event() = default; @@ -178,6 +186,7 @@ decl_module! { #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] pub fn add_well_known_node(origin, node: PeerId, owner: T::AccountId) { T::AddOrigin::ensure_origin(origin)?; + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::get(); ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); @@ -200,6 +209,7 @@ decl_module! { #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] pub fn remove_well_known_node(origin, node: PeerId) { T::RemoveOrigin::ensure_origin(origin)?; + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::get(); @@ -223,6 +233,8 @@ decl_module! { #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] pub fn swap_well_known_node(origin, remove: PeerId, add: PeerId) { T::SwapOrigin::ensure_origin(origin)?; + ensure!(remove.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(add.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); if remove == add { return Ok(()) } @@ -250,7 +262,7 @@ decl_module! { pub fn reset_well_known_nodes(origin, nodes: Vec<(PeerId, T::AccountId)>) { T::ResetOrigin::ensure_origin(origin)?; ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); - + Self::initialize_nodes(&nodes); Self::deposit_event(RawEvent::NodesReset(nodes)); @@ -263,6 +275,8 @@ decl_module! { #[weight = T::WeightInfo::claim_node()] pub fn claim_node(origin, node: PeerId) { let sender = ensure_signed(origin)?; + + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); Owners::::insert(&node, &sender); @@ -277,6 +291,8 @@ decl_module! { #[weight = T::WeightInfo::remove_claim()] pub fn remove_claim(origin, node: PeerId) { let sender = ensure_signed(origin)?; + + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); ensure!(!WellKnownNodes::get().contains(&node), Error::::PermissionDenied); @@ -294,6 +310,8 @@ decl_module! { #[weight = T::WeightInfo::transfer_node()] pub fn transfer_node(origin, node: PeerId, owner: T::AccountId) { let sender = ensure_signed(origin)?; + + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -313,6 +331,8 @@ decl_module! { connections: Vec ) { let sender = ensure_signed(origin)?; + + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -343,6 +363,8 @@ decl_module! { connections: Vec ) { let sender = ensure_signed(origin)?; + + ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -461,10 +483,12 @@ mod tests { } parameter_types! { pub const MaxWellKnownNodes: u32 = 4; + pub const MaxPeerIdLength: u32 = 2; } impl Trait for Test { type Event = (); type MaxWellKnownNodes = MaxWellKnownNodes; + type MaxPeerIdLength = MaxPeerIdLength; type AddOrigin = EnsureSignedBy; type RemoveOrigin = EnsureSignedBy; type SwapOrigin = EnsureSignedBy; @@ -493,6 +517,10 @@ mod tests { NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), BadOrigin ); + assert_noop!( + NodeAuthorization::add_well_known_node(Origin::signed(1), vec![1, 2, 3], 15), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), Error::::AlreadyJoined @@ -524,6 +552,10 @@ mod tests { NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), BadOrigin ); + assert_noop!( + NodeAuthorization::remove_well_known_node(Origin::signed(2), vec![1, 2, 3]), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), Error::::NotExist @@ -550,6 +582,18 @@ mod tests { ), BadOrigin ); + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), vec![1, 2, 3], test_node(20) + ), + Error::::PeerIdTooLong + ); + assert_noop!( + NodeAuthorization::swap_well_known_node( + Origin::signed(3), test_node(20), vec![1, 2, 3] + ), + Error::::PeerIdTooLong + ); assert_ok!( NodeAuthorization::swap_well_known_node( @@ -633,6 +677,10 @@ mod tests { #[test] fn claim_node_works() { new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::claim_node(Origin::signed(1), vec![1, 2, 3]), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), Error::::AlreadyClaimed @@ -646,6 +694,10 @@ mod tests { #[test] fn remove_claim_works() { new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_claim(Origin::signed(15), vec![1, 2, 3]), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), Error::::NotClaimed @@ -672,6 +724,10 @@ mod tests { #[test] fn transfer_node_works() { new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::transfer_node(Origin::signed(15), vec![1, 2, 3], 10), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), Error::::NotClaimed @@ -690,6 +746,12 @@ mod tests { #[test] fn add_connections_works() { new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::add_connections( + Origin::signed(15), vec![1, 2, 3], vec![test_node(5)] + ), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::add_connections( Origin::signed(15), test_node(15), vec![test_node(5)] @@ -721,6 +783,12 @@ mod tests { #[test] fn remove_connections_works() { new_test_ext().execute_with(|| { + assert_noop!( + NodeAuthorization::remove_connections( + Origin::signed(15), vec![1, 2, 3], vec![test_node(5)] + ), + Error::::PeerIdTooLong + ); assert_noop!( NodeAuthorization::remove_connections( Origin::signed(15), test_node(15), vec![test_node(5)] diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index b3c16d4754141..a8d84eb57cff9 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -39,7 +39,7 @@ use base58::{FromBase58, ToBase58}; use crate::hexdisplay::HexDisplay; #[doc(hidden)] pub use sp_std::ops::Deref; -use sp_runtime_interface::pass_by::{PassByInner, PassByCodec}; +use sp_runtime_interface::pass_by::PassByInner; /// Trait to zeroize a memory buffer. pub use zeroize::Zeroize; /// Trait for accessing reference to `SecretString`. From 65cd8eddef79f72cf28744dd8db87d6e01d8842c Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 18:51:15 +0800 Subject: [PATCH 22/34] clear more --- Cargo.lock | 1 - client/network/src/service.rs | 15 ++------------- client/offchain/Cargo.toml | 1 - 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 218fc3770077b..c88e32fcb9c21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7045,7 +7045,6 @@ dependencies = [ "sc-client-db", "sc-keystore", "sc-network", - "sc-peerset", "sc-transaction-pool", "sp-api", "sp-core", diff --git a/client/network/src/service.rs b/client/network/src/service.rs index bf3287989a43d..9befd1c2e41c2 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -30,10 +30,7 @@ use crate::{ ExHashT, NetworkStateInfo, behaviour::{self, Behaviour, BehaviourOut}, - config::{ - parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig, - identity::PublicKey, - }, + config::{parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig}, DhtEvent, discovery::DiscoveryConfig, error::Error, @@ -97,8 +94,6 @@ pub struct NetworkService { is_major_syncing: Arc, /// Local copy of the `PeerId` of the local node. local_peer_id: PeerId, - /// Local copy of the `PublicKey` of the local node. - local_public_key: PublicKey, /// Bandwidth logging system. Can be queried to know the average bandwidth consumed. bandwidth: Arc, /// Peerset manager (PSM); manages the reputation of nodes and indicates the network which @@ -322,7 +317,7 @@ impl NetworkWorker { protocol, params.role, user_agent, - local_public.clone(), + local_public, block_requests, finality_proof_requests, light_client_handler, @@ -403,7 +398,6 @@ impl NetworkWorker { is_major_syncing: is_major_syncing.clone(), peerset: peerset_handle, local_peer_id, - local_public_key: local_public, to_worker, peers_notifications_sinks: peers_notifications_sinks.clone(), protocol_name_by_engine, @@ -602,11 +596,6 @@ impl NetworkService { &self.local_peer_id } - /// Returns the local node `PublicKey`. - pub fn local_public_key(&self) -> &PublicKey { - &self.local_public_key - } - /// Set reserved peers and reserved_only flag. pub fn set_reserved_peers(&self, peers: HashSet, reserved_only: bool) { self.peerset.set_reserved_peers(peers); diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index ffc65b370b725..b3d66365fb41e 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -29,7 +29,6 @@ rand = "0.7.2" sp-runtime = { version = "2.0.0-rc6", path = "../../primitives/runtime" } sp-utils = { version = "2.0.0-rc6", path = "../../primitives/utils" } sc-network = { version = "0.8.0-rc6", path = "../network" } -sc-peerset = { version = "2.0.0-rc6", path = "../peerset" } sc-keystore = { version = "2.0.0-rc6", path = "../keystore" } [target.'cfg(not(target_os = "unknown"))'.dependencies] From d429363339e6ed6fddc8fb21aa3d9927d301e6a5 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Wed, 2 Sep 2020 22:08:33 +0800 Subject: [PATCH 23/34] use BTreeSet for set of peers. --- frame/node-authorization/src/lib.rs | 105 +++++++++++++++++----------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 81dde8ad9c5a6..f92afff8290a6 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -37,7 +37,11 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] -use sp_std::prelude::*; +use sp_std::{ + collections::btree_set::BTreeSet, + iter::FromIterator, + prelude::*, +}; use frame_support::{ decl_module, decl_storage, decl_event, decl_error, debug, ensure, @@ -101,13 +105,13 @@ pub trait Trait: frame_system::Trait { decl_storage! { trait Store for Module as NodeAuthorization { /// The set of well known nodes. This is stored sorted (just by value). - pub WellKnownNodes get(fn well_known_nodes): Vec; + pub WellKnownNodes get(fn well_known_nodes): BTreeSet; /// A map that maintains the ownership of each node. pub Owners get(fn owners): map hasher(blake2_128_concat) PeerId => T::AccountId; /// The additional adapative connections of each node. pub AdditionalConnections get(fn additional_connection): - map hasher(blake2_128_concat) PeerId => Vec; + map hasher(blake2_128_concat) PeerId => BTreeSet; } add_extra_genesis { config(nodes): Vec<(PeerId, T::AccountId)>; @@ -135,7 +139,7 @@ decl_event! { /// The given claim was removed by its owner. ClaimRemoved(PeerId, AccountId), /// The node was transferred to another account. - NodeTransferred(PeerId, AccountId, AccountId), + NodeTransferred(PeerId, AccountId), /// The allowed connections were added to a node. ConnectionsAdded(PeerId, Vec), /// The allowed connections were removed from a node. @@ -190,9 +194,9 @@ decl_module! { let mut nodes = WellKnownNodes::get(); ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); + ensure!(!nodes.contains(&node), Error::::AlreadyJoined); - let location = nodes.binary_search(&node).err().ok_or(Error::::AlreadyJoined)?; - nodes.insert(location, node.clone()); + nodes.insert(node.clone()); WellKnownNodes::put(&nodes); >::insert(&node, &owner); @@ -212,9 +216,9 @@ decl_module! { ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::get(); + ensure!(nodes.contains(&node), Error::::NotExist); - let location = nodes.binary_search(&node).ok().ok_or(Error::::NotExist)?; - nodes.remove(location); + nodes.remove(&node); WellKnownNodes::put(&nodes); >::remove(&node); @@ -239,10 +243,11 @@ decl_module! { if remove == add { return Ok(()) } let mut nodes = WellKnownNodes::get(); - let remove_location = nodes.binary_search(&remove).ok().ok_or(Error::::NotExist)?; - nodes.remove(remove_location); - let add_location = nodes.binary_search(&add).err().ok_or(Error::::AlreadyJoined)?; - nodes.insert(add_location, add.clone()); + ensure!(nodes.contains(&remove), Error::::NotExist); + ensure!(!nodes.contains(&add), Error::::AlreadyJoined); + + nodes.remove(&remove); + nodes.insert(add.clone()); WellKnownNodes::put(&nodes); Owners::::swap(&remove, &add); @@ -317,7 +322,7 @@ decl_module! { Owners::::insert(&node, &owner); - Self::deposit_event(RawEvent::NodeTransferred(node, sender, owner)); + Self::deposit_event(RawEvent::NodeTransferred(node, owner)); } /// Add additional connections to a given node. @@ -342,9 +347,7 @@ decl_module! { if *add_node == node { continue; } - if let Err(add_location) = nodes.binary_search(add_node) { - nodes.insert(add_location, add_node.clone()); - } + nodes.insert(add_node.clone()); } AdditionalConnections::insert(&node, nodes); @@ -371,9 +374,7 @@ decl_module! { let mut nodes = AdditionalConnections::get(&node); for remove_node in connections.iter() { - if let Ok(remove_location) = nodes.binary_search(remove_node) { - nodes.remove(remove_location); - } + nodes.remove(remove_node); } AdditionalConnections::insert(&node, nodes); @@ -398,10 +399,9 @@ decl_module! { impl Module { fn initialize_nodes(nodes: &Vec<(PeerId, T::AccountId)>) { - let mut peer_ids = nodes.iter() + let peer_ids = nodes.iter() .map(|item| item.0.clone()) - .collect::>(); - peer_ids.sort(); + .collect::>(); WellKnownNodes::put(&peer_ids); for (node, who) in nodes.iter() { @@ -413,12 +413,12 @@ impl Module { let mut nodes = AdditionalConnections::get(node); let mut well_known_nodes = WellKnownNodes::get(); - if let Ok(location) = well_known_nodes.binary_search(node) { - well_known_nodes.remove(location); + if well_known_nodes.contains(node) { + well_known_nodes.remove(node); nodes.extend(well_known_nodes); } - nodes + Vec::from_iter(nodes) } } @@ -531,7 +531,7 @@ mod tests { ); assert_eq!( WellKnownNodes::get(), - vec![test_node(10), test_node(15), test_node(20), test_node(30)] + BTreeSet::from_iter(vec![test_node(10), test_node(15), test_node(20), test_node(30)]) ); assert_eq!(Owners::::get(test_node(10)), 10); assert_eq!(Owners::::get(test_node(20)), 20); @@ -561,13 +561,19 @@ mod tests { Error::::NotExist ); - AdditionalConnections::insert(test_node(20), vec![test_node(40)]); + AdditionalConnections::insert( + test_node(20), + BTreeSet::from_iter(vec![test_node(40)]) + ); assert!(AdditionalConnections::contains_key(test_node(20))); assert_ok!( NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20)) ); - assert_eq!(WellKnownNodes::get(), vec![test_node(10), test_node(30)]); + assert_eq!( + WellKnownNodes::get(), + BTreeSet::from_iter(vec![test_node(10), test_node(30)]) + ); assert!(!Owners::::contains_key(test_node(20))); assert!(!AdditionalConnections::contains_key(test_node(20))); }); @@ -602,7 +608,7 @@ mod tests { ); assert_eq!( WellKnownNodes::get(), - vec![test_node(10), test_node(20), test_node(30)] + BTreeSet::from_iter(vec![test_node(10), test_node(20), test_node(30)]) ); assert_noop!( @@ -618,7 +624,10 @@ mod tests { Error::::AlreadyJoined ); - AdditionalConnections::insert(test_node(20), vec![test_node(15)]); + AdditionalConnections::insert( + test_node(20), + BTreeSet::from_iter(vec![test_node(15)]) + ); assert_ok!( NodeAuthorization::swap_well_known_node( Origin::signed(3), test_node(20), test_node(5) @@ -626,12 +635,15 @@ mod tests { ); assert_eq!( WellKnownNodes::get(), - vec![test_node(5), test_node(10), test_node(30)] + BTreeSet::from_iter(vec![test_node(5), test_node(10), test_node(30)]) ); assert!(!Owners::::contains_key(test_node(20))); assert_eq!(Owners::::get(test_node(5)), 20); assert!(!AdditionalConnections::contains_key(test_node(20))); - assert_eq!(AdditionalConnections::get(test_node(5)), vec![test_node(15)]); + assert_eq!( + AdditionalConnections::get(test_node(5)), + BTreeSet::from_iter(vec![test_node(15)]) + ); }); } @@ -666,7 +678,7 @@ mod tests { ); assert_eq!( WellKnownNodes::get(), - vec![test_node(5), test_node(15), test_node(20)] + BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(20)]) ); assert_eq!(Owners::::get(test_node(5)), 5); assert_eq!(Owners::::get(test_node(15)), 15); @@ -714,7 +726,10 @@ mod tests { ); Owners::::insert(test_node(15), 15); - AdditionalConnections::insert(test_node(15), vec![test_node(20)]); + AdditionalConnections::insert( + test_node(15), + BTreeSet::from_iter(vec![test_node(20)]) + ); assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); assert!(!Owners::::contains_key(test_node(15))); assert!(!AdditionalConnections::contains_key(test_node(15))); @@ -775,7 +790,7 @@ mod tests { ); assert_eq!( AdditionalConnections::get(test_node(20)), - vec![test_node(5), test_node(15), test_node(25)] + BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(25)]) ); }); } @@ -804,7 +819,8 @@ mod tests { ); AdditionalConnections::insert( - test_node(20), vec![test_node(5), test_node(15), test_node(25)] + test_node(20), + BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(25)]) ); assert_ok!( NodeAuthorization::remove_connections( @@ -813,19 +829,26 @@ mod tests { vec![test_node(15), test_node(5)] ) ); - assert_eq!(AdditionalConnections::get(test_node(20)), vec![test_node(25)]); + assert_eq!( + AdditionalConnections::get(test_node(20)), + BTreeSet::from_iter(vec![test_node(25)]) + ); }); } #[test] - fn get_authorize_nodes_works() { + fn get_authorized_nodes_works() { new_test_ext().execute_with(|| { AdditionalConnections::insert( - test_node(20), vec![test_node(5), test_node(15), test_node(25)] + test_node(20), + BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(25)]) ); + + let mut authorized_nodes = Module::::get_authorized_nodes(&test_node(20)); + authorized_nodes.sort(); assert_eq!( - Module::::get_authorized_nodes(&test_node(20)), - vec![test_node(5), test_node(15), test_node(25), test_node(10), test_node(30)] + authorized_nodes, + vec![test_node(5), test_node(10), test_node(15), test_node(25), test_node(30)] ); }); } From 12f0386f5e08f0b0a999b6a37445f77eb99e2226 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Thu, 3 Sep 2020 01:57:56 +0800 Subject: [PATCH 24/34] decode opaque peer id. --- frame/node-authorization/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index f92afff8290a6..ad81f2ae677c0 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -42,6 +42,7 @@ use sp_std::{ iter::FromIterator, prelude::*, }; +use codec::Decode; use frame_support::{ decl_module, decl_storage, decl_event, decl_error, debug, ensure, @@ -388,10 +389,16 @@ decl_module! { let network_state = sp_io::offchain::network_state(); match network_state { Err(_) => debug::error!("Error: failed to get network state of node at {:?}", now), - Ok(state) => sp_io::offchain::set_reserved_nodes( - Self::get_authorized_nodes(&state.peer_id.0), - true - ), + Ok(state) => { + let encoded_peer = state.peer_id.0; + match Decode::decode(&mut &encoded_peer[..]) { + Err(_) => debug::error!("Error: failed to decode PeerId at {:?}", now), + Ok(node) => sp_io::offchain::set_reserved_nodes( + Self::get_authorized_nodes(&node), + true + ) + } + } } } } From a18b24848ee5fe4abd4af1deea240932c9937c22 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 15:00:13 +0800 Subject: [PATCH 25/34] extract NetworkProvider for client offchain. --- Cargo.lock | 17 ---- Cargo.toml | 1 - client/network/src/service.rs | 10 ++- client/offchain/Cargo.toml | 1 - client/offchain/src/api.rs | 61 ++++++++++---- client/offchain/src/lib.rs | 69 ++++++++++++--- primitives/core/src/lib.rs | 14 ++- primitives/core/src/offchain/mod.rs | 13 +-- test-utils/runtime/network/Cargo.toml | 24 ------ test-utils/runtime/network/src/lib.rs | 117 -------------------------- 10 files changed, 122 insertions(+), 205 deletions(-) delete mode 100644 test-utils/runtime/network/Cargo.toml delete mode 100644 test-utils/runtime/network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c7224626d9703..93ec8e1b0908a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7110,7 +7110,6 @@ dependencies = [ "sp-transaction-pool", "sp-utils", "substrate-test-runtime-client", - "substrate-test-runtime-network", "threadpool", "tokio 0.2.22", ] @@ -8888,22 +8887,6 @@ dependencies = [ "substrate-test-runtime", ] -[[package]] -name = "substrate-test-runtime-network" -version = "2.0.0-rc6" -dependencies = [ - "async-std", - "futures 0.3.5", - "rand 0.7.3", - "sc-network", - "sc-service", - "sp-blockchain", - "sp-consensus", - "sp-core", - "sp-runtime", - "substrate-test-runtime-client", -] - [[package]] name = "substrate-test-runtime-transaction-pool" version = "2.0.0-rc6" diff --git a/Cargo.toml b/Cargo.toml index 87d4bffc86651..534b71357cc76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -175,7 +175,6 @@ members = [ "test-utils/derive", "test-utils/runtime", "test-utils/runtime/client", - "test-utils/runtime/network", "test-utils/runtime/transaction-pool", "test-utils/test-crate", "utils/browser", diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 8eae75e743983..03648c2a077dc 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -605,9 +605,13 @@ impl NetworkService { &self.local_peer_id } - /// Set reserved peers and reserved_only flag. - pub fn set_reserved_peers(&self, peers: HashSet, reserved_only: bool) { - self.peerset.set_reserved_peers(peers); + /// Set reserved peers. + pub fn set_reserved_peers(&self, peers: HashSet) { + self.peerset.set_reserved_peers(peers) + } + + /// Set reserved_only flag. + pub fn set_reserved_only(&self, reserved_only: bool) { self.peerset.set_reserved_only(reserved_only) } diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index b3d66365fb41e..9f574ff9ebe46 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -41,7 +41,6 @@ sc-client-db = { version = "0.8.0-rc6", default-features = true, path = "../db/" sc-transaction-pool = { version = "2.0.0-rc6", path = "../../client/transaction-pool" } sp-transaction-pool = { version = "2.0.0-rc6", path = "../../primitives/transaction-pool" } substrate-test-runtime-client = { version = "2.0.0-rc6", path = "../../test-utils/runtime/client" } -substrate-test-runtime-network = { version = "2.0.0-rc6", path = "../../test-utils/runtime/network" } tokio = "0.2" lazy_static = "1.4.0" diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 501566d8d0aba..1143a863b51e4 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -22,16 +22,16 @@ use std::{ collections::HashSet, }; -use sp_core::offchain::OffchainStorage; +use crate::NetworkProvider; use futures::Future; use log::error; -use sc_network::{PeerId, Multiaddr, NetworkService, NetworkStateInfo}; +use sc_network::{PeerId, Multiaddr}; use codec::{Encode, Decode}; +use sp_core::OpaquePeerId; use sp_core::offchain::{ Externalities as OffchainExt, HttpRequestId, Timestamp, HttpRequestStatus, HttpError, - OpaqueNetworkState, OpaquePeerId, OpaqueMultiaddr, StorageKind, + OffchainStorage, OpaqueNetworkState, OpaqueMultiaddr, StorageKind, }; -use sp_runtime::traits::Block as BlockT; pub use sp_offchain::STORAGE_PREFIX; pub use http::SharedClient; @@ -48,11 +48,11 @@ mod timestamp; /// Asynchronous offchain API. /// /// NOTE this is done to prevent recursive calls into the runtime (which are not supported currently). -pub(crate) struct Api { +pub(crate) struct Api { /// Offchain Workers database. db: Storage, - /// A NetworkService provider. - network_service: Arc::Hash>>, + /// A provider for substrate networking. + network_provider: Arc, /// Is this node a potential validator? is_validator: bool, /// Everything HTTP-related is handled by a different struct. @@ -69,16 +69,16 @@ fn unavailable_yet(name: &str) -> R { const LOCAL_DB: &str = "LOCAL (fork-aware) DB"; -impl OffchainExt for Api { +impl OffchainExt for Api { fn is_validator(&self) -> bool { self.is_validator } fn network_state(&self) -> Result { - let external_addresses = self.network_service.external_addresses(); + let external_addresses = self.network_provider.external_addresses(); let state = NetworkState::new( - self.network_service.local_peer_id().clone(), + self.network_provider.local_peer_id(), external_addresses, ); Ok(OpaqueNetworkState::from(state)) @@ -188,7 +188,8 @@ impl OffchainExt for Api( + /// Creates new Offchain extensions API implementation an the asynchronous processing part. + pub fn new( db: S, - network_service: Arc::Hash>>, + network_provider: Arc, is_validator: bool, shared_client: SharedClient, - ) -> (Api, Self) { + ) -> (Api, Self) { let (http_api, http_worker) = http::http(shared_client); let api = Api { db, - network_service, + network_provider, is_validator, http: http_api, }; @@ -302,15 +303,39 @@ mod tests { use super::*; use std::{convert::{TryFrom, TryInto}, time::SystemTime}; use sc_client_db::offchain::LocalStorage; + use sc_network::{NetworkStateInfo, PeerId}; - fn offchain_api() -> (Api, AsyncApi) { + struct TestNetwork(); + + impl NetworkProvider for TestNetwork { + fn set_reserved_peers(&self, _peers: HashSet) { + unimplemented!() + } + + fn set_reserved_only(&self, _reserved_only: bool) { + unimplemented!() + } + } + + impl NetworkStateInfo for TestNetwork { + fn external_addresses(&self) -> Vec { + Vec::new() + } + + fn local_peer_id(&self) -> PeerId { + PeerId::random() + } + } + + fn offchain_api() -> (Api, AsyncApi) { let _ = env_logger::try_init(); let db = LocalStorage::new_test(); + let mock = Arc::new(TestNetwork()); let shared_client = SharedClient::new(); AsyncApi::new( db, - substrate_test_runtime_network::build_network_service(), + mock, false, shared_client, ) diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 349906aa337a4..4118bd054212b 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -33,14 +33,17 @@ #![warn(missing_docs)] -use std::{fmt, marker::PhantomData, sync::Arc}; +use std::{ + fmt, marker::PhantomData, sync::Arc, + collections::HashSet, +}; use parking_lot::Mutex; use threadpool::ThreadPool; use sp_api::{ApiExt, ProvideRuntimeApi}; use futures::future::Future; use log::{debug, warn}; -use sc_network::NetworkService; +use sc_network::{ExHashT, NetworkService, NetworkStateInfo, PeerId}; use sp_core::{offchain::{self, OffchainStorage}, ExecutionContext, traits::SpawnNamed}; use sp_runtime::{generic::BlockId, traits::{self, Header}}; use futures::{prelude::*, future::ready}; @@ -50,6 +53,30 @@ use api::SharedClient; pub use sp_offchain::{OffchainWorkerApi, STORAGE_PREFIX}; +/// NetworkProvider provides [`OffchainWorkers`] with all necessary hooks into the +/// underlying Substrate networking. +pub trait NetworkProvider: NetworkStateInfo { + /// Set the reserved peers. + fn set_reserved_peers(&self, peers: HashSet); + + /// Set the reserved only flag. + fn set_reserved_only(&self, reserved_only: bool); +} + +impl NetworkProvider for NetworkService +where + B: traits::Block + 'static, + H: ExHashT, +{ + fn set_reserved_peers(&self, peers: HashSet) { + self.set_reserved_peers(peers) + } + + fn set_reserved_only(&self, reserved_only: bool) { + self.set_reserved_only(reserved_only) + } +} + /// An offchain workers manager. pub struct OffchainWorkers { client: Arc, @@ -98,7 +125,7 @@ impl OffchainWorkers< pub fn on_block_imported( &self, header: &Block::Header, - network_service: Arc::Hash>>, + network_provider: Arc, is_validator: bool, ) -> impl Future { let runtime = self.client.runtime_api(); @@ -122,7 +149,7 @@ impl OffchainWorkers< if version > 0 { let (api, runner) = api::AsyncApi::new( self.db.clone(), - network_service, + network_provider, is_validator, self.shared_client.clone(), ); @@ -173,7 +200,7 @@ pub async fn notification_future( client: Arc, offchain: Arc>, spawner: Spawner, - network_service: Arc::Hash>>, + network_provider: Arc, ) where Block: traits::Block, @@ -188,7 +215,7 @@ pub async fn notification_future( "offchain-on-block", offchain.on_block_imported( &n.header, - network_service.clone(), + network_provider.clone(), is_validator, ).boxed(), ); @@ -208,10 +235,33 @@ pub async fn notification_future( mod tests { use super::*; use std::sync::Arc; + use sc_network::{Multiaddr, PeerId}; use substrate_test_runtime_client::{TestClient, runtime::Block}; use sc_transaction_pool::{BasicPool, FullChainApi}; use sp_transaction_pool::{TransactionPool, InPoolTransaction}; + struct TestNetwork(); + + impl NetworkStateInfo for TestNetwork { + fn external_addresses(&self) -> Vec { + Vec::new() + } + + fn local_peer_id(&self) -> PeerId { + PeerId::random() + } + } + + impl NetworkProvider for TestNetwork { + fn set_reserved_peers(&self, _peers: HashSet) { + unimplemented!() + } + + fn set_reserved_only(&self, _reserved_only: bool) { + unimplemented!() + } + } + struct TestPool( Arc, Block>> ); @@ -242,16 +292,13 @@ mod tests { client.clone(), )); let db = sc_client_db::offchain::LocalStorage::new_test(); + let network = Arc::new(TestNetwork()); let header = client.header(&BlockId::number(0)).unwrap().unwrap(); // when let offchain = OffchainWorkers::new(client, db); futures::executor::block_on( - offchain.on_block_imported( - &header, - substrate_test_runtime_network::build_network_service(), - false - ) + offchain.on_block_imported(&header, network, false) ); // then diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 2a40972166e14..003788d52123c 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -32,6 +32,7 @@ macro_rules! map { ); } +use sp_runtime_interface::pass_by::{PassByEnum, PassByInner}; use sp_std::prelude::*; use sp_std::ops::Deref; #[cfg(feature = "std")] @@ -176,6 +177,17 @@ impl sp_std::ops::Deref for OpaqueMetadata { } } +/// Simple blob to hold a `PeerId` without committing to its format. +#[derive(Default, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)] +pub struct OpaquePeerId(pub Vec); + +impl OpaquePeerId { + /// Create new `OpaquePeerId` + pub fn new(vec: Vec) -> Self { + OpaquePeerId(vec) + } +} + /// Something that is either a native or an encoded value. #[cfg(feature = "std")] pub enum NativeOrEncoded { @@ -257,7 +269,7 @@ pub trait TypeId { /// A log level matching the one from `log` crate. /// /// Used internally by `sp_io::log` method. -#[derive(Encode, Decode, sp_runtime_interface::pass_by::PassByEnum, Copy, Clone)] +#[derive(Encode, Decode, PassByEnum, Copy, Clone)] pub enum LogLevel { /// `Error` log level. Error = 1, diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 21e918d5371e7..eafffe4123221 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -19,7 +19,7 @@ use codec::{Encode, Decode}; use sp_std::{prelude::{Vec, Box}, convert::TryFrom}; -use crate::RuntimeDebug; +use crate::{OpaquePeerId, RuntimeDebug}; use sp_runtime_interface::pass_by::{PassByCodec, PassByInner, PassByEnum}; pub use crate::crypto::KeyTypeId; @@ -190,17 +190,6 @@ pub struct OpaqueNetworkState { pub external_addresses: Vec, } -/// Simple blob to hold a `PeerId` without committing to its format. -#[derive(Default, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)] -pub struct OpaquePeerId(pub Vec); - -impl OpaquePeerId { - /// Create new `OpaquePeerId` - pub fn new(vec: Vec) -> Self { - OpaquePeerId(vec) - } -} - /// Simple blob to hold a `Multiaddr` without committing to its format. #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)] pub struct OpaqueMultiaddr(pub Vec); diff --git a/test-utils/runtime/network/Cargo.toml b/test-utils/runtime/network/Cargo.toml deleted file mode 100644 index c6b98d86a7c21..0000000000000 --- a/test-utils/runtime/network/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "substrate-test-runtime-network" -version = "2.0.0-rc6" -authors = ["Parity Technologies "] -edition = "2018" -license = "Apache-2.0" -homepage = "https://substrate.dev" -repository = "https://github.com/paritytech/substrate/" -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -async-std = { version = "1.6.2", features = ["unstable"] } -futures = "0.3.4" -rand = "0.7.2" -sc-service = { version = "0.8.0-rc6", default-features = false, path = "../../../client/service" } -sc-network = { version = "0.8.0-rc6", path = "../../../client/network" } -sp-blockchain = { version = "2.0.0-rc6", path = "../../../primitives/blockchain" } -sp-consensus = { version = "0.8.0-rc6", path = "../../../primitives/consensus/common" } -sp-core = { version = "2.0.0-rc6", path = "../../../primitives/core" } -sp-runtime = { version = "2.0.0-rc6", path = "../../../primitives/runtime" } -substrate-test-runtime-client = { version = "2.0.0-rc6", path = "../../runtime/client" } diff --git a/test-utils/runtime/network/src/lib.rs b/test-utils/runtime/network/src/lib.rs deleted file mode 100644 index 6cb36c9e8698f..0000000000000 --- a/test-utils/runtime/network/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::sync::Arc; -use futures::prelude::*; -use sc_network::{config, Event, NetworkService, NetworkWorker}; -use sp_runtime::traits::{Block as BlockT, Header as _}; -use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; - -pub type TestNetworkService = NetworkService< - substrate_test_runtime_client::runtime::Block, - substrate_test_runtime_client::runtime::Hash, ->; - -/// Builds a full node to be used for testing. Returns the node service and its associated events -/// stream. -/// -/// > **Note**: We return the events stream in order to not possibly lose events between the -/// > construction of the service and the moment the events stream is grabbed. -pub fn build_test_full_node(config: config::NetworkConfiguration) - -> (Arc, impl Stream) -{ - let client = Arc::new( - TestClientBuilder::with_default_backend() - .build_with_longest_chain() - .0, - ); - - #[derive(Clone)] - struct PassThroughVerifier(bool); - impl sp_consensus::import_queue::Verifier for PassThroughVerifier { - fn verify( - &mut self, - origin: sp_consensus::BlockOrigin, - header: B::Header, - justification: Option, - body: Option>, - ) -> Result< - ( - sp_consensus::BlockImportParams, - Option)>>, - ), - String, - > { - let maybe_keys = header - .digest() - .log(|l| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) - .or_else(|| { - l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"babe")) - }) - }) - .map(|blob| { - vec![( - sp_blockchain::well_known_cache_keys::AUTHORITIES, - blob.to_vec(), - )] - }); - - let mut import = sp_consensus::BlockImportParams::new(origin, header); - import.body = body; - import.finalized = self.0; - import.justification = justification; - import.fork_choice = Some(sp_consensus::ForkChoiceStrategy::LongestChain); - Ok((import, maybe_keys)) - } - } - - let import_queue = Box::new(sp_consensus::import_queue::BasicQueue::new( - PassThroughVerifier(false), - Box::new(client.clone()), - None, - None, - &sp_core::testing::TaskExecutor::new(), - None, - )); - - let worker = NetworkWorker::new(config::Params { - role: config::Role::Full, - executor: None, - network_config: config, - chain: client.clone(), - finality_proof_provider: None, - finality_proof_request_builder: None, - on_demand: None, - transaction_pool: Arc::new(config::EmptyTransactionPool), - protocol_id: config::ProtocolId::from("/test-protocol-name"), - import_queue, - block_announce_validator: Box::new( - sp_consensus::block_validation::DefaultBlockAnnounceValidator, - ), - metrics_registry: None, - }) - .unwrap(); - - let service = worker.service().clone(); - let event_stream = service.event_stream("test"); - - async_std::task::spawn(async move { - futures::pin_mut!(worker); - let _ = worker.await; - }); - - (service, event_stream) -} - -const ENGINE_ID: sp_runtime::ConsensusEngineId = *b"foo\0"; - -/// Build a NetworkService -pub fn build_network_service() -> Arc { - let listen_addr = config::build_multiaddr![Memory(rand::random::())]; - build_test_full_node( - config::NetworkConfiguration { - notifications_protocols: vec![(ENGINE_ID, From::from("/foo"))], - listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, - .. config::NetworkConfiguration::new_local() - } - ).0 -} From 76c7535d817cd4dff0c7e4231ce1194adf811932 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 16:47:33 +0800 Subject: [PATCH 26/34] use OpaquePeerId in node authorization pallet. --- client/offchain/src/api.rs | 4 ++-- frame/node-authorization/Cargo.toml | 3 +-- frame/node-authorization/src/lib.rs | 27 ++++++++++++------------- primitives/core/src/lib.rs | 2 +- primitives/core/src/offchain/mod.rs | 6 +++--- primitives/core/src/offchain/testing.rs | 3 ++- primitives/io/src/lib.rs | 4 ++-- 7 files changed, 24 insertions(+), 25 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 1143a863b51e4..33571ca7d2bc1 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -183,9 +183,9 @@ impl OffchainExt for Api { self.http.response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { let peer_ids: HashSet = nodes.iter() - .filter_map(|node| PeerId::from_bytes(node.clone()).ok()) + .filter_map(|node| PeerId::from_bytes(node.0.clone()).ok()) .collect(); self.network_provider.set_reserved_peers(peer_ids); diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index 02e49e7d5677e..d7fcc81f49b82 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -19,8 +19,6 @@ frame-system = { version = "2.0.0-rc6", default-features = false, path = "../sys sp-core = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/core" } sp-io = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } - -[dev-dependencies] sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } [features] @@ -32,5 +30,6 @@ std = [ "frame-system/std", "sp-core/std", "sp-io/std", + "sp-runtime/std", "sp-std/std", ] diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index ad81f2ae677c0..79cd43ca6db6e 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -37,6 +37,7 @@ // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] +use sp_core::OpaquePeerId as PeerId; use sp_std::{ collections::btree_set::BTreeSet, iter::FromIterator, @@ -51,8 +52,6 @@ use frame_support::{ }; use frame_system::ensure_signed; -type PeerId = Vec; - pub trait WeightInfo { fn add_well_known_node() -> Weight; fn remove_well_known_node() -> Weight; @@ -191,7 +190,7 @@ decl_module! { #[weight = (T::WeightInfo::add_well_known_node(), DispatchClass::Operational)] pub fn add_well_known_node(origin, node: PeerId, owner: T::AccountId) { T::AddOrigin::ensure_origin(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::get(); ensure!(nodes.len() < T::MaxWellKnownNodes::get() as usize, Error::::TooManyNodes); @@ -214,7 +213,7 @@ decl_module! { #[weight = (T::WeightInfo::remove_well_known_node(), DispatchClass::Operational)] pub fn remove_well_known_node(origin, node: PeerId) { T::RemoveOrigin::ensure_origin(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); let mut nodes = WellKnownNodes::get(); ensure!(nodes.contains(&node), Error::::NotExist); @@ -238,8 +237,8 @@ decl_module! { #[weight = (T::WeightInfo::swap_well_known_node(), DispatchClass::Operational)] pub fn swap_well_known_node(origin, remove: PeerId, add: PeerId) { T::SwapOrigin::ensure_origin(origin)?; - ensure!(remove.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); - ensure!(add.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(remove.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(add.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); if remove == add { return Ok(()) } @@ -282,7 +281,7 @@ decl_module! { pub fn claim_node(origin, node: PeerId) { let sender = ensure_signed(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(!Owners::::contains_key(&node),Error::::AlreadyClaimed); Owners::::insert(&node, &sender); @@ -298,7 +297,7 @@ decl_module! { pub fn remove_claim(origin, node: PeerId) { let sender = ensure_signed(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); ensure!(!WellKnownNodes::get().contains(&node), Error::::PermissionDenied); @@ -317,7 +316,7 @@ decl_module! { pub fn transfer_node(origin, node: PeerId, owner: T::AccountId) { let sender = ensure_signed(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -338,7 +337,7 @@ decl_module! { ) { let sender = ensure_signed(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -368,7 +367,7 @@ decl_module! { ) { let sender = ensure_signed(origin)?; - ensure!(node.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); + ensure!(node.0.len() < T::MaxPeerIdLength::get() as usize, Error::::PeerIdTooLong); ensure!(Owners::::contains_key(&node), Error::::NotClaimed); ensure!(Owners::::get(&node) == sender, Error::::NotOwner); @@ -383,8 +382,8 @@ decl_module! { Self::deposit_event(RawEvent::ConnectionsRemoved(node, connections)); } - /// Set reserved node every block. If may not be enabled depends on the offchain - /// worker CLI flag. + /// Set reserved node every block. It may not be enabled depends on the offchain + /// worker settings when starting the node. fn offchain_worker(now: T::BlockNumber) { let network_state = sp_io::offchain::network_state(); match network_state { @@ -394,7 +393,7 @@ decl_module! { match Decode::decode(&mut &encoded_peer[..]) { Err(_) => debug::error!("Error: failed to decode PeerId at {:?}", now), Ok(node) => sp_io::offchain::set_reserved_nodes( - Self::get_authorized_nodes(&node), + Self::get_authorized_nodes(&PeerId(node)), true ) } diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 003788d52123c..44266e4a3d435 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -178,7 +178,7 @@ impl sp_std::ops::Deref for OpaqueMetadata { } /// Simple blob to hold a `PeerId` without committing to its format. -#[derive(Default, Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByInner)] +#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, PassByInner)] pub struct OpaquePeerId(pub Vec); impl OpaquePeerId { diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index eafffe4123221..255e925f9c344 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -488,7 +488,7 @@ pub trait Externalities: Send { ) -> Result; /// Set the reserved nodes - fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool); + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool); } impl Externalities for Box { @@ -568,7 +568,7 @@ impl Externalities for Box { (&mut **self).http_response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { (&mut **self).set_reserved_nodes(nodes, reserved_only) } } @@ -690,7 +690,7 @@ impl Externalities for LimitedExternalities { self.externalities.http_response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { self.check(Capability::NodesReservation, "set_reserved_nodes"); self.externalities.set_reserved_nodes(nodes, reserved_only) } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index 43721028b180c..fd0d22e3b0448 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -24,6 +24,7 @@ use std::{ collections::{BTreeMap, VecDeque}, sync::Arc, }; +use crate::OpaquePeerId; use crate::offchain::{ self, storage::{InMemOffchainStorage, OffchainOverlayedChange, OffchainOverlayedChanges}, @@ -376,7 +377,7 @@ impl offchain::Externalities for TestOffchainExt { } } - fn set_reserved_nodes(&mut self, _nodes: Vec>, _reserved_only: bool) { + fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { unimplemented!() } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index eb92892d10549..29b1bc7de8bc4 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -42,7 +42,7 @@ use sp_core::{ }; use sp_core::{ - crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, + OpaquePeerId, crypto::KeyTypeId, ed25519, sr25519, ecdsa, H256, LogLevel, offchain::{ Timestamp, HttpRequestId, HttpRequestStatus, HttpError, StorageKind, OpaqueNetworkState, }, @@ -962,7 +962,7 @@ pub trait Offchain { } /// Set the reserved peers - fn set_reserved_nodes(&mut self, nodes: Vec>, reserved_only: bool) { + fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { self.extension::() .expect("set_reserved_nodes can be called only in the offchain worker context") .set_reserved_nodes(nodes, reserved_only) From 2430b16abbfb7bd12b9f777692b6e706cf51486d Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 16:56:29 +0800 Subject: [PATCH 27/34] fix test --- frame/node-authorization/Cargo.toml | 2 +- frame/node-authorization/src/lib.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/frame/node-authorization/Cargo.toml b/frame/node-authorization/Cargo.toml index d7fcc81f49b82..b05430c452cc6 100644 --- a/frame/node-authorization/Cargo.toml +++ b/frame/node-authorization/Cargo.toml @@ -18,8 +18,8 @@ frame-support = { version = "2.0.0-rc6", default-features = false, path = "../su frame-system = { version = "2.0.0-rc6", default-features = false, path = "../system" } sp-core = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/core" } sp-io = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/io" } -sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } sp-runtime = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "2.0.0-rc6", default-features = false, path = "../../primitives/std" } [features] default = ["std"] diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 79cd43ca6db6e..7cb6bdb9b8232 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -505,7 +505,7 @@ mod tests { type NodeAuthorization = Module; fn test_node(id: u8) -> PeerId { - vec![id] + PeerId(vec![id]) } fn new_test_ext() -> sp_io::TestExternalities { @@ -524,7 +524,7 @@ mod tests { BadOrigin ); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), vec![1, 2, 3], 15), + NodeAuthorization::add_well_known_node(Origin::signed(1), PeerId(vec![1, 2, 3]), 15), Error::::PeerIdTooLong ); assert_noop!( @@ -559,7 +559,7 @@ mod tests { BadOrigin ); assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), vec![1, 2, 3]), + NodeAuthorization::remove_well_known_node(Origin::signed(2), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( @@ -596,13 +596,13 @@ mod tests { ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), vec![1, 2, 3], test_node(20) + Origin::signed(3), PeerId(vec![1, 2, 3]), test_node(20) ), Error::::PeerIdTooLong ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), test_node(20), vec![1, 2, 3] + Origin::signed(3), test_node(20), PeerId(vec![1, 2, 3]) ), Error::::PeerIdTooLong ); @@ -696,7 +696,7 @@ mod tests { fn claim_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), vec![1, 2, 3]), + NodeAuthorization::claim_node(Origin::signed(1), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( @@ -713,7 +713,7 @@ mod tests { fn remove_claim_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), vec![1, 2, 3]), + NodeAuthorization::remove_claim(Origin::signed(15), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( @@ -746,7 +746,7 @@ mod tests { fn transfer_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), vec![1, 2, 3], 10), + NodeAuthorization::transfer_node(Origin::signed(15), PeerId(vec![1, 2, 3]), 10), Error::::PeerIdTooLong ); assert_noop!( @@ -769,7 +769,7 @@ mod tests { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), vec![1, 2, 3], vec![test_node(5)] + Origin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), Error::::PeerIdTooLong ); @@ -806,7 +806,7 @@ mod tests { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), vec![1, 2, 3], vec![test_node(5)] + Origin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), Error::::PeerIdTooLong ); From a6929c1a30a1ebfa46bd29d4f201d1bee5bfa827 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 18:07:49 +0800 Subject: [PATCH 28/34] better documentation --- client/network/src/service.rs | 14 ++++++++---- client/offchain/src/api.rs | 10 ++++----- client/offchain/src/lib.rs | 20 ++++++++--------- frame/node-authorization/src/lib.rs | 2 +- primitives/core/src/offchain/mod.rs | 29 ++++++++++++++++--------- primitives/core/src/offchain/testing.rs | 2 +- primitives/io/src/lib.rs | 8 +++---- 7 files changed, 50 insertions(+), 35 deletions(-) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 03648c2a077dc..bad0044ada6b7 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -605,13 +605,19 @@ impl NetworkService { &self.local_peer_id } - /// Set reserved peers. - pub fn set_reserved_peers(&self, peers: HashSet) { + /// Set authorized peers. + /// + /// Needs a better solution to manage authorized peers, but now just use reserved peers for + /// prototyping. + pub fn set_authorized_peers(&self, peers: HashSet) { self.peerset.set_reserved_peers(peers) } - /// Set reserved_only flag. - pub fn set_reserved_only(&self, reserved_only: bool) { + /// Set authorized_only flag. + /// + /// Needs a better solution to decide authorized_only, but now just use reserved_only flag for + /// prototyping. + pub fn set_authorized_only(&self, reserved_only: bool) { self.peerset.set_reserved_only(reserved_only) } diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 33571ca7d2bc1..a32cb374c42b5 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -183,13 +183,13 @@ impl OffchainExt for Api { self.http.response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { let peer_ids: HashSet = nodes.iter() .filter_map(|node| PeerId::from_bytes(node.0.clone()).ok()) .collect(); - self.network_provider.set_reserved_peers(peer_ids); - self.network_provider.set_reserved_only(reserved_only); + self.network_provider.set_authorized_peers(peer_ids); + self.network_provider.set_authorized_only(authorized_only); } } @@ -308,11 +308,11 @@ mod tests { struct TestNetwork(); impl NetworkProvider for TestNetwork { - fn set_reserved_peers(&self, _peers: HashSet) { + fn set_authorized_peers(&self, _peers: HashSet) { unimplemented!() } - fn set_reserved_only(&self, _reserved_only: bool) { + fn set_authorized_only(&self, _reserved_only: bool) { unimplemented!() } } diff --git a/client/offchain/src/lib.rs b/client/offchain/src/lib.rs index 4118bd054212b..89f2b7b8100b2 100644 --- a/client/offchain/src/lib.rs +++ b/client/offchain/src/lib.rs @@ -56,11 +56,11 @@ pub use sp_offchain::{OffchainWorkerApi, STORAGE_PREFIX}; /// NetworkProvider provides [`OffchainWorkers`] with all necessary hooks into the /// underlying Substrate networking. pub trait NetworkProvider: NetworkStateInfo { - /// Set the reserved peers. - fn set_reserved_peers(&self, peers: HashSet); + /// Set the authorized peers. + fn set_authorized_peers(&self, peers: HashSet); - /// Set the reserved only flag. - fn set_reserved_only(&self, reserved_only: bool); + /// Set the authorized only flag. + fn set_authorized_only(&self, reserved_only: bool); } impl NetworkProvider for NetworkService @@ -68,12 +68,12 @@ where B: traits::Block + 'static, H: ExHashT, { - fn set_reserved_peers(&self, peers: HashSet) { - self.set_reserved_peers(peers) + fn set_authorized_peers(&self, peers: HashSet) { + self.set_authorized_peers(peers) } - fn set_reserved_only(&self, reserved_only: bool) { - self.set_reserved_only(reserved_only) + fn set_authorized_only(&self, reserved_only: bool) { + self.set_authorized_only(reserved_only) } } @@ -253,11 +253,11 @@ mod tests { } impl NetworkProvider for TestNetwork { - fn set_reserved_peers(&self, _peers: HashSet) { + fn set_authorized_peers(&self, _peers: HashSet) { unimplemented!() } - fn set_reserved_only(&self, _reserved_only: bool) { + fn set_authorized_only(&self, _reserved_only: bool) { unimplemented!() } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 7cb6bdb9b8232..9b401091beb02 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -392,7 +392,7 @@ decl_module! { let encoded_peer = state.peer_id.0; match Decode::decode(&mut &encoded_peer[..]) { Err(_) => debug::error!("Error: failed to decode PeerId at {:?}", now), - Ok(node) => sp_io::offchain::set_reserved_nodes( + Ok(node) => sp_io::offchain::set_authorized_nodes( Self::get_authorized_nodes(&PeerId(node)), true ) diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 255e925f9c344..ef8d2a9a14b2d 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -184,7 +184,7 @@ impl TryFrom for HttpRequestStatus { #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, PassByCodec)] #[cfg_attr(feature = "std", derive(Default))] pub struct OpaqueNetworkState { - /// PeerId of the local node. + /// PeerId of the local node in SCALE encoded. pub peer_id: OpaquePeerId, /// List of addresses the node knows it can be reached as. pub external_addresses: Vec, @@ -266,8 +266,8 @@ pub enum Capability { OffchainWorkerDbRead = 32, /// Access to offchain worker DB (writes). OffchainWorkerDbWrite = 64, - /// Manage the reserved nodes - NodesReservation = 128, + /// Manage the authorized nodes + NodeAuthorization = 128, } /// A set of capabilities @@ -487,8 +487,17 @@ pub trait Externalities: Send { deadline: Option ) -> Result; - /// Set the reserved nodes - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool); + /// Set the authorized nodes from runtime. + /// + /// In a permissioned network, the connection between nodes needs to reach a + /// consensus between participants. + /// + /// - `nodes`: set of nodes which are allowed to connect for the local node. + /// each one is identified with an `OpaquePeerId`, here it just use plain bytes + /// without any encoding. + /// - `authorized_only`: if true, only the authorized nodes are allowed to connect, + /// otherwise unauthorized nodes can also be connected through other mechanism. + fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool); } impl Externalities for Box { @@ -568,8 +577,8 @@ impl Externalities for Box { (&mut **self).http_response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { - (&mut **self).set_reserved_nodes(nodes, reserved_only) + fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { + (&mut **self).set_authorized_nodes(nodes, authorized_only) } } @@ -690,9 +699,9 @@ impl Externalities for LimitedExternalities { self.externalities.http_response_read_body(request_id, buffer, deadline) } - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { - self.check(Capability::NodesReservation, "set_reserved_nodes"); - self.externalities.set_reserved_nodes(nodes, reserved_only) + fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { + self.check(Capability::NodeAuthorization, "set_authorized_nodes"); + self.externalities.set_authorized_nodes(nodes, authorized_only) } } diff --git a/primitives/core/src/offchain/testing.rs b/primitives/core/src/offchain/testing.rs index fd0d22e3b0448..3fe34cc0cfa7b 100644 --- a/primitives/core/src/offchain/testing.rs +++ b/primitives/core/src/offchain/testing.rs @@ -377,7 +377,7 @@ impl offchain::Externalities for TestOffchainExt { } } - fn set_reserved_nodes(&mut self, _nodes: Vec, _reserved_only: bool) { + fn set_authorized_nodes(&mut self, _nodes: Vec, _authorized_only: bool) { unimplemented!() } } diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 29b1bc7de8bc4..3248efaa17e50 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -961,11 +961,11 @@ pub trait Offchain { .map(|r| r as u32) } - /// Set the reserved peers - fn set_reserved_nodes(&mut self, nodes: Vec, reserved_only: bool) { + /// Set the authorized nodes and authorized_only flag. + fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { self.extension::() - .expect("set_reserved_nodes can be called only in the offchain worker context") - .set_reserved_nodes(nodes, reserved_only) + .expect("set_authorized_nodes can be called only in the offchain worker context") + .set_authorized_nodes(nodes, authorized_only) } } From 36f3829342347bdee0fa8ae00fd8ae714b873f23 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 18:25:45 +0800 Subject: [PATCH 29/34] fix test --- frame/im-online/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 835d8440e6d5b..22c6b4464c370 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::*; +use sp_core::OpaquePeerId; use sp_core::offchain::{ - OpaquePeerId, OffchainExt, TransactionPoolExt, testing::{TestOffchainExt, TestTransactionPoolExt}, From 889dfe681ea50a28a15122ef77c65aa2009de4f7 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 18:58:43 +0800 Subject: [PATCH 30/34] doc --- client/network/src/service.rs | 4 ++-- primitives/core/src/offchain/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/network/src/service.rs b/client/network/src/service.rs index bad0044ada6b7..d1248057cc79f 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -607,7 +607,7 @@ impl NetworkService { /// Set authorized peers. /// - /// Needs a better solution to manage authorized peers, but now just use reserved peers for + /// Need a better solution to manage authorized peers, but now just use reserved peers for /// prototyping. pub fn set_authorized_peers(&self, peers: HashSet) { self.peerset.set_reserved_peers(peers) @@ -615,7 +615,7 @@ impl NetworkService { /// Set authorized_only flag. /// - /// Needs a better solution to decide authorized_only, but now just use reserved_only flag for + /// Need a better solution to decide authorized_only, but now just use reserved_only flag for /// prototyping. pub fn set_authorized_only(&self, reserved_only: bool) { self.peerset.set_reserved_only(reserved_only) diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index ef8d2a9a14b2d..78ea083ee0ab7 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -489,10 +489,10 @@ pub trait Externalities: Send { /// Set the authorized nodes from runtime. /// - /// In a permissioned network, the connection between nodes needs to reach a + /// In a permissioned network, the connections between nodes need to reach a /// consensus between participants. /// - /// - `nodes`: set of nodes which are allowed to connect for the local node. + /// - `nodes`: a set of nodes which are allowed to connect for the local node. /// each one is identified with an `OpaquePeerId`, here it just use plain bytes /// without any encoding. /// - `authorized_only`: if true, only the authorized nodes are allowed to connect, From 982bcaf3384884b14a942bc28f3b63c737bb4147 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Tue, 8 Sep 2020 19:29:20 +0800 Subject: [PATCH 31/34] more fix --- frame/im-online/src/benchmarking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frame/im-online/src/benchmarking.rs b/frame/im-online/src/benchmarking.rs index 92d9b9d5a5364..55f294505602e 100644 --- a/frame/im-online/src/benchmarking.rs +++ b/frame/im-online/src/benchmarking.rs @@ -23,7 +23,8 @@ use super::*; use frame_system::RawOrigin; use frame_benchmarking::benchmarks; -use sp_core::offchain::{OpaquePeerId, OpaqueMultiaddr}; +use sp_core::OpaquePeerId; +use sp_core::offchain::OpaqueMultiaddr; use sp_runtime::traits::{ValidateUnsigned, Zero}; use sp_runtime::transaction_validity::TransactionSource; use frame_support::traits::UnfilteredDispatchable; From 2c893ac8a5b940d43d1260cd6c6a8b5c3c0d9aab Mon Sep 17 00:00:00 2001 From: kaichao Date: Wed, 9 Sep 2020 20:02:24 +0800 Subject: [PATCH 32/34] Update primitives/core/src/offchain/mod.rs Co-authored-by: Pierre Krieger --- primitives/core/src/offchain/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/core/src/offchain/mod.rs b/primitives/core/src/offchain/mod.rs index 78ea083ee0ab7..4768496c4a508 100644 --- a/primitives/core/src/offchain/mod.rs +++ b/primitives/core/src/offchain/mod.rs @@ -494,7 +494,7 @@ pub trait Externalities: Send { /// /// - `nodes`: a set of nodes which are allowed to connect for the local node. /// each one is identified with an `OpaquePeerId`, here it just use plain bytes - /// without any encoding. + /// without any encoding. Invalid `OpaquePeerId`s are silently ignored. /// - `authorized_only`: if true, only the authorized nodes are allowed to connect, /// otherwise unauthorized nodes can also be connected through other mechanism. fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool); From e3882be462b4bc9d416626b51f490fe5f3e06da3 Mon Sep 17 00:00:00 2001 From: kaichao Date: Wed, 9 Sep 2020 20:04:41 +0800 Subject: [PATCH 33/34] Update client/offchain/src/api.rs Co-authored-by: Pierre Krieger --- client/offchain/src/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index a32cb374c42b5..a7ab07c549665 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -184,8 +184,8 @@ impl OffchainExt for Api { } fn set_authorized_nodes(&mut self, nodes: Vec, authorized_only: bool) { - let peer_ids: HashSet = nodes.iter() - .filter_map(|node| PeerId::from_bytes(node.0.clone()).ok()) + let peer_ids: HashSet = nodes.into_iter() + .filter_map(|node| PeerId::from_bytes(node.0).ok()) .collect(); self.network_provider.set_authorized_peers(peer_ids); From 517f97a49f56eaf210d4bee3e931318dd08b3a51 Mon Sep 17 00:00:00 2001 From: Kaichao Sun Date: Thu, 10 Sep 2020 08:35:34 +0800 Subject: [PATCH 34/34] derive serialize and deserialize --- primitives/core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 44266e4a3d435..94f6bb2967a0b 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -179,6 +179,7 @@ impl sp_std::ops::Deref for OpaqueMetadata { /// Simple blob to hold a `PeerId` without committing to its format. #[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, PassByInner)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct OpaquePeerId(pub Vec); impl OpaquePeerId {