@@ -69,6 +69,9 @@ pub struct Kademlia<TStore> {
6969 /// Configuration of the wire protocol.
7070 protocol_config : KademliaProtocolConfig ,
7171
72+ /// Configuration of [`RecordStore`] filtering.
73+ record_filtering : KademliaStoreInserts ,
74+
7275 /// The currently active (i.e. in-progress) queries.
7376 queries : QueryPool < QueryInner > ,
7477
@@ -131,6 +134,29 @@ pub enum KademliaBucketInserts {
131134 Manual ,
132135}
133136
137+ /// The configurable filtering strategies for the acceptance of
138+ /// incoming records.
139+ ///
140+ /// This can be used for e.g. signature verification or validating
141+ /// the accompanying [`Key`].
142+ ///
143+ /// [`Key`]: crate::record::Key
144+ #[ derive( Copy , Clone , Debug , PartialEq , Eq ) ]
145+ pub enum KademliaStoreInserts {
146+ /// Whenever a (provider) record is received,
147+ /// the record is forwarded immediately to the [`RecordStore`].
148+ Unfiltered ,
149+ /// Whenever a (provider) record is received, an event is emitted.
150+ /// Provider records generate a [`KademliaEvent::InboundAddProviderRequest`],
151+ /// normal records generate a [`KademliaEvent::InboundPutRecordRequest`].
152+ ///
153+ /// When deemed valid, a (provider) record needs to be explicitly stored in
154+ /// the [`RecordStore`] via [`RecordStore::put`] or [`RecordStore::add_provider`],
155+ /// whichever is applicable. A mutable reference to the [`RecordStore`] can
156+ /// be retrieved via [`Kademlia::store_mut`].
157+ FilterBoth ,
158+ }
159+
134160/// The configuration for the `Kademlia` behaviour.
135161///
136162/// The configuration is consumed by [`Kademlia::new`].
@@ -142,6 +168,7 @@ pub struct KademliaConfig {
142168 record_ttl : Option < Duration > ,
143169 record_replication_interval : Option < Duration > ,
144170 record_publication_interval : Option < Duration > ,
171+ record_filtering : KademliaStoreInserts ,
145172 provider_record_ttl : Option < Duration > ,
146173 provider_publication_interval : Option < Duration > ,
147174 connection_idle_timeout : Duration ,
@@ -175,6 +202,7 @@ impl Default for KademliaConfig {
175202 record_ttl : Some ( Duration :: from_secs ( 36 * 60 * 60 ) ) ,
176203 record_replication_interval : Some ( Duration :: from_secs ( 60 * 60 ) ) ,
177204 record_publication_interval : Some ( Duration :: from_secs ( 24 * 60 * 60 ) ) ,
205+ record_filtering : KademliaStoreInserts :: Unfiltered ,
178206 provider_publication_interval : Some ( Duration :: from_secs ( 12 * 60 * 60 ) ) ,
179207 provider_record_ttl : Some ( Duration :: from_secs ( 24 * 60 * 60 ) ) ,
180208 connection_idle_timeout : Duration :: from_secs ( 10 ) ,
@@ -259,6 +287,15 @@ impl KademliaConfig {
259287 self
260288 }
261289
290+ /// Sets whether or not records should be filtered before being stored.
291+ ///
292+ /// See [`KademliaStoreInserts`] for the different values.
293+ /// Defaults to [`KademliaStoreInserts::Unfiltered`].
294+ pub fn set_record_filtering ( & mut self , filtering : KademliaStoreInserts ) -> & mut Self {
295+ self . record_filtering = filtering;
296+ self
297+ }
298+
262299 /// Sets the (re-)replication interval for stored records.
263300 ///
264301 /// Periodic replication of stored records ensures that the records
@@ -393,6 +430,7 @@ where
393430 kbuckets : KBucketsTable :: new ( local_key, config. kbucket_pending_timeout ) ,
394431 kbucket_inserts : config. kbucket_inserts ,
395432 protocol_config : config. protocol_config ,
433+ record_filtering : config. record_filtering ,
396434 queued_events : VecDeque :: with_capacity ( config. query_config . replication_factor . get ( ) ) ,
397435 queries : QueryPool :: new ( config. query_config ) ,
398436 connected_peers : Default :: default ( ) ,
@@ -1572,22 +1610,33 @@ where
15721610 // The record is cloned because of the weird libp2p protocol
15731611 // requirement to send back the value in the response, although this
15741612 // is a waste of resources.
1575- match self . store . put ( record. clone ( ) ) {
1576- Ok ( ( ) ) => debug ! (
1577- "Record stored: {:?}; {} bytes" ,
1578- record. key,
1579- record. value. len( )
1580- ) ,
1581- Err ( e) => {
1582- info ! ( "Record not stored: {:?}" , e) ;
1613+ match self . record_filtering {
1614+ KademliaStoreInserts :: Unfiltered => match self . store . put ( record. clone ( ) ) {
1615+ Ok ( ( ) ) => debug ! (
1616+ "Record stored: {:?}; {} bytes" ,
1617+ record. key,
1618+ record. value. len( )
1619+ ) ,
1620+ Err ( e) => {
1621+ info ! ( "Record not stored: {:?}" , e) ;
1622+ self . queued_events
1623+ . push_back ( NetworkBehaviourAction :: NotifyHandler {
1624+ peer_id : source,
1625+ handler : NotifyHandler :: One ( connection) ,
1626+ event : KademliaHandlerIn :: Reset ( request_id) ,
1627+ } ) ;
1628+ return ;
1629+ }
1630+ } ,
1631+ KademliaStoreInserts :: FilterBoth => {
15831632 self . queued_events
1584- . push_back ( NetworkBehaviourAction :: NotifyHandler {
1585- peer_id : source ,
1586- handler : NotifyHandler :: One ( connection ) ,
1587- event : KademliaHandlerIn :: Reset ( request_id ) ,
1588- } ) ;
1589-
1590- return ;
1633+ . push_back ( NetworkBehaviourAction :: GenerateEvent (
1634+ KademliaEvent :: InboundPutRecordRequest {
1635+ source ,
1636+ connection ,
1637+ record : record . clone ( ) ,
1638+ } ,
1639+ ) ) ;
15911640 }
15921641 }
15931642 }
@@ -1620,8 +1669,18 @@ where
16201669 expires : self . provider_record_ttl . map ( |ttl| Instant :: now ( ) + ttl) ,
16211670 addresses : provider. multiaddrs ,
16221671 } ;
1623- if let Err ( e) = self . store . add_provider ( record) {
1624- info ! ( "Provider record not stored: {:?}" , e) ;
1672+ match self . record_filtering {
1673+ KademliaStoreInserts :: Unfiltered => {
1674+ if let Err ( e) = self . store . add_provider ( record) {
1675+ info ! ( "Provider record not stored: {:?}" , e) ;
1676+ }
1677+ }
1678+ KademliaStoreInserts :: FilterBoth => {
1679+ self . queued_events
1680+ . push_back ( NetworkBehaviourAction :: GenerateEvent (
1681+ KademliaEvent :: InboundAddProviderRequest { record } ,
1682+ ) ) ;
1683+ }
16251684 }
16261685 }
16271686 }
@@ -2257,6 +2316,20 @@ pub struct PeerRecord {
22572316/// See [`NetworkBehaviour::poll`].
22582317#[ derive( Debug ) ]
22592318pub enum KademliaEvent {
2319+ /// A peer sent a [`KademliaHandlerIn::PutRecord`] request and filtering is enabled.
2320+ ///
2321+ /// See [`KademliaStoreInserts`] and [`KademliaConfig::set_record_filtering`].
2322+ InboundPutRecordRequest {
2323+ source : PeerId ,
2324+ connection : ConnectionId ,
2325+ record : Record ,
2326+ } ,
2327+
2328+ /// A peer sent a [`KademliaHandlerIn::AddProvider`] request and filtering [`KademliaStoreInserts::FilterBoth`] is enabled.
2329+ ///
2330+ /// See [`KademliaStoreInserts`] and [`KademliaConfig::set_record_filtering`] for details..
2331+ InboundAddProviderRequest { record : ProviderRecord } ,
2332+
22602333 /// An inbound request has been received and handled.
22612334 //
22622335 // Note on the difference between 'request' and 'query': A request is a
0 commit comments