1use super::{
7 accumulator::InMemoryAccumulator, position::Position, verify_transaction_info,
8 MerkleTreeInternalNode, SparseMerkleInternalNode, SparseMerkleLeafNode,
9};
10use crate::{
11 account_state_blob::AccountStateBlob,
12 ledger_info::LedgerInfo,
13 transaction::{TransactionInfoTrait, Version},
14};
15use anyhow::{bail, ensure, format_err, Context, Result};
16#[cfg(any(test, feature = "fuzzing"))]
17use diem_crypto::hash::TestOnlyHasher;
18use diem_crypto::{
19 hash::{
20 CryptoHash, CryptoHasher, EventAccumulatorHasher, TransactionAccumulatorHasher,
21 SPARSE_MERKLE_PLACEHOLDER_HASH,
22 },
23 HashValue,
24};
25#[cfg(any(test, feature = "fuzzing"))]
26use proptest_derive::Arbitrary;
27use serde::{Deserialize, Serialize};
28use std::marker::PhantomData;
29
30#[derive(Clone, Serialize, Deserialize)]
34pub struct AccumulatorProof<H> {
35 siblings: Vec<HashValue>,
38
39 phantom: PhantomData<H>,
40}
41
42pub type LeafCount = u64;
46pub const MAX_ACCUMULATOR_PROOF_DEPTH: usize = 63;
47pub const MAX_ACCUMULATOR_LEAVES: LeafCount = 1 << MAX_ACCUMULATOR_PROOF_DEPTH;
48
49impl<H> AccumulatorProof<H>
50where
51 H: CryptoHasher,
52{
53 pub fn new(siblings: Vec<HashValue>) -> Self {
55 AccumulatorProof {
56 siblings,
57 phantom: PhantomData,
58 }
59 }
60
61 pub fn siblings(&self) -> &[HashValue] {
63 &self.siblings
64 }
65
66 pub fn verify(
69 &self,
70 expected_root_hash: HashValue,
71 element_hash: HashValue,
72 element_index: u64,
73 ) -> Result<()> {
74 ensure!(
75 self.siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
76 "Accumulator proof has more than {} ({}) siblings.",
77 MAX_ACCUMULATOR_PROOF_DEPTH,
78 self.siblings.len()
79 );
80
81 let actual_root_hash = self
82 .siblings
83 .iter()
84 .fold(
85 (element_hash, element_index),
86 |(hash, index), sibling_hash| {
88 (
89 if index % 2 == 0 {
90 MerkleTreeInternalNode::<H>::new(hash, *sibling_hash).hash()
92 } else {
93 MerkleTreeInternalNode::<H>::new(*sibling_hash, hash).hash()
95 },
96 index / 2,
98 )
99 },
100 )
101 .0;
102 ensure!(
103 actual_root_hash == expected_root_hash,
104 "Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
105 actual_root_hash,
106 expected_root_hash
107 );
108
109 Ok(())
110 }
111}
112
113impl<H> std::fmt::Debug for AccumulatorProof<H> {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 write!(f, "AccumulatorProof {{ siblings: {:?} }}", self.siblings)
116 }
117}
118
119impl<H> PartialEq for AccumulatorProof<H> {
120 fn eq(&self, other: &Self) -> bool {
121 self.siblings == other.siblings
122 }
123}
124
125impl<H> Eq for AccumulatorProof<H> {}
126
127pub type TransactionAccumulatorProof = AccumulatorProof<TransactionAccumulatorHasher>;
128pub type EventAccumulatorProof = AccumulatorProof<EventAccumulatorHasher>;
129#[cfg(any(test, feature = "fuzzing"))]
130pub type TestAccumulatorProof = AccumulatorProof<TestOnlyHasher>;
131
132#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
135pub struct SparseMerkleProof<V> {
136 leaf: Option<SparseMerkleLeafNode>,
146
147 siblings: Vec<HashValue>,
150
151 phantom: PhantomData<V>,
152}
153
154impl<V> SparseMerkleProof<V>
155where
156 V: CryptoHash,
157{
158 pub fn new(leaf: Option<SparseMerkleLeafNode>, siblings: Vec<HashValue>) -> Self {
160 SparseMerkleProof {
161 leaf,
162 siblings,
163 phantom: PhantomData,
164 }
165 }
166
167 pub fn leaf(&self) -> Option<SparseMerkleLeafNode> {
169 self.leaf
170 }
171
172 pub fn siblings(&self) -> &[HashValue] {
174 &self.siblings
175 }
176
177 pub fn verify(
182 &self,
183 expected_root_hash: HashValue,
184 element_key: HashValue,
185 element_value: Option<&V>,
186 ) -> Result<()> {
187 ensure!(
188 self.siblings.len() <= HashValue::LENGTH_IN_BITS,
189 "Sparse Merkle Tree proof has more than {} ({}) siblings.",
190 HashValue::LENGTH_IN_BITS,
191 self.siblings.len(),
192 );
193
194 match (element_value, self.leaf) {
195 (Some(value), Some(leaf)) => {
196 ensure!(
200 element_key == leaf.key,
201 "Keys do not match. Key in proof: {:x}. Expected key: {:x}.",
202 leaf.key,
203 element_key
204 );
205 let hash = value.hash();
206 ensure!(
207 hash == leaf.value_hash,
208 "Value hashes do not match. Value hash in proof: {:x}. \
209 Expected value hash: {:x}",
210 leaf.value_hash,
211 hash,
212 );
213 }
214 (Some(_value), None) => bail!("Expected inclusion proof. Found non-inclusion proof."),
215 (None, Some(leaf)) => {
216 ensure!(
221 element_key != leaf.key,
222 "Expected non-inclusion proof, but key exists in proof.",
223 );
224 ensure!(
225 element_key.common_prefix_bits_len(leaf.key) >= self.siblings.len(),
226 "Key would not have ended up in the subtree where the provided key in proof \
227 is the only existing key, if it existed. So this is not a valid \
228 non-inclusion proof.",
229 );
230 }
231 (None, None) => {
232 }
236 }
237
238 let current_hash = self
239 .leaf
240 .map_or(*SPARSE_MERKLE_PLACEHOLDER_HASH, |leaf| leaf.hash());
241 let actual_root_hash = self
242 .siblings
243 .iter()
244 .zip(
245 element_key
246 .iter_bits()
247 .rev()
248 .skip(HashValue::LENGTH_IN_BITS - self.siblings.len()),
249 )
250 .fold(current_hash, |hash, (sibling_hash, bit)| {
251 if bit {
252 SparseMerkleInternalNode::new(*sibling_hash, hash).hash()
253 } else {
254 SparseMerkleInternalNode::new(hash, *sibling_hash).hash()
255 }
256 });
257 ensure!(
258 actual_root_hash == expected_root_hash,
259 "Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
260 actual_root_hash,
261 expected_root_hash,
262 );
263
264 Ok(())
265 }
266}
267
268#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
277pub struct TransactionAccumulatorSummary(InMemoryAccumulator<TransactionAccumulatorHasher>);
278
279impl TransactionAccumulatorSummary {
280 pub fn new(accumulator: InMemoryAccumulator<TransactionAccumulatorHasher>) -> Result<Self> {
281 ensure!(
282 !accumulator.is_empty(),
283 "empty accumulator: we can't verify consistency proofs from an empty accumulator",
284 );
285 Ok(Self(accumulator))
286 }
287
288 pub fn version(&self) -> Version {
289 self.0.version()
290 }
291
292 pub fn root_hash(&self) -> HashValue {
293 self.0.root_hash()
294 }
295
296 pub fn verify_consistency(&self, ledger_info: &LedgerInfo) -> Result<()> {
300 ensure!(
301 ledger_info.version() == self.version(),
302 "ledger info and accumulator must be at the same version: \
303 ledger info version={}, accumulator version={}",
304 ledger_info.version(),
305 self.version(),
306 );
307 ensure!(
308 ledger_info.transaction_accumulator_hash() == self.root_hash(),
309 "ledger info root hash and accumulator root hash must match: \
310 ledger info root hash={}, accumulator root hash={}",
311 ledger_info.transaction_accumulator_hash(),
312 self.root_hash(),
313 );
314 Ok(())
315 }
316
317 pub fn try_from_genesis_proof(
320 genesis_proof: AccumulatorConsistencyProof,
321 target_version: Version,
322 ) -> Result<Self> {
323 let num_txns = target_version.saturating_add(1);
324 Ok(Self(InMemoryAccumulator::new(
325 genesis_proof.into_subtrees(),
326 num_txns,
327 )?))
328 }
329
330 pub fn try_extend_with_proof(
334 &self,
335 consistency_proof: &AccumulatorConsistencyProof,
336 target_li: &LedgerInfo,
337 ) -> Result<Self> {
338 ensure!(
339 target_li.version() >= self.0.version(),
340 "target ledger info version ({}) must be newer than our current accumulator \
341 summary version ({})",
342 target_li.version(),
343 self.0.version(),
344 );
345 let num_new_txns = target_li.version() - self.0.version();
346 let new_accumulator = Self(
347 self.0
348 .append_subtrees(consistency_proof.subtrees(), num_new_txns)?,
349 );
350 new_accumulator
351 .verify_consistency(target_li)
352 .context("accumulator is not consistent with the target ledger info after applying consistency proof")?;
353 Ok(new_accumulator)
354 }
355}
356
357#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
367pub struct AccumulatorConsistencyProof {
368 subtrees: Vec<HashValue>,
370}
371
372impl AccumulatorConsistencyProof {
373 pub fn new(subtrees: Vec<HashValue>) -> Self {
375 Self { subtrees }
376 }
377
378 pub fn is_empty(&self) -> bool {
379 self.subtrees.is_empty()
380 }
381
382 pub fn subtrees(&self) -> &[HashValue] {
384 &self.subtrees
385 }
386
387 pub fn into_subtrees(self) -> Vec<HashValue> {
388 self.subtrees
389 }
390}
391
392#[derive(Clone, Deserialize, Serialize)]
411pub struct AccumulatorRangeProof<H> {
412 left_siblings: Vec<HashValue>,
415
416 right_siblings: Vec<HashValue>,
419
420 phantom: PhantomData<H>,
421}
422
423impl<H> AccumulatorRangeProof<H>
424where
425 H: CryptoHasher,
426{
427 pub fn new(left_siblings: Vec<HashValue>, right_siblings: Vec<HashValue>) -> Self {
429 Self {
430 left_siblings,
431 right_siblings,
432 phantom: PhantomData,
433 }
434 }
435
436 pub fn new_empty() -> Self {
438 Self::new(vec![], vec![])
439 }
440
441 pub fn left_siblings(&self) -> &Vec<HashValue> {
443 &self.left_siblings
444 }
445
446 pub fn right_siblings(&self) -> &Vec<HashValue> {
448 &self.right_siblings
449 }
450
451 pub fn verify(
454 &self,
455 expected_root_hash: HashValue,
456 first_leaf_index: Option<u64>,
457 leaf_hashes: &[HashValue],
458 ) -> Result<()> {
459 if first_leaf_index.is_none() {
460 ensure!(
461 leaf_hashes.is_empty(),
462 "first_leaf_index indicated empty list while leaf_hashes is not empty.",
463 );
464 ensure!(
465 self.left_siblings.is_empty() && self.right_siblings.is_empty(),
466 "No siblings are needed.",
467 );
468 return Ok(());
469 }
470
471 ensure!(
472 self.left_siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
473 "Proof has more than {} ({}) left siblings.",
474 MAX_ACCUMULATOR_PROOF_DEPTH,
475 self.left_siblings.len(),
476 );
477 ensure!(
478 self.right_siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
479 "Proof has more than {} ({}) right siblings.",
480 MAX_ACCUMULATOR_PROOF_DEPTH,
481 self.right_siblings.len(),
482 );
483 ensure!(
484 !leaf_hashes.is_empty(),
485 "leaf_hashes is empty while first_leaf_index indicated non-empty list.",
486 );
487
488 let mut left_sibling_iter = self.left_siblings.iter().peekable();
489 let mut right_sibling_iter = self.right_siblings.iter().peekable();
490
491 let mut first_pos = Position::from_leaf_index(
492 first_leaf_index.expect("first_leaf_index should not be None."),
493 );
494 let mut current_hashes = leaf_hashes.to_vec();
495 let mut parent_hashes = vec![];
496
497 while current_hashes.len() > 1
500 || left_sibling_iter.peek().is_some()
501 || right_sibling_iter.peek().is_some()
502 {
503 let mut children_iter = current_hashes.iter();
504
505 if first_pos.is_right_child() {
508 let left_hash = *left_sibling_iter.next().ok_or_else(|| {
509 format_err!("First child is a right child, but missing sibling on the left.")
510 })?;
511 let right_hash = *children_iter.next().expect("The first leaf must exist.");
512 parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
513 }
514
515 let mut children_iter = children_iter.as_slice().chunks_exact(2);
517 while let Some(chunk) = children_iter.next() {
518 let left_hash = chunk[0];
519 let right_hash = chunk[1];
520 parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
521 }
522
523 let remainder = children_iter.remainder();
526 assert!(remainder.len() <= 1);
527 if !remainder.is_empty() {
528 let left_hash = remainder[0];
529 let right_hash = *right_sibling_iter.next().ok_or_else(|| {
530 format_err!("Last child is a left child, but missing sibling on the right.")
531 })?;
532 parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
533 }
534
535 first_pos = first_pos.parent();
536 current_hashes.clear();
537 std::mem::swap(&mut current_hashes, &mut parent_hashes);
538 }
539
540 ensure!(
541 current_hashes[0] == expected_root_hash,
542 "Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
543 current_hashes[0],
544 expected_root_hash,
545 );
546
547 Ok(())
548 }
549}
550
551impl<H> std::fmt::Debug for AccumulatorRangeProof<H> {
552 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
553 write!(
554 f,
555 "AccumulatorRangeProof {{ left_siblings: {:?}, right_siblings: {:?} }}",
556 self.left_siblings, self.right_siblings,
557 )
558 }
559}
560
561impl<H> PartialEq for AccumulatorRangeProof<H> {
562 fn eq(&self, other: &Self) -> bool {
563 self.left_siblings == other.left_siblings && self.right_siblings == other.right_siblings
564 }
565}
566
567impl<H> Eq for AccumulatorRangeProof<H> {}
568
569pub type TransactionAccumulatorRangeProof = AccumulatorRangeProof<TransactionAccumulatorHasher>;
570#[cfg(any(test, feature = "fuzzing"))]
571pub type TestAccumulatorRangeProof = AccumulatorRangeProof<TestOnlyHasher>;
572
573#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
597pub struct SparseMerkleRangeProof {
598 right_siblings: Vec<HashValue>,
601}
602
603impl SparseMerkleRangeProof {
604 pub fn new(right_siblings: Vec<HashValue>) -> Self {
606 Self { right_siblings }
607 }
608
609 pub fn right_siblings(&self) -> &[HashValue] {
611 &self.right_siblings
612 }
613
614 pub fn verify(
617 &self,
618 expected_root_hash: HashValue,
619 rightmost_known_leaf: SparseMerkleLeafNode,
620 left_siblings: Vec<HashValue>,
621 ) -> Result<()> {
622 let num_siblings = left_siblings.len() + self.right_siblings.len();
623 let mut left_sibling_iter = left_siblings.iter();
624 let mut right_sibling_iter = self.right_siblings().iter();
625
626 let mut current_hash = rightmost_known_leaf.hash();
627 for bit in rightmost_known_leaf
628 .key()
629 .iter_bits()
630 .rev()
631 .skip(HashValue::LENGTH_IN_BITS - num_siblings)
632 {
633 let (left_hash, right_hash) = if bit {
634 (
635 *left_sibling_iter
636 .next()
637 .ok_or_else(|| format_err!("Missing left sibling."))?,
638 current_hash,
639 )
640 } else {
641 (
642 current_hash,
643 *right_sibling_iter
644 .next()
645 .ok_or_else(|| format_err!("Missing right sibling."))?,
646 )
647 };
648 current_hash = SparseMerkleInternalNode::new(left_hash, right_hash).hash();
649 }
650
651 ensure!(
652 current_hash == expected_root_hash,
653 "Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
654 current_hash,
655 expected_root_hash,
656 );
657
658 Ok(())
659 }
660}
661
662#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
664#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
665pub struct TransactionInfoWithProof<T> {
666 pub ledger_info_to_transaction_info_proof: TransactionAccumulatorProof,
669
670 pub transaction_info: T,
672}
673
674impl<T: TransactionInfoTrait> TransactionInfoWithProof<T> {
675 pub fn new(
678 ledger_info_to_transaction_info_proof: TransactionAccumulatorProof,
679 transaction_info: T,
680 ) -> Self {
681 Self {
682 ledger_info_to_transaction_info_proof,
683 transaction_info,
684 }
685 }
686
687 pub fn ledger_info_to_transaction_info_proof(&self) -> &TransactionAccumulatorProof {
689 &self.ledger_info_to_transaction_info_proof
690 }
691
692 pub fn transaction_info(&self) -> &T {
694 &self.transaction_info
695 }
696
697 pub fn verify(&self, ledger_info: &LedgerInfo, transaction_version: Version) -> Result<()> {
700 verify_transaction_info(
701 ledger_info,
702 transaction_version,
703 &self.transaction_info,
704 &self.ledger_info_to_transaction_info_proof,
705 )?;
706 Ok(())
707 }
708}
709
710#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
714#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
715pub struct AccountStateProof<T> {
716 transaction_info_with_proof: TransactionInfoWithProof<T>,
717
718 transaction_info_to_account_proof: SparseMerkleProof<AccountStateBlob>,
720}
721
722impl<T: TransactionInfoTrait> AccountStateProof<T> {
723 pub fn new(
726 transaction_info_with_proof: TransactionInfoWithProof<T>,
727 transaction_info_to_account_proof: SparseMerkleProof<AccountStateBlob>,
728 ) -> Self {
729 AccountStateProof {
730 transaction_info_with_proof,
731 transaction_info_to_account_proof,
732 }
733 }
734
735 pub fn transaction_info_with_proof(&self) -> &TransactionInfoWithProof<T> {
737 &self.transaction_info_with_proof
738 }
739
740 pub fn transaction_info_to_account_proof(&self) -> &SparseMerkleProof<AccountStateBlob> {
742 &self.transaction_info_to_account_proof
743 }
744
745 pub fn verify(
749 &self,
750 ledger_info: &LedgerInfo,
751 state_version: Version,
752 account_address_hash: HashValue,
753 account_state_blob: Option<&AccountStateBlob>,
754 ) -> Result<()> {
755 self.transaction_info_to_account_proof.verify(
756 self.transaction_info_with_proof
757 .transaction_info
758 .state_root_hash(),
759 account_address_hash,
760 account_state_blob,
761 )?;
762
763 self.transaction_info_with_proof
764 .verify(ledger_info, state_version)?;
765
766 Ok(())
767 }
768}
769
770#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
774#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
775pub struct EventProof<T> {
776 transaction_info_with_proof: TransactionInfoWithProof<T>,
777
778 transaction_info_to_event_proof: EventAccumulatorProof,
780}
781
782impl<T: TransactionInfoTrait> EventProof<T> {
783 pub fn new(
786 transaction_info_with_proof: TransactionInfoWithProof<T>,
787 transaction_info_to_event_proof: EventAccumulatorProof,
788 ) -> Self {
789 EventProof {
790 transaction_info_with_proof,
791 transaction_info_to_event_proof,
792 }
793 }
794
795 pub fn transaction_info_with_proof(&self) -> &TransactionInfoWithProof<T> {
797 &self.transaction_info_with_proof
798 }
799
800 pub fn verify(
802 &self,
803 ledger_info: &LedgerInfo,
804 event_hash: HashValue,
805 transaction_version: Version,
806 event_version_within_transaction: Version,
807 ) -> Result<()> {
808 self.transaction_info_to_event_proof.verify(
809 self.transaction_info_with_proof
810 .transaction_info()
811 .event_root_hash(),
812 event_hash,
813 event_version_within_transaction,
814 )?;
815
816 self.transaction_info_with_proof
817 .verify(ledger_info, transaction_version)?;
818
819 Ok(())
820 }
821}
822
823#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
825#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
826pub struct TransactionInfoListWithProof<T> {
827 pub ledger_info_to_transaction_infos_proof: TransactionAccumulatorRangeProof,
828 pub transaction_infos: Vec<T>,
829}
830
831impl<T: TransactionInfoTrait> TransactionInfoListWithProof<T> {
832 pub fn new(
833 ledger_info_to_transaction_infos_proof: TransactionAccumulatorRangeProof,
834 transaction_infos: Vec<T>,
835 ) -> Self {
836 Self {
837 ledger_info_to_transaction_infos_proof,
838 transaction_infos,
839 }
840 }
841
842 pub fn new_empty() -> Self {
844 Self::new(AccumulatorRangeProof::new_empty(), vec![])
845 }
846
847 pub fn verify(
850 &self,
851 ledger_info: &LedgerInfo,
852 first_transaction_info_version: Option<Version>,
853 ) -> Result<()> {
854 let txn_info_hashes: Vec<_> = self
855 .transaction_infos
856 .iter()
857 .map(CryptoHash::hash)
858 .collect();
859 self.ledger_info_to_transaction_infos_proof.verify(
860 ledger_info.transaction_accumulator_hash(),
861 first_transaction_info_version,
862 &txn_info_hashes,
863 )
864 }
865}
866
867#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
870pub struct AccumulatorExtensionProof<H> {
871 frozen_subtree_roots: Vec<HashValue>,
873 num_leaves: LeafCount,
875 leaves: Vec<HashValue>,
877
878 hasher: PhantomData<H>,
879}
880
881impl<H: CryptoHasher> AccumulatorExtensionProof<H> {
882 pub fn new(
883 frozen_subtree_roots: Vec<HashValue>,
884 num_leaves: LeafCount,
885 leaves: Vec<HashValue>,
886 ) -> Self {
887 Self {
888 frozen_subtree_roots,
889 num_leaves,
890 leaves,
891 hasher: PhantomData,
892 }
893 }
894
895 pub fn verify(&self, original_root: HashValue) -> anyhow::Result<InMemoryAccumulator<H>> {
896 let original_tree =
897 InMemoryAccumulator::<H>::new(self.frozen_subtree_roots.clone(), self.num_leaves)?;
898 ensure!(
899 original_tree.root_hash() == original_root,
900 "Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
901 original_tree.root_hash(),
902 original_root
903 );
904
905 Ok(original_tree.append(self.leaves.as_slice()))
906 }
907}
908
909pub mod default_protocol {
910 use crate::transaction::TransactionInfo;
911
912 pub use super::{
913 AccumulatorConsistencyProof, AccumulatorExtensionProof, AccumulatorProof,
914 AccumulatorRangeProof, EventAccumulatorProof, SparseMerkleProof, SparseMerkleRangeProof,
915 TransactionAccumulatorProof, TransactionAccumulatorRangeProof,
916 TransactionAccumulatorSummary,
917 };
918
919 pub type AccountStateProof = super::AccountStateProof<TransactionInfo>;
920 pub type EventProof = super::EventProof<TransactionInfo>;
921 pub type TransactionInfoListWithProof = super::TransactionInfoListWithProof<TransactionInfo>;
922 pub type TransactionInfoWithProof = super::TransactionInfoWithProof<TransactionInfo>;
923}