1use parking_lot::Mutex;
22
23use crate::ProofSizeProvider;
24use std::{collections::VecDeque, sync::Arc};
25
26sp_externalities::decl_extension! {
27 pub struct ProofSizeExt(Box<dyn ProofSizeProvider + 'static + Sync + Send>);
30
31 impl ProofSizeExt {
32 fn start_transaction(&mut self, ty: sp_externalities::TransactionType) {
33 self.0.start_transaction(ty.is_host());
34 }
35
36 fn rollback_transaction(&mut self, ty: sp_externalities::TransactionType) {
37 self.0.rollback_transaction(ty.is_host());
38 }
39
40 fn commit_transaction(&mut self, ty: sp_externalities::TransactionType) {
41 self.0.commit_transaction(ty.is_host());
42 }
43 }
44}
45
46impl ProofSizeExt {
47 pub fn new<T: ProofSizeProvider + Sync + Send + 'static>(recorder: T) -> Self {
49 ProofSizeExt(Box::new(recorder))
50 }
51
52 pub fn storage_proof_size(&self) -> u64 {
54 self.0.estimate_encoded_size() as _
55 }
56}
57
58pub struct RecordedProofSizeEstimations(pub VecDeque<usize>);
64
65struct RecordingProofSizeProviderInner {
67 inner: Box<dyn ProofSizeProvider + Send + Sync>,
68 proof_size_estimations: Vec<Vec<usize>>,
72}
73
74#[derive(Clone)]
80pub struct RecordingProofSizeProvider {
81 inner: Arc<Mutex<RecordingProofSizeProviderInner>>,
82}
83
84impl RecordingProofSizeProvider {
85 pub fn new<T: ProofSizeProvider + Sync + Send + 'static>(recorder: T) -> Self {
87 Self {
88 inner: Arc::new(Mutex::new(RecordingProofSizeProviderInner {
89 inner: Box::new(recorder),
90 proof_size_estimations: vec![Vec::new()],
92 })),
93 }
94 }
95
96 pub fn recorded_estimations(&self) -> Vec<usize> {
99 self.inner.lock().proof_size_estimations.iter().flatten().copied().collect()
100 }
101}
102
103impl ProofSizeProvider for RecordingProofSizeProvider {
104 fn estimate_encoded_size(&self) -> usize {
105 let mut inner = self.inner.lock();
106
107 let estimation = inner.inner.estimate_encoded_size();
108
109 inner
110 .proof_size_estimations
111 .last_mut()
112 .expect("There is always at least one transaction open; qed")
113 .push(estimation);
114
115 estimation
116 }
117
118 fn start_transaction(&mut self, is_host: bool) {
119 if is_host {
133 self.inner.lock().proof_size_estimations.push(Default::default());
134 }
135 }
136
137 fn rollback_transaction(&mut self, is_host: bool) {
138 let mut inner = self.inner.lock();
139
140 if is_host && inner.proof_size_estimations.len() > 1 {
144 inner.proof_size_estimations.pop();
145 }
146 }
147
148 fn commit_transaction(&mut self, is_host: bool) {
149 let mut inner = self.inner.lock();
150
151 if is_host && inner.proof_size_estimations.len() > 1 {
152 let last = inner
153 .proof_size_estimations
154 .pop()
155 .expect("There are more than one element in the vector; qed");
156
157 inner
158 .proof_size_estimations
159 .last_mut()
160 .expect("There are more than one element in the vector; qed")
161 .extend(last);
162 }
163 }
164}
165
166pub struct ReplayProofSizeProvider(Arc<Mutex<RecordedProofSizeEstimations>>);
172
173impl ReplayProofSizeProvider {
174 pub fn from_recorded(recorded: RecordedProofSizeEstimations) -> Self {
176 Self(Arc::new(Mutex::new(recorded)))
177 }
178}
179
180impl From<RecordedProofSizeEstimations> for ReplayProofSizeProvider {
181 fn from(value: RecordedProofSizeEstimations) -> Self {
182 Self::from_recorded(value)
183 }
184}
185
186impl ProofSizeProvider for ReplayProofSizeProvider {
187 fn estimate_encoded_size(&self) -> usize {
188 self.0.lock().0.pop_front().unwrap_or_default()
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use std::sync::atomic::{AtomicUsize, Ordering};
196
197 #[derive(Clone)]
199 struct MockProofSizeProvider {
200 size: Arc<AtomicUsize>,
201 }
202
203 impl MockProofSizeProvider {
204 fn new(initial_size: usize) -> Self {
205 Self { size: Arc::new(AtomicUsize::new(initial_size)) }
206 }
207
208 fn set_size(&self, new_size: usize) {
209 self.size.store(new_size, Ordering::Relaxed);
210 }
211 }
212
213 impl ProofSizeProvider for MockProofSizeProvider {
214 fn estimate_encoded_size(&self) -> usize {
215 self.size.load(Ordering::Relaxed)
216 }
217
218 fn start_transaction(&mut self, _is_host: bool) {}
219 fn rollback_transaction(&mut self, _is_host: bool) {}
220 fn commit_transaction(&mut self, _is_host: bool) {}
221 }
222
223 #[test]
224 fn recording_proof_size_provider_basic_functionality() {
225 let mock = MockProofSizeProvider::new(100);
226 let tracker = RecordingProofSizeProvider::new(mock.clone());
227
228 assert_eq!(tracker.recorded_estimations(), Vec::<usize>::new());
230
231 let size = tracker.estimate_encoded_size();
233 assert_eq!(size, 100);
234 assert_eq!(tracker.recorded_estimations(), vec![100]);
235
236 mock.set_size(200);
238 let size = tracker.estimate_encoded_size();
239 assert_eq!(size, 200);
240 assert_eq!(tracker.recorded_estimations(), vec![100, 200]);
241
242 let size = tracker.estimate_encoded_size();
244 assert_eq!(size, 200);
245 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 200]);
246 }
247
248 #[test]
249 fn recording_proof_size_provider_host_transactions() {
250 let mock = MockProofSizeProvider::new(100);
251 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
252
253 tracker.estimate_encoded_size();
255 tracker.estimate_encoded_size();
256 assert_eq!(tracker.recorded_estimations(), vec![100, 100]);
257
258 tracker.start_transaction(true);
260 mock.set_size(200);
261 tracker.estimate_encoded_size();
262
263 assert_eq!(tracker.recorded_estimations(), vec![100, 100, 200]);
265
266 tracker.commit_transaction(true);
268
269 assert_eq!(tracker.recorded_estimations(), vec![100, 100, 200]);
271
272 mock.set_size(300);
274 tracker.estimate_encoded_size();
275 assert_eq!(tracker.recorded_estimations(), vec![100, 100, 200, 300]);
276 }
277
278 #[test]
279 fn recording_proof_size_provider_host_transaction_rollback() {
280 let mock = MockProofSizeProvider::new(100);
281 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
282
283 tracker.estimate_encoded_size();
285 assert_eq!(tracker.recorded_estimations(), vec![100]);
286
287 tracker.start_transaction(true);
289 mock.set_size(200);
290 tracker.estimate_encoded_size();
291 tracker.estimate_encoded_size();
292
293 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 200]);
295
296 tracker.rollback_transaction(true);
298
299 assert_eq!(tracker.recorded_estimations(), vec![100]);
301 }
302
303 #[test]
304 fn recording_proof_size_provider_runtime_transactions_ignored() {
305 let mock = MockProofSizeProvider::new(100);
306 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
307
308 tracker.estimate_encoded_size();
310 assert_eq!(tracker.recorded_estimations(), vec![100]);
311
312 tracker.start_transaction(false);
314 mock.set_size(200);
315 tracker.estimate_encoded_size();
316
317 assert_eq!(tracker.recorded_estimations(), vec![100, 200]);
319
320 tracker.commit_transaction(false);
322 assert_eq!(tracker.recorded_estimations(), vec![100, 200]);
323
324 tracker.rollback_transaction(false);
326 assert_eq!(tracker.recorded_estimations(), vec![100, 200]);
327 }
328
329 #[test]
330 fn recording_proof_size_provider_nested_host_transactions() {
331 let mock = MockProofSizeProvider::new(100);
332 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
333
334 tracker.estimate_encoded_size();
336 assert_eq!(tracker.recorded_estimations(), vec![100]);
337
338 tracker.start_transaction(true);
340 mock.set_size(200);
341 tracker.estimate_encoded_size();
342
343 tracker.start_transaction(true);
345 mock.set_size(300);
346 tracker.estimate_encoded_size();
347
348 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 300]);
349
350 tracker.commit_transaction(true);
352 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 300]);
353
354 tracker.commit_transaction(true);
356 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 300]);
357 }
358
359 #[test]
360 fn recording_proof_size_provider_nested_host_transaction_rollback() {
361 let mock = MockProofSizeProvider::new(100);
362 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
363
364 tracker.estimate_encoded_size();
366
367 tracker.start_transaction(true);
369 mock.set_size(200);
370 tracker.estimate_encoded_size();
371
372 tracker.start_transaction(true);
374 mock.set_size(300);
375 tracker.estimate_encoded_size();
376
377 assert_eq!(tracker.recorded_estimations(), vec![100, 200, 300]);
378
379 tracker.rollback_transaction(true);
381 assert_eq!(tracker.recorded_estimations(), vec![100, 200]);
382
383 tracker.rollback_transaction(true);
385 assert_eq!(tracker.recorded_estimations(), vec![100]);
386 }
387
388 #[test]
389 fn recording_proof_size_provider_rollback_on_base_transaction_does_nothing() {
390 let mock = MockProofSizeProvider::new(100);
391 let mut tracker = RecordingProofSizeProvider::new(mock.clone());
392
393 tracker.estimate_encoded_size();
395 tracker.estimate_encoded_size();
396 assert_eq!(tracker.recorded_estimations(), vec![100, 100]);
397
398 tracker.rollback_transaction(true);
400 assert_eq!(tracker.recorded_estimations(), vec![100, 100]);
401 }
402
403 #[test]
404 fn recorded_proof_size_estimations_struct() {
405 let estimations = vec![100, 200, 300];
406 let recorded = RecordedProofSizeEstimations(estimations.into());
407 let expected: VecDeque<usize> = vec![100, 200, 300].into();
408 assert_eq!(recorded.0, expected);
409 }
410
411 #[test]
412 fn replay_proof_size_provider_basic_functionality() {
413 let estimations = vec![100, 200, 300, 150];
414 let recorded = RecordedProofSizeEstimations(estimations.into());
415 let replay = ReplayProofSizeProvider::from_recorded(recorded);
416
417 assert_eq!(replay.estimate_encoded_size(), 100);
419 assert_eq!(replay.estimate_encoded_size(), 200);
420 assert_eq!(replay.estimate_encoded_size(), 300);
421 assert_eq!(replay.estimate_encoded_size(), 150);
422 }
423
424 #[test]
425 fn replay_proof_size_provider_exhausted_returns_zero() {
426 let estimations = vec![100, 200];
427 let recorded = RecordedProofSizeEstimations(estimations.into());
428 let replay = ReplayProofSizeProvider::from_recorded(recorded);
429
430 assert_eq!(replay.estimate_encoded_size(), 100);
432 assert_eq!(replay.estimate_encoded_size(), 200);
433
434 assert_eq!(replay.estimate_encoded_size(), 0);
436 assert_eq!(replay.estimate_encoded_size(), 0);
437 }
438
439 #[test]
440 fn replay_proof_size_provider_empty_returns_zero() {
441 let recorded = RecordedProofSizeEstimations(VecDeque::new());
442 let replay = ReplayProofSizeProvider::from_recorded(recorded);
443
444 assert_eq!(replay.estimate_encoded_size(), 0);
446 assert_eq!(replay.estimate_encoded_size(), 0);
447 }
448
449 #[test]
450 fn replay_proof_size_provider_from_trait() {
451 let estimations = vec![42, 84];
452 let recorded = RecordedProofSizeEstimations(estimations.into());
453 let replay: ReplayProofSizeProvider = recorded.into();
454
455 assert_eq!(replay.estimate_encoded_size(), 42);
456 assert_eq!(replay.estimate_encoded_size(), 84);
457 assert_eq!(replay.estimate_encoded_size(), 0);
458 }
459
460 #[test]
461 fn record_and_replay_integration() {
462 let mock = MockProofSizeProvider::new(100);
463 let recorder = RecordingProofSizeProvider::new(mock.clone());
464
465 recorder.estimate_encoded_size();
467 mock.set_size(200);
468 recorder.estimate_encoded_size();
469 mock.set_size(300);
470 recorder.estimate_encoded_size();
471
472 let recorded_estimations = recorder.recorded_estimations();
474 assert_eq!(recorded_estimations, vec![100, 200, 300]);
475
476 let recorded = RecordedProofSizeEstimations(recorded_estimations.into());
478 let replay = ReplayProofSizeProvider::from_recorded(recorded);
479
480 assert_eq!(replay.estimate_encoded_size(), 100);
482 assert_eq!(replay.estimate_encoded_size(), 200);
483 assert_eq!(replay.estimate_encoded_size(), 300);
484 assert_eq!(replay.estimate_encoded_size(), 0);
485 }
486
487 #[test]
488 fn replay_proof_size_provider_single_value() {
489 let estimations = vec![42];
490 let recorded = RecordedProofSizeEstimations(estimations.into());
491 let replay = ReplayProofSizeProvider::from_recorded(recorded);
492
493 assert_eq!(replay.estimate_encoded_size(), 42);
495 assert_eq!(replay.estimate_encoded_size(), 0);
496 }
497}