diff --git a/Cargo.lock b/Cargo.lock index 3d5193fe0ee8..e8458bd44707 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18445,7 +18445,6 @@ dependencies = [ "futures", "futures-timer", "ip_network", - "libp2p", "linked_hash_set", "log", "multihash 0.19.1", @@ -19477,8 +19476,10 @@ name = "sc-network-types" version = "0.10.0" dependencies = [ "bs58", + "bytes", "ed25519-dalek", "libp2p-identity", + "libp2p-kad", "litep2p", "log", "multiaddr 0.18.1", diff --git a/prdoc/pr_5842.prdoc b/prdoc/pr_5842.prdoc new file mode 100644 index 000000000000..0175c7583419 --- /dev/null +++ b/prdoc/pr_5842.prdoc @@ -0,0 +1,18 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Get rid of libp2p dependency in sc-authority-discovery + +doc: + - audience: Node Dev + description: | + Removes `libp2p` types in authority-discovery, and replace them with network backend agnostic types from `sc-network-types`. + The `sc-network` interface is therefore updated accordingly. + +crates: + - name: sc-network + bump: patch + - name: sc-network-types + bump: patch + - name: sc-authority-discovery + bump: patch diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 09381ec6b553..fc88d07ef936 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -24,7 +24,6 @@ codec = { workspace = true } futures = { workspace = true } futures-timer = { workspace = true } ip_network = { workspace = true } -libp2p = { features = ["ed25519", "kad"], workspace = true } multihash = { workspace = true } linked_hash_set = { workspace = true } log = { workspace = true, default-features = true } diff --git a/substrate/client/authority-discovery/src/tests.rs b/substrate/client/authority-discovery/src/tests.rs index acfd0e61de01..a73515ee00d2 100644 --- a/substrate/client/authority-discovery/src/tests.rs +++ b/substrate/client/authority-discovery/src/tests.rs @@ -25,7 +25,7 @@ use crate::{ }; use futures::{channel::mpsc::channel, executor::LocalPool, task::LocalSpawn}; -use libp2p::identity::ed25519; +use sc_network_types::ed25519; use std::{collections::HashSet, sync::Arc}; use sc_network::{multiaddr::Protocol, Multiaddr, PeerId}; diff --git a/substrate/client/authority-discovery/src/worker.rs b/substrate/client/authority-discovery/src/worker.rs index 6f4fbac77e05..13e860463c2d 100644 --- a/substrate/client/authority-discovery/src/worker.rs +++ b/substrate/client/authority-discovery/src/worker.rs @@ -34,8 +34,8 @@ use futures::{channel::mpsc, future, stream::Fuse, FutureExt, Stream, StreamExt} use addr_cache::AddrCache; use codec::{Decode, Encode}; use ip_network::IpNetwork; -use libp2p::kad::{PeerRecord, Record}; use linked_hash_set::LinkedHashSet; +use sc_network_types::rec::{Key, PeerRecord, Record}; use log::{debug, error, trace}; use prometheus_endpoint::{register, Counter, CounterVec, Gauge, Opts, U64}; @@ -580,7 +580,7 @@ where debug!(target: LOG_TARGET, "Value for hash '{:?}' found on Dht.", v.record.key); - if let Err(e) = self.handle_dht_value_found_event(v) { + if let Err(e) = self.handle_dht_value_found_event(v.into()) { if let Some(metrics) = &self.metrics { metrics.handle_value_found_event_failure.inc(); } @@ -592,7 +592,7 @@ where metrics.dht_event_received.with_label_values(&["value_not_found"]).inc(); } - if self.in_flight_lookups.remove(&hash).is_some() { + if self.in_flight_lookups.remove::(&hash.to_vec().into()).is_some() { debug!(target: LOG_TARGET, "Value for hash '{:?}' not found on Dht.", hash) } else { debug!( @@ -602,7 +602,7 @@ where } }, DhtEvent::ValuePut(hash) => { - if !self.latest_published_kad_keys.contains(&hash) { + if !self.latest_published_kad_keys.contains::(&hash.to_vec().into()) { return; } @@ -618,7 +618,7 @@ where debug!(target: LOG_TARGET, "Successfully put hash '{:?}' on Dht.", hash) }, DhtEvent::ValuePutFailed(hash) => { - if !self.latest_published_kad_keys.contains(&hash) { + if !self.latest_published_kad_keys.contains::(&hash.to_vec().into()) { // Not a value we have published or received multiple times. return; } @@ -646,7 +646,7 @@ where async fn handle_put_record_requested( &mut self, - record_key: KademliaKey, + record_key: Key, record_value: Vec, publisher: Option, expires: Option, @@ -656,7 +656,7 @@ where // Make sure we don't ever work with an outdated set of authorities // and that we do not update known_authorithies too often. let best_hash = self.client.best_hash().await?; - if !self.known_authorities.contains_key(&record_key) && + if !self.known_authorities.contains_key::(&record_key.to_vec().into()) && self.authorities_queried_at .map(|authorities_queried_at| authorities_queried_at != best_hash) .unwrap_or(true) @@ -677,8 +677,10 @@ where self.authorities_queried_at = Some(best_hash); } - let authority_id = - self.known_authorities.get(&record_key).ok_or(Error::UnknownAuthority)?; + let authority_id = self + .known_authorities + .get::(&record_key.to_vec().into()) + .ok_or(Error::UnknownAuthority)?; let signed_record = Self::check_record_signed_with_authority_id(record_value.as_slice(), authority_id)?; self.check_record_signed_with_network_key( @@ -697,7 +699,8 @@ where }) .unwrap_or_default(); // 0 is a sane default for records that do not have creation time present. - let current_record_info = self.last_known_records.get(&record_key); + let current_record_info = + self.last_known_records.get::(&record_key.to_vec().into()); // If record creation time is older than the current record creation time, // we don't store it since we want to give higher priority to newer records. if let Some(current_record_info) = current_record_info { @@ -712,7 +715,12 @@ where } } - self.network.store_record(record_key, record_value, Some(publisher), expires); + self.network.store_record( + record_key.to_vec().into(), + record_value, + Some(publisher), + expires, + ); Ok(()) } @@ -766,15 +774,19 @@ where // Ensure `values` is not empty and all its keys equal. let remote_key = peer_record.record.key.clone(); - let authority_id: AuthorityId = - if let Some(authority_id) = self.in_flight_lookups.remove(&remote_key) { - self.known_lookups.insert(remote_key.clone(), authority_id.clone()); - authority_id - } else if let Some(authority_id) = self.known_lookups.get(&remote_key) { - authority_id.clone() - } else { - return Err(Error::ReceivingUnexpectedRecord); - }; + let authority_id: AuthorityId = if let Some(authority_id) = + self.in_flight_lookups.remove::(&remote_key.to_vec().into()) + { + self.known_lookups + .insert(remote_key.clone().to_vec().into(), authority_id.clone()); + authority_id + } else if let Some(authority_id) = + self.known_lookups.get::(&remote_key.to_vec().into()) + { + authority_id.clone() + } else { + return Err(Error::ReceivingUnexpectedRecord); + }; let local_peer_id = self.network.local_peer_id(); @@ -835,7 +847,7 @@ where let addr_cache_needs_update = self.handle_new_record( &authority_id, - remote_key.clone(), + remote_key.clone().to_vec().into(), RecordInfo { creation_time: records_creation_time, peers_with_record: answering_peer_id.into_iter().collect(), @@ -870,7 +882,7 @@ where if new_record.creation_time > current_record_info.creation_time { let peers_that_need_updating = current_record_info.peers_with_record.clone(); self.network.put_record_to( - new_record.record.clone(), + new_record.record.clone().into(), peers_that_need_updating.clone(), // If this is empty it means we received the answer from our node local // storage, so we need to update that as well. @@ -907,7 +919,7 @@ where authority_id, new_record.creation_time, current_record_info.creation_time, ); self.network.put_record_to( - current_record_info.record.clone(), + current_record_info.record.clone().into(), new_record.peers_with_record.clone(), // If this is empty it means we received the answer from our node local // storage, so we need to update that as well. diff --git a/substrate/client/authority-discovery/src/worker/schema/tests.rs b/substrate/client/authority-discovery/src/worker/schema/tests.rs index 557fa9641f97..1dff1b93e06d 100644 --- a/substrate/client/authority-discovery/src/worker/schema/tests.rs +++ b/substrate/client/authority-discovery/src/worker/schema/tests.rs @@ -26,9 +26,9 @@ mod schema_v2 { use super::*; use codec::Encode; -use libp2p::identity::Keypair; use prost::Message; use sc_network::{Multiaddr, PeerId}; +use sc_network_types::ed25519::Keypair; #[test] fn v2_decodes_v1() { @@ -61,7 +61,7 @@ fn v2_decodes_v1() { #[test] fn v1_decodes_v2() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -73,7 +73,7 @@ fn v1_decodes_v2() { let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; let mut vec_record_v2 = vec![]; record_v2.encode(&mut vec_record_v2).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v2 = PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v2 = SignedAuthorityRecord { @@ -97,7 +97,7 @@ fn v1_decodes_v2() { #[test] fn v1_decodes_v3() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -112,7 +112,7 @@ fn v1_decodes_v3() { }; let mut vec_record_v3 = vec![]; record_v3.encode(&mut vec_record_v3).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v3 = PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v3 = SignedAuthorityRecord { @@ -136,7 +136,7 @@ fn v1_decodes_v3() { #[test] fn v3_decodes_v2() { - let peer_secret = Keypair::generate_ed25519(); + let peer_secret = Keypair::generate(); let peer_public = peer_secret.public(); let peer_id = peer_public.to_peer_id(); let multiaddress: Multiaddr = @@ -148,7 +148,7 @@ fn v3_decodes_v2() { let record_v2 = schema_v2::AuthorityRecord { addresses: vec_addresses.clone() }; let mut vec_record_v2 = vec![]; record_v2.encode(&mut vec_record_v2).unwrap(); - let vec_peer_public = peer_public.encode_protobuf(); + let vec_peer_public = peer_public.to_bytes().to_vec(); let peer_signature_v2 = schema_v2::PeerSignature { public_key: vec_peer_public, signature: vec_peer_signature }; let signed_record_v2 = schema_v2::SignedAuthorityRecord { diff --git a/substrate/client/authority-discovery/src/worker/tests.rs b/substrate/client/authority-discovery/src/worker/tests.rs index d71a85db8b81..a594e405a4dc 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -30,13 +30,15 @@ use futures::{ sink::SinkExt, task::LocalSpawn, }; -use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; use prometheus_endpoint::prometheus::default_registry; - use sc_client_api::HeaderBackend; -use sc_network::{service::signature::Keypair, Signature}; +use sc_network::{ + service::signature::{Keypair, SigningError}, + PublicKey, Signature, +}; use sc_network_types::{ multiaddr::{Multiaddr, Protocol}, + rec::Key as KademliaKey, PeerId, }; use sp_api::{ApiRef, ProvideRuntimeApi}; @@ -167,7 +169,7 @@ impl NetworkSigner for TestNetwork { fn sign_with_local_identity( &self, msg: Vec, - ) -> std::result::Result { + ) -> std::result::Result { Signature::sign_message(msg, &self.identity) } @@ -178,8 +180,8 @@ impl NetworkSigner for TestNetwork { signature: &Vec, message: &Vec, ) -> std::result::Result { - let public_key = libp2p::identity::PublicKey::try_decode_protobuf(&public_key) - .map_err(|error| error.to_string())?; + let public_key = + PublicKey::try_decode_protobuf(&public_key).map_err(|error| error.to_string())?; let peer_id: PeerId = peer_id.into(); let remote: PeerId = public_key.to_peer_id().into(); diff --git a/substrate/client/network/src/behaviour.rs b/substrate/client/network/src/behaviour.rs index 5ecbec52d507..f4551213a7a5 100644 --- a/substrate/client/network/src/behaviour.rs +++ b/substrate/client/network/src/behaviour.rs @@ -375,18 +375,23 @@ impl From for BehaviourOut { }, DiscoveryOut::Discovered(peer_id) => BehaviourOut::Discovered(peer_id), DiscoveryOut::ValueFound(results, duration) => - BehaviourOut::Dht(DhtEvent::ValueFound(results), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValueFound(results.into()), Some(duration)), DiscoveryOut::ValueNotFound(key, duration) => - BehaviourOut::Dht(DhtEvent::ValueNotFound(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValueNotFound(key.to_vec().into()), Some(duration)), DiscoveryOut::ValuePut(key, duration) => - BehaviourOut::Dht(DhtEvent::ValuePut(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValuePut(key.to_vec().into()), Some(duration)), DiscoveryOut::PutRecordRequest(record_key, record_value, publisher, expires) => BehaviourOut::Dht( - DhtEvent::PutRecordRequest(record_key, record_value, publisher, expires), + DhtEvent::PutRecordRequest( + record_key.to_vec().into(), + record_value, + publisher, + expires, + ), None, ), DiscoveryOut::ValuePutFailed(key, duration) => - BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), Some(duration)), + BehaviourOut::Dht(DhtEvent::ValuePutFailed(key.to_vec().into()), Some(duration)), DiscoveryOut::RandomKademliaStarted => BehaviourOut::RandomKademliaStarted, } } diff --git a/substrate/client/network/src/event.rs b/substrate/client/network/src/event.rs index 5400d11cb6ac..d441b7e47ba7 100644 --- a/substrate/client/network/src/event.rs +++ b/substrate/client/network/src/event.rs @@ -22,12 +22,12 @@ use crate::types::ProtocolName; use bytes::Bytes; -use libp2p::{ - kad::{record::Key, PeerRecord}, - PeerId, -}; use sc_network_common::role::ObservedRole; +use sc_network_types::{ + rec::{Key, PeerRecord}, + PeerId, +}; /// Events generated by DHT as a response to get_value and put_value requests. #[derive(Debug, Clone)] diff --git a/substrate/client/network/src/litep2p/mod.rs b/substrate/client/network/src/litep2p/mod.rs index df4244890f96..0f75ac0c32f6 100644 --- a/substrate/client/network/src/litep2p/mod.rs +++ b/substrate/client/network/src/litep2p/mod.rs @@ -702,21 +702,21 @@ impl NetworkBackend for Litep2pNetworkBac None => return, Some(command) => match command { NetworkServiceCommand::GetValue{ key } => { - let query_id = self.discovery.get_value(key.clone()).await; - self.pending_get_values.insert(query_id, (key, Instant::now())); + let query_id = self.discovery.get_value(key.to_vec().into()).await; + self.pending_get_values.insert(query_id, (key.to_vec().into(), Instant::now())); } NetworkServiceCommand::PutValue { key, value } => { - let query_id = self.discovery.put_value(key.clone(), value).await; - self.pending_put_values.insert(query_id, (key, Instant::now())); + let query_id = self.discovery.put_value(key.to_vec().into(), value).await; + self.pending_put_values.insert(query_id, (key.to_vec().into(), Instant::now())); } NetworkServiceCommand::PutValueTo { record, peers, update_local_storage} => { let kademlia_key = record.key.to_vec().into(); - let query_id = self.discovery.put_value_to_peers(record, peers, update_local_storage).await; + let query_id = self.discovery.put_value_to_peers(record.into(), peers, update_local_storage).await; self.pending_put_values.insert(query_id, (kademlia_key, Instant::now())); } NetworkServiceCommand::StoreRecord { key, value, publisher, expires } => { - self.discovery.store_record(key, value, publisher.map(Into::into), expires).await; + self.discovery.store_record(key.to_vec().into(), value, publisher.map(Into::into), expires).await; } NetworkServiceCommand::EventStream { tx } => { self.event_streams.push(tx); @@ -835,7 +835,7 @@ impl NetworkBackend for Litep2pNetworkBac self.event_streams.send( Event::Dht( DhtEvent::ValueFound( - record + record.into() ) ) ); @@ -863,7 +863,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValuePut(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValuePut(sc_network_types::rec::Key::new::(&key.to_vec().into())) )); if let Some(ref metrics) = self.metrics { @@ -889,7 +889,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValuePutFailed(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValuePutFailed(sc_network_types::rec::Key::new::(&key.to_vec().into())) )); if let Some(ref metrics) = self.metrics { @@ -907,7 +907,7 @@ impl NetworkBackend for Litep2pNetworkBac ); self.event_streams.send(Event::Dht( - DhtEvent::ValueNotFound(libp2p::kad::RecordKey::new(&key)) + DhtEvent::ValueNotFound(sc_network_types::rec::Key::new::(&key.to_vec().into())) )); if let Some(ref metrics) = self.metrics { @@ -963,7 +963,7 @@ impl NetworkBackend for Litep2pNetworkBac Some(DiscoveryEvent::IncomingRecord { record: Record { key, value, publisher, expires }} ) => { self.event_streams.send(Event::Dht( DhtEvent::PutRecordRequest( - libp2p::kad::RecordKey::new(&key), + sc_network_types::rec::Key::new::(&key.to_vec().into()), value, publisher.map(Into::into), expires, diff --git a/substrate/client/network/src/litep2p/service.rs b/substrate/client/network/src/litep2p/service.rs index 693217f5ad94..e1823b32d312 100644 --- a/substrate/client/network/src/litep2p/service.rs +++ b/substrate/client/network/src/litep2p/service.rs @@ -32,15 +32,15 @@ use crate::{ RequestFailure, Signature, }; -use crate::litep2p::Record; use codec::DecodeAll; use futures::{channel::oneshot, stream::BoxStream}; -use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; +use libp2p::identity::SigningError; use litep2p::{ addresses::PublicAddresses, crypto::ed25519::Keypair, types::multiaddr::Multiaddr as LiteP2pMultiaddr, }; use parking_lot::RwLock; +use sc_network_types::rec::{Key as KademliaKey, Record}; use sc_network_common::{ role::{ObservedRole, Roles}, @@ -266,12 +266,7 @@ impl NetworkDHTProvider for Litep2pNetworkService { let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::PutValue { key, value }); } - fn put_record_to( - &self, - record: libp2p::kad::Record, - peers: HashSet, - update_local_storage: bool, - ) { + fn put_record_to(&self, record: Record, peers: HashSet, update_local_storage: bool) { let _ = self.cmd_tx.unbounded_send(NetworkServiceCommand::PutValueTo { record: Record { key: record.key.to_vec().into(), diff --git a/substrate/client/network/src/service.rs b/substrate/client/network/src/service.rs index 71d0b45aa06d..96f8893d3354 100644 --- a/substrate/client/network/src/service.rs +++ b/substrate/client/network/src/service.rs @@ -68,7 +68,6 @@ use libp2p::{ core::{upgrade, ConnectedPoint, Endpoint}, identify::Info as IdentifyInfo, identity::ed25519, - kad::{record::Key as KademliaKey, Record}, multiaddr::{self, Multiaddr}, swarm::{ Config as SwarmConfig, ConnectionError, ConnectionId, DialError, Executor, ListenError, @@ -80,6 +79,7 @@ use log::{debug, error, info, trace, warn}; use metrics::{Histogram, MetricSources, Metrics}; use parking_lot::Mutex; use prometheus_endpoint::Registry; +use sc_network_types::rec::{Key as KademliaKey, Record}; use sc_client_api::BlockBackend; use sc_network_common::{ @@ -1455,17 +1455,17 @@ where fn handle_worker_message(&mut self, msg: ServiceToWorkerMsg) { match msg { ServiceToWorkerMsg::GetValue(key) => - self.network_service.behaviour_mut().get_value(key), + self.network_service.behaviour_mut().get_value(key.to_vec().into()), ServiceToWorkerMsg::PutValue(key, value) => - self.network_service.behaviour_mut().put_value(key, value), + self.network_service.behaviour_mut().put_value(key.to_vec().into(), value), ServiceToWorkerMsg::PutRecordTo { record, peers, update_local_storage } => self .network_service .behaviour_mut() - .put_record_to(record, peers, update_local_storage), + .put_record_to(record.into(), peers, update_local_storage), ServiceToWorkerMsg::StoreRecord(key, value, publisher, expires) => self .network_service .behaviour_mut() - .store_record(key, value, publisher, expires), + .store_record(key.to_vec().into(), value, publisher, expires), ServiceToWorkerMsg::AddKnownAddress(peer_id, addr) => self.network_service.behaviour_mut().add_known_address(peer_id, addr), ServiceToWorkerMsg::EventStream(sender) => self.event_streams.push(sender), diff --git a/substrate/client/network/src/service/traits.rs b/substrate/client/network/src/service/traits.rs index bd4f83c7fd44..500d3fe6aeda 100644 --- a/substrate/client/network/src/service/traits.rs +++ b/substrate/client/network/src/service/traits.rs @@ -32,12 +32,15 @@ use crate::{ }; use futures::{channel::oneshot, Stream}; -use libp2p::kad::Record; use prometheus_endpoint::Registry; use sc_client_api::BlockBackend; use sc_network_common::{role::ObservedRole, ExHashT}; -use sc_network_types::{multiaddr::Multiaddr, PeerId}; +pub use sc_network_types::{ + multiaddr::Multiaddr, + rec::{Key as KademliaKey, Record}, + PeerId, +}; use sp_runtime::traits::Block as BlockT; use std::{ @@ -49,7 +52,7 @@ use std::{ time::{Duration, Instant}, }; -pub use libp2p::{identity::SigningError, kad::record::Key as KademliaKey}; +pub use libp2p::identity::SigningError; /// Supertrait defining the services provided by [`NetworkBackend`] service handle. pub trait NetworkService: diff --git a/substrate/client/network/types/Cargo.toml b/substrate/client/network/types/Cargo.toml index 655f104111e4..7438eaeffcd2 100644 --- a/substrate/client/network/types/Cargo.toml +++ b/substrate/client/network/types/Cargo.toml @@ -11,8 +11,10 @@ documentation = "https://docs.rs/sc-network-types" [dependencies] bs58 = { workspace = true, default-features = true } +bytes = { version = "1.4.0", default-features = false } ed25519-dalek = { workspace = true, default-features = true } libp2p-identity = { features = ["ed25519", "peerid", "rand"], workspace = true } +libp2p-kad = { version = "0.44.6", default-features = false } litep2p = { workspace = true } log = { workspace = true, default-features = true } multiaddr = { workspace = true } diff --git a/substrate/client/network/types/src/lib.rs b/substrate/client/network/types/src/lib.rs index 5684e38ab2e8..ba9bb739efdb 100644 --- a/substrate/client/network/types/src/lib.rs +++ b/substrate/client/network/types/src/lib.rs @@ -19,6 +19,6 @@ pub mod ed25519; pub mod multiaddr; pub mod multihash; - mod peer_id; +pub mod rec; pub use peer_id::PeerId; diff --git a/substrate/client/network/types/src/rec.rs b/substrate/client/network/types/src/rec.rs new file mode 100644 index 000000000000..5180e4dac98f --- /dev/null +++ b/substrate/client/network/types/src/rec.rs @@ -0,0 +1,171 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{multihash::Multihash, PeerId}; +use bytes::Bytes; +use litep2p::protocol::libp2p::kademlia::{Record as LiteRecord, RecordKey}; +use std::{borrow::Borrow, error::Error, fmt, time::Instant}; + +/// The (opaque) key of a record. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Key(Bytes); + +impl Key { + /// Creates a new key from the bytes of the input. + pub fn new>(key: &K) -> Self { + Key(Bytes::copy_from_slice(key.as_ref())) + } + + /// Copies the bytes of the key into a new vector. + pub fn to_vec(&self) -> Vec { + Vec::from(&self.0[..]) + } +} + +impl Borrow<[u8]> for Key { + fn borrow(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsRef<[u8]> for Key { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl From> for Key { + fn from(v: Vec) -> Key { + Key(Bytes::from(v)) + } +} + +impl From for Key { + fn from(m: Multihash) -> Key { + Key::from(m.to_bytes()) + } +} + +/// A record stored in the DHT. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Record { + /// Key of the record. + pub key: Key, + /// Value of the record. + pub value: Vec, + /// The (original) publisher of the record. + pub publisher: Option, + /// The expiration time as measured by a local, monotonic clock. + pub expires: Option, +} + +impl Record { + /// Creates a new record for insertion into the DHT. + pub fn new(key: K, value: Vec) -> Self + where + K: Into, + { + Record { key: key.into(), value, publisher: None, expires: None } + } + + /// Checks whether the record is expired w.r.t. the given `Instant`. + pub fn is_expired(&self, now: Instant) -> bool { + self.expires.map_or(false, |t| now >= t) + } +} + +impl From for Record { + fn from(out: libp2p_kad::Record) -> Self { + let vec: Vec = out.key.to_vec(); + let key: Key = vec.into(); + let publisher = out.publisher.map(Into::into); + Record { key, value: out.value, publisher, expires: out.expires } + } +} + +impl From for LiteRecord { + fn from(val: Record) -> Self { + let vec: Vec = val.key.to_vec(); + let key: RecordKey = vec.into(); + let publisher = val.publisher.map(Into::into); + LiteRecord { key, value: val.value, publisher, expires: val.expires } + } +} + +impl From for libp2p_kad::Record { + fn from(a: Record) -> libp2p_kad::Record { + let peer = a.publisher.map(Into::into); + libp2p_kad::Record { + key: a.key.to_vec().into(), + value: a.value, + publisher: peer, + expires: a.expires, + } + } +} + +/// A record either received by the given peer or retrieved from the local +/// record store. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PeerRecord { + /// The peer from whom the record was received. `None` if the record was + /// retrieved from local storage. + pub peer: Option, + pub record: Record, +} + +impl From for PeerRecord { + fn from(out: libp2p_kad::PeerRecord) -> Self { + let peer = out.peer.map(Into::into); + let record = out.record.into(); + PeerRecord { peer, record } + } +} + +/// An error during signing of a message. +#[derive(Debug)] +pub struct SigningError { + msg: String, + source: Option>, +} + +/// An error during encoding of key material. +#[allow(dead_code)] +impl SigningError { + #[cfg(not(target_arch = "wasm32"))] + pub(crate) fn new(msg: S) -> Self { + Self { msg: msg.to_string(), source: None } + } + + #[cfg(not(target_arch = "wasm32"))] + pub(crate) fn source(self, source: impl Error + Send + Sync + 'static) -> Self { + Self { source: Some(Box::new(source)), ..self } + } +} + +impl fmt::Display for SigningError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Key signing error: {}", self.msg) + } +} + +impl Error for SigningError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.source.as_ref().map(|s| &**s as &dyn Error) + } +}