Skip to content

Commit a93a40f

Browse files
committed
chore: adjustments following reviews
- Rename new event from `CertificateValidatedFromCache` to `CertificateFetchedFromCache` - Better naming for the cache default duration in client (to make it explicit that the number is one week) - Make some tests more clear with better naming and more assertion - Change `ClientBuilder::with_certificate_verifier_cache` to take an option, allowing to disable existing cache and simplifying usage in the wasm library. - Simplify local storage acquisition in `LocalStorageCertificateVerifierCache` by raising an error if it's missing instead of asking consumer to handle an option (it should not be used if not available anyway). - Adjusted some comments and logs
1 parent be52d65 commit a93a40f

File tree

9 files changed

+95
-108
lines changed

9 files changed

+95
-108
lines changed

examples/client-snapshot/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl FeedbackReceiver for IndicatifFeedbackReceiver {
171171
progress_bar.inc(1);
172172
}
173173
}
174-
MithrilEvent::CertificateValidatedFromCache {
174+
MithrilEvent::CertificateFetchedFromCache {
175175
certificate_chain_validation_id: _,
176176
certificate_hash,
177177
} => {

mithril-client-cli/src/utils/feedback_receiver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl FeedbackReceiver for IndicatifFeedbackReceiver {
9292
progress_bar.inc(1);
9393
}
9494
}
95-
MithrilEvent::CertificateValidatedFromCache {
95+
MithrilEvent::CertificateFetchedFromCache {
9696
certificate_chain_validation_id: _,
9797
certificate_hash,
9898
} => {

mithril-client-wasm/src/certificate_verification_cache.rs

Lines changed: 58 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,18 @@ impl LocalStorageCertificateVerifierCache {
5454
previous_certificate_hash: &PreviousCertificateHash,
5555
expire_at: DateTime<Utc>,
5656
) -> MithrilResult<()> {
57-
if let Some(storage) = open_local_storage()? {
58-
let key = self.cache_key(certificate_hash);
59-
storage
60-
.set_item(
61-
&key,
62-
&serde_json::to_string(&CachedCertificate::new(
63-
previous_certificate_hash,
64-
expire_at,
65-
))
66-
.map_err(|err| anyhow!("Error serializing cache: {err:?}"))?,
67-
)
68-
.map_err(|err| anyhow!("Error storing key `{key}` in local storage: {err:?}"))?;
69-
}
57+
let key = self.cache_key(certificate_hash);
58+
open_local_storage()?
59+
.set_item(
60+
&key,
61+
&serde_json::to_string(&CachedCertificate::new(
62+
previous_certificate_hash,
63+
expire_at,
64+
))
65+
.map_err(|err| anyhow!("Error serializing cache: {err:?}"))?,
66+
)
67+
.map_err(|err| anyhow!("Error storing key `{key}` in local storage: {err:?}"))?;
68+
7069
Ok(())
7170
}
7271

@@ -80,11 +79,12 @@ impl LocalStorageCertificateVerifierCache {
8079
}
8180
}
8281

83-
fn open_local_storage() -> MithrilResult<Option<Storage>> {
82+
fn open_local_storage() -> MithrilResult<Storage> {
8483
let window = window()
8584
.with_context(|| "No window object")?
8685
.local_storage()
87-
.map_err(|err| anyhow!("Error accessing local storage: {err:?}"))?;
86+
.map_err(|err| anyhow!("Error accessing local storage: {err:?}"))?
87+
.with_context(|| "No local storage object")?;
8888
Ok(window)
8989
}
9090

@@ -108,50 +108,45 @@ impl CertificateVerifierCache for LocalStorageCertificateVerifierCache {
108108
&self,
109109
certificate_hash: &CertificateHash,
110110
) -> MithrilResult<Option<String>> {
111-
match open_local_storage()? {
112-
None => return Ok(None),
113-
Some(storage) => {
114-
let key = self.cache_key(certificate_hash);
115-
match storage.get_item(&key).map_err(|err| {
116-
anyhow!("Error accessing key `{key}` from local storage: {err:?}")
117-
})? {
118-
Some(value) => {
119-
let cached = Self::parse_cached_certificate(value)?;
120-
if Utc::now() >= cached.expire_at {
121-
Ok(None)
122-
} else {
123-
Ok(Some(cached.previous_hash))
124-
}
125-
}
126-
None => Ok(None),
111+
let key = self.cache_key(certificate_hash);
112+
match open_local_storage()?
113+
.get_item(&key)
114+
.map_err(|err| anyhow!("Error accessing key `{key}` from local storage: {err:?}"))?
115+
{
116+
Some(value) => {
117+
let cached = Self::parse_cached_certificate(value)?;
118+
if Utc::now() >= cached.expire_at {
119+
Ok(None)
120+
} else {
121+
Ok(Some(cached.previous_hash))
127122
}
128123
}
124+
None => Ok(None),
129125
}
130126
}
131127

132128
async fn reset(&self) -> MithrilResult<()> {
133-
if let Some(storage) = open_local_storage()? {
134-
let len = storage
135-
.length()
136-
.map_err(|err| anyhow!("Error accessing local storage length: {err:?}"))?;
137-
let mut key_to_remove = vec![];
138-
139-
for i in 0..len {
140-
match storage.key(i).map_err(|err| {
141-
anyhow!("Error accessing key index `{i}` from local storage: {err:?}")
142-
})? {
143-
Some(key) if key.starts_with(&self.cache_key_prefix) => key_to_remove.push(key),
144-
_ => continue,
145-
}
146-
}
129+
let storage = open_local_storage()?;
130+
let len = storage
131+
.length()
132+
.map_err(|err| anyhow!("Error accessing local storage length: {err:?}"))?;
133+
let mut key_to_remove = vec![];
147134

148-
for key in key_to_remove {
149-
storage.remove_item(&key).map_err(|err| {
150-
anyhow!("Error removing key `{key}` from local storage: {err:?}")
151-
})?;
135+
for i in 0..len {
136+
match storage.key(i).map_err(|err| {
137+
anyhow!("Error accessing key index `{i}` from local storage: {err:?}")
138+
})? {
139+
Some(key) if key.starts_with(&self.cache_key_prefix) => key_to_remove.push(key),
140+
_ => continue,
152141
}
153142
}
154143

144+
for key in key_to_remove {
145+
storage
146+
.remove_item(&key)
147+
.map_err(|err| anyhow!("Error removing key `{key}` from local storage: {err:?}"))?;
148+
}
149+
155150
Ok(())
156151
}
157152
}
@@ -164,7 +159,7 @@ pub(crate) mod test_tools {
164159

165160
/// `Test only` Return the raw content of the local storage
166161
pub(crate) fn local_storage_content() -> HashMap<String, String> {
167-
let storage = open_local_storage().unwrap().unwrap();
162+
let storage = open_local_storage().unwrap();
168163
let len = storage.length().unwrap();
169164
let mut content = HashMap::new();
170165

@@ -220,7 +215,7 @@ pub(crate) mod test_tools {
220215
certificate_hash: &CertificateHash,
221216
expire_at: DateTime<Utc>,
222217
) {
223-
let storage = open_local_storage().unwrap().unwrap();
218+
let storage = open_local_storage().unwrap();
224219
let key = self.cache_key(certificate_hash);
225220
let existing_value = Self::parse_cached_certificate(
226221
storage.get_item(&key).unwrap().expect("Key not found"),
@@ -243,7 +238,7 @@ pub(crate) mod test_tools {
243238
&self,
244239
certificate_hash: &CertificateHash,
245240
) -> Option<CachedCertificate> {
246-
let storage = open_local_storage().unwrap().unwrap();
241+
let storage = open_local_storage().unwrap();
247242
storage
248243
.get_item(&self.cache_key(certificate_hash))
249244
.unwrap()
@@ -286,7 +281,7 @@ mod tests {
286281
#[wasm_bindgen_test]
287282
async fn store_in_empty_cache_add_new_item_that_expire_after_parametrized_delay() {
288283
let expiration_delay = TimeDelta::hours(1);
289-
let now = Utc::now();
284+
let start_time = Utc::now();
290285
let cache = LocalStorageCertificateVerifierCache::new(
291286
"store_in_empty_cache_add_new_item_that_expire_after_parametrized_delay",
292287
expiration_delay,
@@ -302,7 +297,7 @@ mod tests {
302297

303298
assert_eq!(1, cache.len());
304299
assert_eq!("parent", cached.previous_hash);
305-
assert!(cached.expire_at - now >= expiration_delay);
300+
assert!(cached.expire_at - start_time >= expiration_delay);
306301
}
307302

308303
#[wasm_bindgen_test]
@@ -333,31 +328,32 @@ mod tests {
333328
#[wasm_bindgen_test]
334329
async fn storing_same_hash_update_parent_hash_and_expiration_time() {
335330
let expiration_delay = TimeDelta::days(2);
336-
let now = Utc::now();
331+
let start_time = Utc::now();
337332
let cache = LocalStorageCertificateVerifierCache::new(
338333
"storing_same_hash_update_parent_hash_and_expiration_time",
339334
expiration_delay,
340335
)
341336
.with_items([("hash", "first_parent"), ("another_hash", "another_parent")]);
342337

338+
let initial_value = cache.get_cached_value("hash").unwrap();
339+
343340
cache
344341
.store_validated_certificate("hash", "updated_parent")
345342
.await
346343
.unwrap();
347344

348-
let updated_value = cache
349-
.get_cached_value("hash")
350-
.expect("Cache should have been populated");
345+
let updated_value = cache.get_cached_value("hash").unwrap();
351346

352347
assert_eq!(2, cache.len());
353348
assert_eq!(
354349
Some("another_parent".to_string()),
355350
cache.get_previous_hash("another_hash").await.unwrap(),
356-
"Existing but not updated value should not have been altered, content: {:#?}, now: {:?}",
357-
local_storage_content(), now,
351+
"Existing but not updated value should not have been altered, content: {:#?}, start_time: {:?}",
352+
local_storage_content(), start_time,
358353
);
359354
assert_eq!("updated_parent", updated_value.previous_hash);
360-
assert!(updated_value.expire_at - now >= expiration_delay);
355+
assert_ne!(initial_value, updated_value);
356+
assert!(updated_value.expire_at - start_time >= expiration_delay);
361357
}
362358
}
363359

@@ -424,7 +420,7 @@ mod tests {
424420
TimeDelta::hours(1),
425421
)
426422
.with_items([("hash", "parent"), ("another_hash", "another_parent")]);
427-
let storage = open_local_storage().unwrap().unwrap();
423+
let storage = open_local_storage().unwrap();
428424
storage
429425
.set_item("key_from_another_component", "another_value")
430426
.unwrap();

mithril-client-wasm/src/client_wasm.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,29 +91,24 @@ impl MithrilClient {
9191
.map_err(|err| format!("Failed to parse options: {err:?}"))
9292
.unwrap()
9393
};
94-
let mut client_builder =
95-
ClientBuilder::aggregator(aggregator_endpoint, genesis_verification_key)
96-
.add_feedback_receiver(feedback_receiver)
97-
.with_options(client_options.clone());
9894

9995
let certificate_verifier_cache = if client_options.unstable
10096
&& client_options.enable_certificate_chain_verification_cache
10197
{
102-
let cache = Self::build_certifier_cache(
98+
Self::build_certifier_cache(
10399
aggregator_endpoint,
104100
TimeDelta::seconds(
105101
client_options.certificate_chain_verification_cache_duration_in_seconds as i64,
106102
),
107-
);
108-
if let Some(cache) = &cache {
109-
client_builder = client_builder.with_certificate_verifier_cache(cache.clone());
110-
}
111-
cache
103+
)
112104
} else {
113105
None
114106
};
115107

116-
let client = client_builder
108+
let client = ClientBuilder::aggregator(aggregator_endpoint, genesis_verification_key)
109+
.add_feedback_receiver(feedback_receiver)
110+
.with_options(client_options.clone())
111+
.with_certificate_verifier_cache(certificate_verifier_cache.clone())
117112
.build()
118113
.map_err(|err| format!("{err:?}"))
119114
.unwrap();
@@ -132,16 +127,15 @@ impl MithrilClient {
132127
if web_sys::window().is_none() {
133128
web_sys::console::warn_1(
134129
&"Can't enable certificate chain verification cache: window object is not available\
135-
(are you running in a browser environment ?)"
130+
(are you running in a browser environment?)"
136131
.into(),
137132
);
138133
return None;
139134
}
140135

141136
web_sys::console::warn_1(
142-
&"Certificate chain verification cache is enabled.\n\
143-
This feature is experimental and will be heavily modified or removed in the \
144-
future as its security implications are not fully understood."
137+
&"Danger: the certificate chain verification cache is enabled.\n\
138+
This feature is highly experimental and insecure, and it must not be used in production."
145139
.into(),
146140
);
147141

mithril-client/src/certificate_client/verify.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ impl MithrilCertificateVerifier {
111111
) -> MithrilResult<Option<CertificateToVerify>> {
112112
trace!(self.logger, "Validating certificate"; "hash" => certificate.hash(), "previous_hash" => certificate.hash());
113113
if let Some(previous_hash) = self.fetch_cached_previous_hash(certificate.hash()).await? {
114-
trace!(self.logger, "Certificate validated from cache"; "hash" => certificate.hash(), "previous_hash" => &previous_hash);
114+
trace!(self.logger, "Certificate fetched from cache"; "hash" => certificate.hash(), "previous_hash" => &previous_hash);
115115
self.feedback_sender
116-
.send_event(MithrilEvent::CertificateValidatedFromCache {
116+
.send_event(MithrilEvent::CertificateFetchedFromCache {
117117
certificate_hash: certificate.hash().to_owned(),
118118
certificate_chain_validation_id: certificate_chain_validation_id.to_string(),
119119
})

mithril-client/src/certificate_client/verify_cache/memory_cache.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ mod tests {
212212
#[tokio::test]
213213
async fn store_in_empty_cache_add_new_item_that_expire_after_parametrized_delay() {
214214
let expiration_delay = TimeDelta::hours(1);
215-
let now = Utc::now();
215+
let start_time = Utc::now();
216216
let cache = MemoryCertificateVerifierCache::new(expiration_delay);
217217
cache
218218
.store_validated_certificate("hash", "parent")
@@ -226,7 +226,7 @@ mod tests {
226226

227227
assert_eq!(1, cache.len().await);
228228
assert_eq!("parent", cached.previous_hash);
229-
assert!(cached.expire_at - now >= expiration_delay);
229+
assert!(cached.expire_at - start_time >= expiration_delay);
230230
}
231231

232232
#[tokio::test]
@@ -253,28 +253,28 @@ mod tests {
253253
#[tokio::test]
254254
async fn storing_same_hash_update_parent_hash_and_expiration_time() {
255255
let expiration_delay = TimeDelta::days(2);
256-
let now = Utc::now();
256+
let start_time = Utc::now();
257257
let cache = MemoryCertificateVerifierCache::new(expiration_delay)
258258
.with_items([("hash", "first_parent"), ("another_hash", "another_parent")]);
259259

260+
let initial_value = cache.get_cached_value("hash").await.unwrap();
261+
260262
cache
261263
.store_validated_certificate("hash", "updated_parent")
262264
.await
263265
.unwrap();
264266

265-
let updated_value = cache
266-
.get_cached_value("hash")
267-
.await
268-
.expect("Cache should have been populated");
267+
let updated_value = cache.get_cached_value("hash").await.unwrap();
269268

270269
assert_eq!(2, cache.len().await);
271270
assert_eq!(
272271
Some("another_parent".to_string()),
273272
cache.get_previous_hash("another_hash").await.unwrap(),
274273
"Existing but not updated value should not have been altered"
275274
);
275+
assert_ne!(initial_value, updated_value);
276276
assert_eq!("updated_parent", updated_value.previous_hash);
277-
assert!(updated_value.expire_at - now >= expiration_delay);
277+
assert!(updated_value.expire_at - start_time >= expiration_delay);
278278
}
279279
}
280280

0 commit comments

Comments
 (0)