hotshot_libp2p_networking/network/behaviours/dht/store/
validated.rs1use std::marker::PhantomData;
7
8use delegate::delegate;
9use hotshot_types::traits::signature_key::SignatureKey;
10use libp2p::kad::store::{Error, RecordStore, Result};
11use tracing::warn;
12
13use crate::network::behaviours::dht::record::{RecordKey, RecordValue};
14
15pub struct ValidatedStore<R: RecordStore, K: SignatureKey> {
17 store: R,
19
20 phantom: std::marker::PhantomData<K>,
22}
23
24impl<R: RecordStore, K: SignatureKey> ValidatedStore<R, K> {
25 pub fn new(store: R) -> Self {
27 ValidatedStore {
28 store,
29 phantom: PhantomData,
30 }
31 }
32}
33
34impl<R: RecordStore, K: SignatureKey> RecordStore for ValidatedStore<R, K>
36where
37 K: 'static,
38{
39 type ProvidedIter<'a>
40 = R::ProvidedIter<'a>
41 where
42 R: 'a,
43 K: 'a;
44 type RecordsIter<'a>
45 = R::RecordsIter<'a>
46 where
47 R: 'a,
48 K: 'a;
49
50 delegate! {
52 to self.store{
53 fn add_provider(&mut self, record: libp2p::kad::ProviderRecord) -> libp2p::kad::store::Result<()>;
54 fn get(&self, k: &libp2p::kad::RecordKey) -> Option<std::borrow::Cow<'_, libp2p::kad::Record>>;
55 fn provided(&self) -> Self::ProvidedIter<'_>;
56 fn providers(&self, key: &libp2p::kad::RecordKey) -> Vec<libp2p::kad::ProviderRecord>;
57 fn records(&self) -> Self::RecordsIter<'_>;
58 fn remove(&mut self, k: &libp2p::kad::RecordKey);
59 fn remove_provider(&mut self, k: &libp2p::kad::RecordKey, p: &libp2p::PeerId);
60 }
61 }
62
63 fn put(&mut self, record: libp2p::kad::Record) -> Result<()> {
65 if let Ok(record_value) = RecordValue::<K>::try_from(record.clone()) {
67 let Ok(record_key) = RecordKey::try_from_bytes(&record.key.to_vec()) else {
69 warn!("Failed to convert record key");
70 return Err(Error::MaxRecords);
71 };
72
73 if record_value.validate(&record_key) {
75 if let Err(err) = self.store.put(record.clone()) {
77 warn!("Failed to store record: {err:?}");
78 return Err(Error::MaxRecords);
79 }
80 } else {
81 warn!("Failed to validate record");
82 return Err(Error::MaxRecords);
83 }
84 }
85
86 Ok(())
87 }
88}
89
90#[cfg(test)]
91mod test {
92 use hotshot_types::signature_key::BLSPubKey;
93 use libp2p::{
94 kad::{store::MemoryStore, Record},
95 PeerId,
96 };
97
98 use super::*;
99 use crate::network::behaviours::dht::record::Namespace;
100
101 #[test]
103 fn test_valid_stored() {
104 let (public_key, private_key) = BLSPubKey::generated_from_seed_indexed([1; 32], 1337);
106
107 let value = vec![5, 6, 7, 8];
109
110 let record_key = RecordKey::new(Namespace::Lookup, public_key.to_bytes());
112
113 let record_value: RecordValue<BLSPubKey> =
115 RecordValue::new_signed(&record_key, value.clone(), &private_key).unwrap();
116
117 let mut store: ValidatedStore<MemoryStore, BLSPubKey> =
119 ValidatedStore::new(MemoryStore::new(PeerId::random()));
120
121 let record_value_bytes =
123 bincode::serialize(&record_value).expect("Failed to serialize record value");
124
125 let record = Record::new(record_key.to_bytes(), record_value_bytes);
127 store.put(record).expect("Failed to store record");
128
129 let libp2p_record_key = libp2p::kad::RecordKey::new(&record_key.to_bytes());
131 let stored_record = store.get(&libp2p_record_key).expect("Failed to get record");
132 let stored_record_value: RecordValue<BLSPubKey> =
133 bincode::deserialize(&stored_record.value).expect("Failed to deserialize record value");
134
135 assert_eq!(
137 record_value, stored_record_value,
138 "Stored record is not the same as original"
139 );
140 }
141
142 #[test]
144 fn test_invalid_not_stored() {
145 let (public_key, _) = BLSPubKey::generated_from_seed_indexed([1; 32], 1337);
147
148 let record_key = RecordKey::new(Namespace::Lookup, public_key.to_bytes());
150
151 let record_value: RecordValue<BLSPubKey> = RecordValue::new(vec![2, 3]);
153
154 let mut store: ValidatedStore<MemoryStore, BLSPubKey> =
156 ValidatedStore::new(MemoryStore::new(PeerId::random()));
157
158 let record_value_bytes =
160 bincode::serialize(&record_value).expect("Failed to serialize record value");
161
162 let record = Record::new(record_key.to_bytes(), record_value_bytes);
164 assert!(store.put(record).is_err(), "Should not have stored record");
165
166 let libp2p_record_key = libp2p::kad::RecordKey::new(&record_key.to_bytes());
168 assert!(
169 store.get(&libp2p_record_key).is_none(),
170 "Should not have stored record"
171 );
172 }
173}