client/authority-discovery: Remove sentry node logic (#7368)

* client/authority-discovery: Remove sentry node logic

The notion of sentry nodes has been deprecated (see [1] for details).
This commit removes support for sentry nodes in the
`client/authority-discovery` module.

While removing `Role::Sentry` this commit also introduces
`Role::Discover`, allowing a node to discover addresses of authorities
without publishing ones own addresses. This will be needed in Polkadot
for collator nodes.

[1] https://github.com/paritytech/substrate/issues/6845

* client/authority-discovery/service: Improve PeerId comment
This commit is contained in:
Max Inden
2020-10-26 11:06:56 +01:00
committed by GitHub
parent 52a49e7f51
commit 653868c01e
6 changed files with 69 additions and 214 deletions
@@ -29,7 +29,6 @@ use futures_timer::Delay;
use addr_cache::AddrCache;
use async_trait::async_trait;
use codec::Decode;
use either::Either;
use libp2p::{core::multiaddr, multihash::Multihash};
use log::{debug, error, log_enabled};
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
@@ -37,7 +36,6 @@ use prost::Message;
use rand::{seq::SliceRandom, thread_rng};
use sc_client_api::blockchain::HeaderBackend;
use sc_network::{
config::MultiaddrWithPeerId,
DhtEvent,
ExHashT,
Multiaddr,
@@ -73,68 +71,47 @@ const MAX_ADDRESSES_PER_AUTHORITY: usize = 10;
/// Maximum number of in-flight DHT lookups at any given point in time.
const MAX_IN_FLIGHT_LOOKUPS: usize = 8;
/// Role an authority discovery module can run as.
/// Role an authority discovery [`Worker`] can run as.
pub enum Role {
/// Actual authority as well as a reference to its key store.
Authority(Arc<dyn CryptoStore>),
/// Sentry node that guards an authority.
///
/// No reference to its key store needed, as sentry nodes don't have an identity to sign
/// addresses with in the first place.
Sentry,
/// Publish own addresses and discover addresses of others.
PublishAndDiscover(Arc<dyn CryptoStore>),
/// Discover addresses of others.
Discover,
}
/// A [`Worker`] makes a given authority discoverable and discovers other
/// authorities.
/// An authority discovery [`Worker`] can publish the local node's addresses as well as discover
/// those of other nodes via a Kademlia DHT.
///
/// The [`Worker`] implements the Future trait. By
/// polling [`Worker`] an authority:
/// When constructed with [`Role::PublishAndDiscover`] a [`Worker`] will
///
/// 1. **Makes itself discoverable**
/// 1. Retrieve its external addresses (including peer id).
///
/// 1. Retrieves its external addresses (including peer id) or the ones of
/// its sentry nodes.
/// 2. Get the list of keys owned by the local node participating in the current authority set.
///
/// 2. Signs the above.
/// 3. Sign the addresses with the keys.
///
/// 3. Puts the signature and the addresses on the libp2p Kademlia DHT.
/// 4. Put addresses and signature as a record with the authority id as a key on a Kademlia DHT.
///
/// When constructed with either [`Role::PublishAndDiscover`] or [`Role::Publish`] a [`Worker`] will
///
/// 2. **Discovers other authorities**
/// 1. Retrieve the current and next set of authorities.
///
/// 1. Retrieves the current and next set of authorities.
/// 2. Start DHT queries for the ids of the authorities.
///
/// 2. Starts DHT queries for the ids of the authorities.
/// 3. Validate the signatures of the retrieved key value pairs.
///
/// 3. Validates the signatures of the retrieved key value pairs.
/// 4. Add the retrieved external addresses as priority nodes to the
/// network peerset.
///
/// 4. Adds the retrieved external addresses as priority nodes to the
/// peerset.
///
/// When run as a sentry node, the [`Worker`] does not publish
/// any addresses to the DHT but still discovers validators and sentry nodes of
/// validators, i.e. only step 2 (Discovers other authorities) is executed.
pub struct Worker<Client, Network, Block, DhtEventStream>
where
Block: BlockT + 'static,
Network: NetworkProvider,
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
<Client as ProvideRuntimeApi<Block>>::Api: AuthorityDiscoveryApi<Block>,
{
/// Channel receiver for messages send by an [`Service`].
/// 5. Allow querying of the collected addresses via the [`crate::Service`].
pub struct Worker<Client, Network, Block, DhtEventStream> {
/// Channel receiver for messages send by a [`Service`].
from_service: Fuse<mpsc::Receiver<ServicetoWorkerMsg>>,
client: Arc<Client>,
network: Arc<Network>,
/// List of sentry node public addresses.
//
// There are 3 states:
// - None: No addresses were specified.
// - Some(vec![]): Addresses were specified, but none could be parsed as proper
// Multiaddresses.
// - Some(vec![a, b, c, ...]): Valid addresses were specified.
sentry_nodes: Option<Vec<Multiaddr>>,
/// Channel we receive Dht events on.
dht_event_rx: DhtEventStream,
@@ -169,15 +146,11 @@ where
AuthorityDiscoveryApi<Block, Error = sp_blockchain::Error>,
DhtEventStream: Stream<Item = DhtEvent> + Unpin,
{
/// Return a new [`Worker`].
///
/// Note: When specifying `sentry_nodes` this module will not advertise the public addresses of
/// the node itself but only the public addresses of its sentry nodes.
/// Construct a [`Worker`].
pub(crate) fn new(
from_service: mpsc::Receiver<ServicetoWorkerMsg>,
client: Arc<Client>,
network: Arc<Network>,
sentry_nodes: Vec<MultiaddrWithPeerId>,
dht_event_rx: DhtEventStream,
role: Role,
prometheus_registry: Option<prometheus_endpoint::Registry>,
@@ -207,12 +180,6 @@ where
query_interval_duration,
);
let sentry_nodes = if !sentry_nodes.is_empty() {
Some(sentry_nodes.into_iter().map(|ma| ma.concat()).collect::<Vec<_>>())
} else {
None
};
let addr_cache = AddrCache::new();
let metrics = match prometheus_registry {
@@ -232,7 +199,6 @@ where
from_service: from_service.fuse(),
client,
network,
sentry_nodes,
dht_event_rx,
publish_interval,
query_interval,
@@ -313,33 +279,23 @@ where
}
fn addresses_to_publish(&self) -> impl ExactSizeIterator<Item = Multiaddr> {
match &self.sentry_nodes {
Some(addrs) => Either::Left(addrs.clone().into_iter()),
None => {
let peer_id: Multihash = self.network.local_peer_id().into();
Either::Right(
self.network.external_addresses()
.into_iter()
.map(move |a| {
if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) {
a
} else {
a.with(multiaddr::Protocol::P2p(peer_id.clone()))
}
}),
)
}
}
let peer_id: Multihash = self.network.local_peer_id().into();
self.network.external_addresses()
.into_iter()
.map(move |a| {
if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) {
a
} else {
a.with(multiaddr::Protocol::P2p(peer_id.clone()))
}
})
}
/// Publish either our own or if specified the public addresses of our sentry nodes.
/// Publish own public addresses.
async fn publish_ext_addresses(&mut self) -> Result<()> {
let key_store = match &self.role {
Role::Authority(key_store) => key_store,
// Only authority nodes can put addresses (their own or the ones of their sentry nodes)
// on the Dht. Sentry nodes don't have a known identity to authenticate such addresses,
// thus `publish_ext_addresses` becomes a no-op.
Role::Sentry => return Ok(()),
Role::PublishAndDiscover(key_store) => key_store,
Role::Discover => return Ok(()),
};
let addresses = self.addresses_to_publish();
@@ -394,12 +350,12 @@ where
let id = BlockId::hash(self.client.info().best_hash);
let local_keys = match &self.role {
Role::Authority(key_store) => {
Role::PublishAndDiscover(key_store) => {
key_store.sr25519_public_keys(
key_types::AUTHORITY_DISCOVERY
).await.into_iter().collect::<HashSet<_>>()
},
Role::Sentry => HashSet::new(),
Role::Discover => HashSet::new(),
};
let mut authorities = self
@@ -798,13 +754,7 @@ impl Metrics {
// Helper functions for unit testing.
#[cfg(test)]
impl<Block, Client, Network, DhtEventStream> Worker<Client, Network, Block, DhtEventStream>
where
Block: BlockT + 'static,
Network: NetworkProvider,
Client: ProvideRuntimeApi<Block> + Send + Sync + 'static + HeaderBackend<Block>,
<Client as ProvideRuntimeApi<Block>>::Api: AuthorityDiscoveryApi<Block>,
{
impl<Block, Client, Network, DhtEventStream> Worker<Client, Network, Block, DhtEventStream> {
pub(crate) fn inject_addresses(&mut self, authority: AuthorityId, addresses: Vec<Multiaddr>) {
self.addr_cache.insert(authority, addresses);
}