Skip to content

Commit 1a0325c

Browse files
kad: Providers part 7: better types and public API, public addresses & known providers (#246)
This PR introduces the following changes: 1. Introduces a better type `ContentProvider` without a burden of `KademliaPeer`. 2. Simplifies public litep2p content providers API. 3. Uses `PublicAddresses` API when advertising local providers. 4. Adds locally known providers to discovered providers when performing `GET_PROVIDERS` request. 5. Emits `IncomingProvider` event when remote node registers as a provider via `ADD_PROVIDER` request.
1 parent e9f4f97 commit 1a0325c

File tree

8 files changed

+331
-224
lines changed

8 files changed

+331
-224
lines changed

src/protocol/libp2p/kademlia/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use std::{
4141
const DEFAULT_TTL: Duration = Duration::from_secs(36 * 60 * 60);
4242

4343
/// Default provider record TTL.
44-
const DEFAULT_PROVIDER_TTL: Duration = Duration::from_secs(48 * 60 * 60);
44+
pub(super) const DEFAULT_PROVIDER_TTL: Duration = Duration::from_secs(48 * 60 * 60);
4545

4646
/// Default provider republish interval.
4747
pub(super) const DEFAULT_PROVIDER_REFRESH_INTERVAL: Duration = Duration::from_secs(22 * 60 * 60);

src/protocol/libp2p/kademlia/handle.rs

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
// DEALINGS IN THE SOFTWARE.
2020

2121
use crate::{
22-
protocol::libp2p::kademlia::{KademliaPeer, PeerRecord, QueryId, Record, RecordKey},
22+
protocol::libp2p::kademlia::{ContentProvider, PeerRecord, QueryId, Record, RecordKey},
2323
PeerId,
2424
};
2525

@@ -148,9 +148,6 @@ pub(crate) enum KademliaCommand {
148148
/// Provided key.
149149
key: RecordKey,
150150

151-
/// Our external addresses to publish.
152-
public_addresses: Vec<Multiaddr>,
153-
154151
/// Query ID for the query.
155152
query_id: QueryId,
156153
},
@@ -210,9 +207,12 @@ pub enum KademliaEvent {
210207
/// Query ID.
211208
query_id: QueryId,
212209

210+
/// Provided key.
211+
provided_key: RecordKey,
212+
213213
/// Found providers with cached addresses. Returned providers are sorted by distane to the
214214
/// provided key.
215-
providers: Vec<KademliaPeer>,
215+
providers: Vec<ContentProvider>,
216216
},
217217

218218
/// `PUT_VALUE` query succeeded.
@@ -240,6 +240,15 @@ pub enum KademliaEvent {
240240
/// Record.
241241
record: Record,
242242
},
243+
244+
/// Incoming `ADD_PROVIDER` request received.
245+
IncomingProvider {
246+
/// Provided key.
247+
provided_key: RecordKey,
248+
249+
/// Provider.
250+
provider: ContentProvider,
251+
},
243252
}
244253

245254
/// The type of the DHT records.
@@ -352,20 +361,9 @@ impl KademliaHandle {
352361
///
353362
/// Register the local peer ID & its `public_addresses` as a provider for a given `key`.
354363
/// Returns [`Err`] only if `Kademlia` is terminating.
355-
pub async fn start_providing(
356-
&mut self,
357-
key: RecordKey,
358-
public_addresses: Vec<Multiaddr>,
359-
) -> QueryId {
364+
pub async fn start_providing(&mut self, key: RecordKey) -> QueryId {
360365
let query_id = self.next_query_id();
361-
let _ = self
362-
.cmd_tx
363-
.send(KademliaCommand::StartProviding {
364-
key,
365-
public_addresses,
366-
query_id,
367-
})
368-
.await;
366+
let _ = self.cmd_tx.send(KademliaCommand::StartProviding { key, query_id }).await;
369367

370368
query_id
371369
}

src/protocol/libp2p/kademlia/message.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
use crate::{
2222
protocol::libp2p::kademlia::{
23-
record::{Key as RecordKey, ProviderRecord, Record},
23+
record::{ContentProvider, Key as RecordKey, Record},
2424
schema,
2525
types::{ConnectionType, KademliaPeer},
2626
},
@@ -172,14 +172,14 @@ impl KademliaMessage {
172172
}
173173

174174
/// Create `ADD_PROVIDER` message with `provider`.
175-
pub fn add_provider(provider: ProviderRecord) -> Bytes {
175+
pub fn add_provider(provided_key: RecordKey, provider: ContentProvider) -> Bytes {
176176
let peer = KademliaPeer::new(
177-
provider.provider,
177+
provider.peer,
178178
provider.addresses,
179179
ConnectionType::CanConnect, // ignored by message recipient
180180
);
181181
let message = schema::kademlia::Message {
182-
key: provider.key.clone().to_vec(),
182+
key: provided_key.clone().to_vec(),
183183
cluster_level_raw: 10,
184184
r#type: schema::kademlia::MessageType::AddProvider.into(),
185185
provider_peers: std::iter::once((&peer).into()).collect(),
@@ -209,16 +209,17 @@ impl KademliaMessage {
209209

210210
/// Create `GET_PROVIDERS` response.
211211
pub fn get_providers_response(
212-
providers: Vec<ProviderRecord>,
212+
providers: Vec<ContentProvider>,
213213
closer_peers: &[KademliaPeer],
214214
) -> Vec<u8> {
215215
let provider_peers = providers
216216
.into_iter()
217217
.map(|p| {
218218
KademliaPeer::new(
219-
p.provider,
219+
p.peer,
220220
p.addresses,
221-
ConnectionType::CanConnect, // ignored by recipient
221+
// `ConnectionType` is ignored by a recipient
222+
ConnectionType::NotConnected,
222223
)
223224
})
224225
.map(|p| (&p).into())

src/protocol/libp2p/kademlia/mod.rs

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use crate::{
2929
handle::KademliaCommand,
3030
message::KademliaMessage,
3131
query::{QueryAction, QueryEngine},
32-
record::ProviderRecord,
3332
routing_table::RoutingTable,
3433
store::{MemoryStore, MemoryStoreAction, MemoryStoreConfig},
3534
types::{ConnectionType, KademliaPeer, Key},
@@ -61,7 +60,7 @@ pub use handle::{
6160
IncomingRecordValidationMode, KademliaEvent, KademliaHandle, Quorum, RoutingTableUpdateMode,
6261
};
6362
pub use query::QueryId;
64-
pub use record::{Key as RecordKey, PeerRecord, Record};
63+
pub use record::{ContentProvider, Key as RecordKey, PeerRecord, Record};
6564

6665
/// Logging target for the file.
6766
const LOG_TARGET: &str = "litep2p::ipfs::kademlia";
@@ -165,9 +164,6 @@ pub(crate) struct Kademlia {
165164
/// Default record TTL.
166165
record_ttl: Duration,
167166

168-
/// Provider record TTL.
169-
provider_ttl: Duration,
170-
171167
/// Query engine.
172168
engine: QueryEngine,
173169

@@ -193,6 +189,7 @@ impl Kademlia {
193189
local_peer_id,
194190
MemoryStoreConfig {
195191
provider_refresh_interval: config.provider_refresh_interval,
192+
provider_ttl: config.provider_ttl,
196193
..Default::default()
197194
},
198195
);
@@ -212,7 +209,6 @@ impl Kademlia {
212209
update_mode: config.update_mode,
213210
validation_mode: config.validation_mode,
214211
record_ttl: config.record_ttl,
215-
provider_ttl: config.provider_ttl,
216212
replication_factor: config.replication_factor,
217213
engine: QueryEngine::new(local_peer_id, config.replication_factor, PARALLELISM_FACTOR),
218214
}
@@ -523,7 +519,7 @@ impl Kademlia {
523519
),
524520
}
525521
}
526-
KademliaMessage::AddProvider { key, providers } => {
522+
KademliaMessage::AddProvider { key, mut providers } => {
527523
tracing::trace!(
528524
target: LOG_TARGET,
529525
?peer,
@@ -532,15 +528,27 @@ impl Kademlia {
532528
"handle `ADD_PROVIDER` message",
533529
);
534530

535-
match (providers.len(), providers.first()) {
531+
match (providers.len(), providers.pop()) {
536532
(1, Some(provider)) =>
537533
if provider.peer == peer {
538-
self.store.put_provider(ProviderRecord {
539-
key,
540-
provider: peer,
541-
addresses: provider.addresses.clone(),
542-
expires: Instant::now() + self.provider_ttl,
543-
});
534+
self.store.put_provider(
535+
key.clone(),
536+
ContentProvider {
537+
peer,
538+
addresses: provider.addresses.clone(),
539+
},
540+
);
541+
542+
let _ = self
543+
.event_tx
544+
.send(KademliaEvent::IncomingProvider {
545+
provided_key: key,
546+
provider: ContentProvider {
547+
peer: provider.peer,
548+
addresses: provider.addresses,
549+
},
550+
})
551+
.await;
544552
} else {
545553
tracing::trace!(
546554
target: LOG_TARGET,
@@ -590,10 +598,13 @@ impl Kademlia {
590598
"handle `GET_PROVIDERS` request",
591599
);
592600

593-
let providers = self.store.get_providers(key);
594-
// TODO: if local peer is among the providers, update its `ProviderRecord`
595-
// to have up-to-date addresses.
596-
// Requires https://github.com/paritytech/litep2p/issues/211.
601+
let mut providers = self.store.get_providers(key);
602+
603+
// Make sure local provider addresses are up to date.
604+
let local_peer_id = self.local_key.clone().into_preimage();
605+
providers.iter_mut().find(|p| p.peer == local_peer_id).as_mut().map(|p| {
606+
p.addresses = self.service.public_addresses().get_addresses();
607+
});
597608

598609
let closer_peers = self
599610
.routing_table
@@ -787,16 +798,19 @@ impl Kademlia {
787798

788799
Ok(())
789800
}
790-
QueryAction::AddProviderToFoundNodes { provider, peers } => {
801+
QueryAction::AddProviderToFoundNodes {
802+
provided_key,
803+
provider,
804+
peers,
805+
} => {
791806
tracing::trace!(
792807
target: LOG_TARGET,
793-
provided_key = ?provider.key,
808+
?provided_key,
794809
num_peers = ?peers.len(),
795810
"add provider record to found peers",
796811
);
797812

798-
let provided_key = provider.key.clone();
799-
let message = KademliaMessage::add_provider(provider);
813+
let message = KademliaMessage::add_provider(provided_key.clone(), provider);
800814

801815
for peer in peers {
802816
if let Err(error) = self.open_substream_or_dial(
@@ -828,12 +842,14 @@ impl Kademlia {
828842
}
829843
QueryAction::GetProvidersQueryDone {
830844
query_id,
845+
provided_key,
831846
providers,
832847
} => {
833848
let _ = self
834849
.event_tx
835850
.send(KademliaEvent::GetProvidersSuccess {
836851
query_id,
852+
provided_key,
837853
providers,
838854
})
839855
.await;
@@ -1036,28 +1052,26 @@ impl Kademlia {
10361052
}
10371053
Some(KademliaCommand::StartProviding {
10381054
key,
1039-
public_addresses,
10401055
query_id
10411056
}) => {
10421057
tracing::debug!(
10431058
target: LOG_TARGET,
10441059
query = ?query_id,
10451060
?key,
1046-
?public_addresses,
10471061
"register as a content provider",
10481062
);
10491063

1050-
let provider = ProviderRecord {
1051-
key: key.clone(),
1052-
provider: self.service.local_peer_id(),
1053-
addresses: public_addresses,
1054-
expires: Instant::now() + self.provider_ttl,
1064+
let addresses = self.service.public_addresses().get_addresses();
1065+
let provider = ContentProvider {
1066+
peer: self.service.local_peer_id(),
1067+
addresses,
10551068
};
10561069

1057-
self.store.put_provider(provider.clone());
1070+
self.store.put_provider(key.clone(), provider.clone());
10581071

10591072
self.engine.start_add_provider(
10601073
query_id,
1074+
key.clone(),
10611075
provider,
10621076
self.routing_table
10631077
.closest(Key::new(key), self.replication_factor)
@@ -1105,12 +1119,15 @@ impl Kademlia {
11051119
Some(KademliaCommand::GetProviders { key, query_id }) => {
11061120
tracing::debug!(target: LOG_TARGET, ?key, "get providers from DHT");
11071121

1122+
let known_providers = self.store.get_providers(&key);
1123+
11081124
self.engine.start_get_providers(
11091125
query_id,
11101126
key.clone(),
11111127
self.routing_table
11121128
.closest(Key::new(key), self.replication_factor)
11131129
.into(),
1130+
known_providers,
11141131
);
11151132
}
11161133
Some(KademliaCommand::AddKnownPeer { peer, addresses }) => {
@@ -1151,25 +1168,24 @@ impl Kademlia {
11511168
}
11521169
},
11531170
action = self.store.next_action() => match action {
1154-
Some(MemoryStoreAction::RefreshProvider { mut provider }) => {
1171+
Some(MemoryStoreAction::RefreshProvider { provided_key, provider }) => {
11551172
tracing::trace!(
11561173
target: LOG_TARGET,
1157-
key = ?provider.key,
1174+
?provided_key,
11581175
"republishing local provider",
11591176
);
11601177

1161-
// Make sure to roll expiration time.
1162-
provider.expires = Instant::now() + self.provider_ttl;
1163-
1164-
self.store.put_provider(provider.clone());
1178+
self.store.put_provider(provided_key.clone(), provider.clone());
1179+
// We never update local provider addresses in the store when refresh
1180+
// it, as this is done anyway when replying to `GET_PROVIDERS` request.
11651181

1166-
let key = provider.key.clone();
11671182
let query_id = self.next_query_id();
11681183
self.engine.start_add_provider(
11691184
query_id,
1185+
provided_key.clone(),
11701186
provider,
11711187
self.routing_table
1172-
.closest(Key::new(key), self.replication_factor)
1188+
.closest(Key::new(provided_key), self.replication_factor)
11731189
.into(),
11741190
);
11751191
}

0 commit comments

Comments
 (0)