Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
47b4f7c
{core,srml}/authority-discovery: Move generic to specific session keys
mxinden Oct 25, 2019
4d80316
{srml,core}/authority-discovery: Verify signature outside of runtime
mxinden Oct 28, 2019
1be93d3
*: Add authority discovery to the set of session keys
mxinden Oct 28, 2019
3551221
*: Sign authority discovery DHT payload with keystore instead of runtime
mxinden Oct 28, 2019
b516aee
core/authority-discovery: Give libp2p Kademlia time to start up
mxinden Oct 29, 2019
404d9a9
core/authority-discovery: Move authorities priority group name to const
mxinden Oct 29, 2019
e922805
node/runtime/src/lib.rs: Bump runtime spec version
mxinden Oct 29, 2019
38cf886
*: Fix lints and node/testing test failures
mxinden Oct 29, 2019
50e90a9
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Oct 31, 2019
db05799
*: Fix formatting
mxinden Nov 4, 2019
b7b49c4
Merge remote-tracking branch 'master' into refactor-authority-discovery
mxinden Nov 4, 2019
1d72997
Merge branch 'master' of https://github.com/paritytech/substrate into…
mxinden Nov 4, 2019
180f5ec
core/authority-discovery: Box dht event channel in unit tests
mxinden Nov 5, 2019
8aca3d7
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Nov 6, 2019
f8cfff7
node/cli/src/service.rs: Fix future import
mxinden Nov 6, 2019
642ca6c
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Nov 8, 2019
1f5241c
node/cli/src/service.rs: Replace unwrap by expect with proof
mxinden Nov 8, 2019
744c218
node/cli/src/chain_spec: Remove TODO for testnet key generation
mxinden Nov 8, 2019
409d885
core/authority-discovery/src/lib: Remove scale encoding TODOs
mxinden Nov 8, 2019
79de0c0
srml/authority-discovery: Make comment a doc comment
mxinden Nov 10, 2019
0b8f7dd
core/authority-discovery: Remove unused StreamExt import
mxinden Nov 10, 2019
a6d8f6c
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Nov 10, 2019
1a90903
node/runtime: Bump impl version to debug CI
mxinden Nov 10, 2019
a2c9df5
Test ci.
tomusdrw Nov 10, 2019
edff1f8
Change the line width to 100.
tomusdrw Nov 10, 2019
ae5108a
Revert "Change the line width to 100."
tomusdrw Nov 10, 2019
3b71b57
Fix a check for polkadot to work on forked repos.
tomusdrw Nov 10, 2019
65756f9
Revert "node/runtime: Bump impl version to debug CI"
mxinden Nov 10, 2019
0ae3bfe
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Nov 11, 2019
fc5156c
Revert "Test ci."
mxinden Nov 11, 2019
4d36114
Merge remote-tracking branch 'paritytech/master' into refactor-author…
mxinden Nov 12, 2019
56d630c
Cargo.lock: Fix wrong lock file merge
mxinden Nov 12, 2019
b689a1f
srml/authority-discovery: Keep track of new validator set not upcoming
mxinden Nov 14, 2019
89f5018
core/authority-discovery: Document key retrieval functions
mxinden Nov 14, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
*: Sign authority discovery DHT payload with keystore instead of runtime
Instead of calling a runtime function to sign a dht payload, which then
invokes the keystore, pass the keystore to the authority discovery
module and use it directly.
  • Loading branch information
mxinden committed Oct 29, 2019
commit 35512214b6a738668071a4a66a18c49f497dd6b4
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions core/authority-discovery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ client = { package = "substrate-client", path = "../../core/client" }
codec = { package = "parity-scale-codec", default-features = false, version = "1.0.3" }
derive_more = "0.15.0"
futures = "0.1.29"
keystore = { package = "substrate-keystore", path = "../keystore" }
libp2p = { version = "0.12.0", default-features = false, features = ["secp256k1", "libp2p-websocket"] }
log = "0.4.8"
network = { package = "substrate-network", path = "../../core/network" }
Expand Down
8 changes: 1 addition & 7 deletions core/authority-discovery/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,9 @@ pub type AuthoritySignature = app::Signature;
decl_runtime_apis! {
/// The authority discovery api.
///
/// This api is used by the `core/authority-discovery` module to retrieve our
/// own authority identifier, to retrieve identifiers of the current authority
/// set, as well as sign and verify Kademlia Dht external address payloads
/// from and to other authorities.
/// This api is used by the `core/authority-discovery` module to retrieve identifiers of the current authority set.
pub trait AuthorityDiscoveryApi {
/// Retrieve authority identifiers of the current authority set.
fn authorities() -> Vec<AuthorityId>;

/// Sign the given payload with the private key corresponding to the returned authority id.
fn sign(payload: &Vec<u8>) -> Option<(AuthoritySignature, AuthorityId)>;
}
}
4 changes: 1 addition & 3 deletions core/authority-discovery/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ pub enum Error {
HashingAuthorityId(libp2p::core::multiaddr::multihash::EncodeError),
/// Failed calling into the Substrate runtime.
CallingRuntime(client::error::Error),
/// Failed signing the dht payload via the Substrate runtime.
SigningDhtPayload,
/// From the Dht we only get the hashed authority id. In order to retrieve the actual authority id and to ensure it
/// is actually an authority, we match the hash against the hash of the authority id of all other authorities. This
/// error is the result of the above failing.
Expand All @@ -45,5 +43,5 @@ pub enum Error {
/// Failed to parse a libp2p multi address.
ParsingMultiaddress(libp2p::core::multiaddr::Error),
/// Tokio timer error.
PollingTokioTimer(tokio_timer::Error)
PollingTokioTimer(tokio_timer::Error),
}
144 changes: 88 additions & 56 deletions core/authority-discovery/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ use futures::{prelude::*, sync::mpsc::Receiver};
use log::{debug, error, log_enabled, warn};
use network::specialization::NetworkSpecialization;
use network::{DhtEvent, ExHashT};
use primitives::crypto::Pair;
use primitives::crypto::{key_types, Pair};
use primitives::traits::BareCryptoStorePtr;
use prost::Message;
use sr_primitives::generic::BlockId;
use sr_primitives::traits::{Block as BlockT, ProvideRuntimeApi};
Expand All @@ -75,13 +76,16 @@ where
Network: NetworkProvider,
Client: ProvideRuntimeApi + Send + Sync + 'static + HeaderBackend<Block>,
<Client as ProvideRuntimeApi>::Api: AuthorityDiscoveryApi<Block>,

{
client: Arc<Client>,

network: Arc<Network>,
/// Channel we receive Dht events on.
dht_event_rx: Receiver<DhtEvent>,

key_store: BareCryptoStorePtr,

/// Interval to be proactive, publishing own addresses.
publish_interval: tokio_timer::Interval,
/// Interval on which to query for addresses of other authorities.
Expand All @@ -107,6 +111,7 @@ where
pub fn new(
client: Arc<Client>,
network: Arc<Network>,
key_store: BareCryptoStorePtr,
dht_event_rx: futures::sync::mpsc::Receiver<DhtEvent>,
) -> AuthorityDiscovery<Client, Network, Block> {
// Kademlia's default time-to-live for Dht records is 36h, republishing records every 24h. Given that a node
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not perfect to depend on any "default value" that probably could change at any moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Kademlia does not expose these values to the outside as of today (https://github.com/libp2p/rust-libp2p/blob/master/protocols/kad/src/lib.rs). If we want to do that in the future I would prefer doing that in a follow up pull request.

Expand All @@ -128,6 +133,7 @@ where
client,
network,
dht_event_rx,
key_store,
publish_interval,
query_interval,
address_cache,
Expand All @@ -136,8 +142,6 @@ where
}

fn publish_own_ext_addresses(&mut self) -> Result<()> {
let id = BlockId::hash(self.client.info().best_hash);

let addresses = self
.network
.external_addresses()
Expand All @@ -155,27 +159,25 @@ where
.encode(&mut serialized_addresses)
.map_err(Error::EncodingProto)?;

let (signature, authority_id) = self
.client
.runtime_api()
.sign(&id, &serialized_addresses)
.map_err(Error::CallingRuntime)?
.ok_or(Error::SigningDhtPayload)?;
for key in self.get_priv_keys_within_authority_set()?.into_iter() {
let signature = key.sign(&serialized_addresses);

let mut signed_addresses = vec![];
schema::SignedAuthorityAddresses {
addresses: serialized_addresses,
// TODO: Instead of encoding via scale and then encoding via proto, we could also convert the signature to a
// [u8] and protobuf encode from there.
signature: signature.encode(),
}
.encode(&mut signed_addresses)
.map_err(Error::EncodingProto)?;
let mut signed_addresses = vec![];
schema::SignedAuthorityAddresses {
addresses: serialized_addresses.clone(),
// TODO: Instead of encoding via scale and then encoding via proto, we could also convert the signature
// to a [u8] and protobuf encode from there. Important to keep in mind that this module is not anywhere
// close to a resource hot path.
signature: signature.encode(),
}
.encode(&mut signed_addresses)
.map_err(Error::EncodingProto)?;

self.network.put_value(
hash_authority_id(authority_id.as_ref())?,
signed_addresses,
);
self.network.put_value(
hash_authority_id(key.public().as_ref())?,
signed_addresses,
);
}

Ok(())
}
Expand Down Expand Up @@ -291,6 +293,44 @@ where
self.address_cache
.retain(|peer_id, _addresses| current_authorities.contains(peer_id))
}

fn get_priv_keys_within_authority_set(&mut self) -> Result<Vec<AuthorityPair>> {
let keys = self.get_own_public_keys_within_authority_set()?
.into_iter()
.map(std::convert::Into::into)
.filter_map(|pub_key| {
self.key_store.read().sr25519_key_pair(key_types::AUTHORITY_DISCOVERY, &pub_key)
})
.map(std::convert::Into::into)
.collect();

Ok(keys)
}

fn get_own_public_keys_within_authority_set(&mut self) -> Result<HashSet<AuthorityId>> {
let local_pub_keys = self.key_store
.read()
.sr25519_public_keys(key_types::AUTHORITY_DISCOVERY)
.into_iter()
.collect::<HashSet<_>>();

let id = BlockId::hash(self.client.info().best_hash);
let current_authorities = self
.client
.runtime_api()
.authorities(&id)
.map_err(Error::CallingRuntime)?
.into_iter()
.map(std::convert::Into::into)
.collect::<HashSet<_>>();

let intersection = local_pub_keys.intersection(&current_authorities)
.cloned()
.map(std::convert::Into::into)
.collect();

Ok(intersection)
}
}

impl<Client, Network, Block> futures::Future for AuthorityDiscovery<Client, Network, Block>
Expand Down Expand Up @@ -418,21 +458,23 @@ mod tests {
use super::*;
use client::runtime_api::{ApiExt, Core, RuntimeVersion};
use futures::future::poll_fn;
use primitives::{ExecutionContext, NativeOrEncoded, Public};
use primitives::{ExecutionContext, NativeOrEncoded, testing::KeyStore};
use sr_primitives::traits::Zero;
use sr_primitives::traits::{ApiRef, Block as BlockT, NumberFor, ProvideRuntimeApi};
use std::sync::{Arc, Mutex};
use test_client::runtime::Block;
use tokio::runtime::current_thread;

#[derive(Clone)]
struct TestApi {}
struct TestApi {
authorities: Vec<AuthorityId>,
}

impl ProvideRuntimeApi for TestApi {
type Api = RuntimeApi;

fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> {
RuntimeApi {}.into()
RuntimeApi{authorities: self.authorities.clone()}.into()
}
}

Expand Down Expand Up @@ -477,7 +519,9 @@ mod tests {
}
}

struct RuntimeApi {}
struct RuntimeApi {
authorities: Vec<AuthorityId>,
}

impl Core<Block> for RuntimeApi {
fn Core_version_runtime_api_impl(
Expand Down Expand Up @@ -543,28 +587,7 @@ mod tests {
_: Option<()>,
_: Vec<u8>,
) -> std::result::Result<NativeOrEncoded<Vec<AuthorityId>>, client::error::Error> {
// TODO: cleanup
let authority_1_key_pair = AuthorityPair::from_seed_slice(&[1; 32]).unwrap();
let authority_2_key_pair = AuthorityPair::from_seed_slice(&[2; 32]).unwrap();
return Ok(NativeOrEncoded::Native(vec![
authority_1_key_pair.public(),
authority_2_key_pair.public(),
]));
}
fn AuthorityDiscoveryApi_sign_runtime_api_impl(
&self,
_: &BlockId<Block>,
_: ExecutionContext,
_: Option<&std::vec::Vec<u8>>,
_: Vec<u8>,
) -> std::result::Result<
NativeOrEncoded<Option<(AuthoritySignature, AuthorityId)>>,
client::error::Error,
> {
return Ok(NativeOrEncoded::Native(Some((
AuthorityPair::from_seed_slice(&[0; 32]).unwrap().sign(b"1"),
AuthorityId::from_slice(&[2; 32]),
))));
return Ok(NativeOrEncoded::Native(self.authorities.clone()));
}
}

Expand Down Expand Up @@ -605,11 +628,13 @@ mod tests {
#[test]
fn publish_own_ext_addresses_puts_record_on_dht() {
let (_dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000);
let test_api = Arc::new(TestApi {});
let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new();
let public = key_store.write().sr25519_generate_new(key_types::AUTHORITY_DISCOVERY, None).unwrap();
let test_api = Arc::new(TestApi {authorities: vec![public.into()]});

let mut authority_discovery =
AuthorityDiscovery::new(test_api, network.clone(), dht_event_rx);
AuthorityDiscovery::new(test_api, network.clone(), key_store, dht_event_rx);

authority_discovery.publish_own_ext_addresses().unwrap();

Expand All @@ -620,11 +645,18 @@ mod tests {
#[test]
fn request_addresses_of_others_triggers_dht_get_query() {
let (_dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000);
let test_api = Arc::new(TestApi {});

// Generate authority keys
let authority_1_key_pair = AuthorityPair::from_seed_slice(&[1; 32]).unwrap();
let authority_2_key_pair = AuthorityPair::from_seed_slice(&[2; 32]).unwrap();

let test_api = Arc::new(TestApi {authorities: vec![authority_1_key_pair.public(), authority_2_key_pair.public()]});

let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new();

let mut authority_discovery =
AuthorityDiscovery::new(test_api, network.clone(), dht_event_rx);
AuthorityDiscovery::new(test_api, network.clone(), key_store, dht_event_rx);

authority_discovery.request_addresses_of_others().unwrap();

Expand All @@ -637,16 +669,16 @@ mod tests {
// Create authority discovery.

let (mut dht_event_tx, dht_event_rx) = futures::sync::mpsc::channel(1000);
let test_api = Arc::new(TestApi {});
let key_pair = AuthorityPair::from_seed_slice(&[1; 32]).unwrap();
let test_api = Arc::new(TestApi {authorities: vec![key_pair.public()]});
let network: Arc<TestNetwork> = Arc::new(Default::default());
let key_store = KeyStore::new();

let mut authority_discovery =
AuthorityDiscovery::new(test_api, network.clone(), dht_event_rx);
AuthorityDiscovery::new(test_api, network.clone(), key_store, dht_event_rx);

// Create sample dht event.

let key_pair = AuthorityPair::from_seed_slice(&[1; 32]).unwrap();

let authority_id_1 = hash_authority_id(key_pair.public().as_ref()).unwrap();
let address_1: libp2p::Multiaddr = "/ip6/2001:db8::".parse().unwrap();

Expand Down
11 changes: 10 additions & 1 deletion node/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ macro_rules! new_full {
// back-pressure. Authority discovery is triggering one event per authority within the current authority set.
// This estimates the authority set size to be somewhere below 10 000 thereby setting the channel buffer size to
// 10 000.
let (dht_event_tx, _dht_event_rx) =
let (dht_event_tx, dht_event_rx) =
mpsc::channel::<DhtEvent>(10_000);

let service = builder.with_network_protocol(|_| Ok(crate::service::NodeProtocol::new()))?
Expand Down Expand Up @@ -169,6 +169,15 @@ macro_rules! new_full {

let babe = babe::start_babe(babe_config)?;
service.spawn_essential_task(babe);

let authority_discovery = authority_discovery::AuthorityDiscovery::new(
service.client(),
service.network(),
service.keystore(),
dht_event_rx,
);

service.spawn_task(authority_discovery);
}

let config = grandpa::Config {
Expand Down
4 changes: 0 additions & 4 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -647,10 +647,6 @@ impl_runtime_apis! {
fn authorities() -> Vec<AuthorityDiscoveryId> {
AuthorityDiscovery::authorities()
}

fn sign(payload: &Vec<u8>) -> Option<(AuthorityDiscoverySignature, AuthorityDiscoveryId)> {
AuthorityDiscovery::sign(payload)
}
}

impl system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
Expand Down
Loading