Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

client/authority-discovery: Append PeerId to Multiaddr at most once #6933

Merged
merged 4 commits into from
Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
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 client/authority-discovery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ prost-build = "0.6.1"
bytes = "0.5.0"
codec = { package = "parity-scale-codec", default-features = false, version = "1.3.4" }
derive_more = "0.99.2"
either = "1.5.3"
futures = "0.3.4"
futures-timer = "3.0.1"
libp2p = { version = "0.24.0", default-features = false, features = ["kad"] }
Expand Down
42 changes: 24 additions & 18 deletions client/authority-discovery/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ use futures_timer::Delay;

use addr_cache::AddrCache;
use codec::Decode;
use libp2p::core::multiaddr;
use either::Either;
use libp2p::{core::multiaddr, multihash::Multihash};
use log::{debug, error, log_enabled};
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
use prost::Message;
Expand Down Expand Up @@ -232,6 +233,25 @@ where
}
}

fn addresses_to_publish(&self) -> impl ExactSizeIterator<Item = Multiaddr> {
Copy link
Member

Choose a reason for hiding this comment

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

IMHO returning a Iterator does not makes that much sense here:

  • We need an extra dependency for it
  • It will be collected anyway, which means in the case with sentry nodes, we clone the structure, convert it into an iterator and create a vector of it afterwards again. This could be solved with a simple clone.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need an extra dependency for it

Within Substrate we already depend on either 13 times, in addition, without the derive feature either doesn't have any dependencies. Is this not a trade off worth taking?

It will be collected anyway, which means in the case with sentry nodes, we clone the structure, convert it into an iterator and create a vector of it afterwards again. This could be solved with a simple clone.

True. In the case of sentry nodes this is sub optimal, but in the case of a validator itself it removes the need for one Iterator conversion (i.e. Vec -> Iterator -> filter -> inner to_vec -> Vec instead of Vec -> Iterator -> filter -> Vec -> Iterator -> inner to vec -> Vec). With the fact in mind that sentry nodes are deprecated (#6845) I think optimizing for the latter makes more sense. Lastly I very much doubt this has an impact in the first place as it is executed every 12 h only.

Does the above make sense @bkchr?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah fine by me.

This was also no blocker by me ;)

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(_))) {
return a;
}
a.with(multiaddr::Protocol::P2p(peer_id.clone()))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if a.iter().any(|p| matches!(p, multiaddr::Protocol::P2p(_))) {
return a;
}
a.with(multiaddr::Protocol::P2p(peer_id.clone()))
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.
fn publish_ext_addresses(&mut self) -> Result<()> {
let key_store = match &self.role {
Expand All @@ -242,29 +262,15 @@ where
Role::Sentry => return Ok(()),
};

if let Some(metrics) = &self.metrics {
metrics.publish.inc()
}

let addresses: Vec<_> = match &self.sentry_nodes {
Some(addrs) => addrs.clone().into_iter()
.map(|a| a.to_vec())
.collect(),
None => self.network.external_addresses()
.into_iter()
.map(|a| a.with(multiaddr::Protocol::P2p(
self.network.local_peer_id().into(),
)))
.map(|a| a.to_vec())
.collect(),
};
let addresses = self.addresses_to_publish();

if let Some(metrics) = &self.metrics {
metrics.publish.inc();
metrics.amount_last_published.set(addresses.len() as u64);
}

let mut serialized_addresses = vec![];
schema::AuthorityAddresses { addresses }
schema::AuthorityAddresses { addresses: addresses.map(|a| a.to_vec()).collect() }
.encode(&mut serialized_addresses)
.map_err(Error::EncodingProto)?;

Expand Down
71 changes: 70 additions & 1 deletion client/authority-discovery/src/worker/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ sp_api::mock_impl_runtime_apis! {

pub struct TestNetwork {
peer_id: PeerId,
external_addresses: Vec<Multiaddr>,
// Whenever functions on `TestNetwork` are called, the function arguments are added to the
// vectors below.
pub put_value_call: Arc<Mutex<Vec<(kad::record::Key, Vec<u8>)>>>,
Expand All @@ -179,6 +180,10 @@ impl Default for TestNetwork {
fn default() -> Self {
TestNetwork {
peer_id: PeerId::random(),
external_addresses: vec![
"/ip6/2001:db8::/tcp/30333"
.parse().unwrap(),
],
put_value_call: Default::default(),
get_value_call: Default::default(),
set_priority_group_call: Default::default(),
Expand Down Expand Up @@ -212,7 +217,7 @@ impl NetworkStateInfo for TestNetwork {
}

fn external_addresses(&self) -> Vec<Multiaddr> {
vec!["/ip6/2001:db8::/tcp/30333".parse().unwrap()]
self.external_addresses.clone()
}
}

Expand Down Expand Up @@ -691,3 +696,67 @@ fn do_not_cache_addresses_without_peer_id() {
"Expect worker to only cache `Multiaddr`s with `PeerId`s.",
);
}

#[test]
fn addresses_to_publish_adds_p2p() {
let (_dht_event_tx, dht_event_rx) = channel(1000);
let network: Arc<TestNetwork> = Arc::new(Default::default());

assert!(!matches!(
network.external_addresses().pop().unwrap().pop().unwrap(),
multiaddr::Protocol::P2p(_)
));

let (_to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new(
from_service,
Arc::new(TestApi {
authorities: vec![],
}),
network.clone(),
vec![],
dht_event_rx.boxed(),
Role::Authority(KeyStore::new()),
Some(prometheus_endpoint::Registry::new()),
);

assert!(
matches!(
worker.addresses_to_publish().next().unwrap().pop().unwrap(),
multiaddr::Protocol::P2p(_)
),
"Expect `addresses_to_publish` to append `p2p` protocol component.",
);
}

/// Ensure [`Worker::addresses_to_publish`] does not add an additional `p2p` protocol component in
/// case one already exists.
#[test]
fn addresses_to_publish_respects_existing_p2p_protocol() {
let (_dht_event_tx, dht_event_rx) = channel(1000);
let network: Arc<TestNetwork> = Arc::new(TestNetwork {
external_addresses: vec![
"/ip6/2001:db8::/tcp/30333/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC"
.parse().unwrap(),
],
.. Default::default()
});

let (_to_worker, from_service) = mpsc::channel(0);
let worker = Worker::new(
from_service,
Arc::new(TestApi {
authorities: vec![],
}),
network.clone(),
vec![],
dht_event_rx.boxed(),
Role::Authority(KeyStore::new()),
Some(prometheus_endpoint::Registry::new()),
);

assert_eq!(
network.external_addresses, worker.addresses_to_publish().collect::<Vec<_>>(),
"Expected Multiaddr from `TestNetwork` to not be altered.",
);
}