use super::{
accumulator::InMemoryAccumulator, position::Position, verify_transaction_info,
MerkleTreeInternalNode, SparseMerkleInternalNode, SparseMerkleLeafNode,
};
use crate::{
account_state_blob::AccountStateBlob,
ledger_info::LedgerInfo,
transaction::{TransactionInfo, Version},
};
use anyhow::{bail, ensure, format_err, Result};
#[cfg(any(test, feature = "fuzzing"))]
use diem_crypto::hash::TestOnlyHasher;
use diem_crypto::{
hash::{
CryptoHash, CryptoHasher, EventAccumulatorHasher, TransactionAccumulatorHasher,
SPARSE_MERKLE_PLACEHOLDER_HASH,
},
HashValue,
};
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
#[derive(Clone, Serialize, Deserialize)]
pub struct AccumulatorProof<H> {
siblings: Vec<HashValue>,
phantom: PhantomData<H>,
}
pub type LeafCount = u64;
pub const MAX_ACCUMULATOR_PROOF_DEPTH: usize = 63;
pub const MAX_ACCUMULATOR_LEAVES: LeafCount = 1 << MAX_ACCUMULATOR_PROOF_DEPTH;
impl<H> AccumulatorProof<H>
where
H: CryptoHasher,
{
pub fn new(siblings: Vec<HashValue>) -> Self {
AccumulatorProof {
siblings,
phantom: PhantomData,
}
}
pub fn siblings(&self) -> &[HashValue] {
&self.siblings
}
pub fn verify(
&self,
expected_root_hash: HashValue,
element_hash: HashValue,
element_index: u64,
) -> Result<()> {
ensure!(
self.siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
"Accumulator proof has more than {} ({}) siblings.",
MAX_ACCUMULATOR_PROOF_DEPTH,
self.siblings.len()
);
let actual_root_hash = self
.siblings
.iter()
.fold(
(element_hash, element_index),
|(hash, index), sibling_hash| {
(
if index % 2 == 0 {
MerkleTreeInternalNode::<H>::new(hash, *sibling_hash).hash()
} else {
MerkleTreeInternalNode::<H>::new(*sibling_hash, hash).hash()
},
index / 2,
)
},
)
.0;
ensure!(
actual_root_hash == expected_root_hash,
"Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
actual_root_hash,
expected_root_hash
);
Ok(())
}
}
impl<H> std::fmt::Debug for AccumulatorProof<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "AccumulatorProof {{ siblings: {:?} }}", self.siblings)
}
}
impl<H> PartialEq for AccumulatorProof<H> {
fn eq(&self, other: &Self) -> bool {
self.siblings == other.siblings
}
}
impl<H> Eq for AccumulatorProof<H> {}
pub type TransactionAccumulatorProof = AccumulatorProof<TransactionAccumulatorHasher>;
pub type EventAccumulatorProof = AccumulatorProof<EventAccumulatorHasher>;
#[cfg(any(test, feature = "fuzzing"))]
pub type TestAccumulatorProof = AccumulatorProof<TestOnlyHasher>;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SparseMerkleProof<V> {
leaf: Option<SparseMerkleLeafNode>,
siblings: Vec<HashValue>,
phantom: PhantomData<V>,
}
impl<V> SparseMerkleProof<V>
where
V: CryptoHash,
{
pub fn new(leaf: Option<SparseMerkleLeafNode>, siblings: Vec<HashValue>) -> Self {
SparseMerkleProof {
leaf,
siblings,
phantom: PhantomData,
}
}
pub fn leaf(&self) -> Option<SparseMerkleLeafNode> {
self.leaf
}
pub fn siblings(&self) -> &[HashValue] {
&self.siblings
}
pub fn verify(
&self,
expected_root_hash: HashValue,
element_key: HashValue,
element_value: Option<&V>,
) -> Result<()> {
ensure!(
self.siblings.len() <= HashValue::LENGTH_IN_BITS,
"Sparse Merkle Tree proof has more than {} ({}) siblings.",
HashValue::LENGTH_IN_BITS,
self.siblings.len(),
);
match (element_value, self.leaf) {
(Some(value), Some(leaf)) => {
ensure!(
element_key == leaf.key,
"Keys do not match. Key in proof: {:x}. Expected key: {:x}.",
leaf.key,
element_key
);
let hash = value.hash();
ensure!(
hash == leaf.value_hash,
"Value hashes do not match. Value hash in proof: {:x}. \
Expected value hash: {:x}",
leaf.value_hash,
hash,
);
}
(Some(_value), None) => bail!("Expected inclusion proof. Found non-inclusion proof."),
(None, Some(leaf)) => {
ensure!(
element_key != leaf.key,
"Expected non-inclusion proof, but key exists in proof.",
);
ensure!(
element_key.common_prefix_bits_len(leaf.key) >= self.siblings.len(),
"Key would not have ended up in the subtree where the provided key in proof \
is the only existing key, if it existed. So this is not a valid \
non-inclusion proof.",
);
}
(None, None) => {
}
}
let current_hash = self
.leaf
.map_or(*SPARSE_MERKLE_PLACEHOLDER_HASH, |leaf| leaf.hash());
let actual_root_hash = self
.siblings
.iter()
.zip(
element_key
.iter_bits()
.rev()
.skip(HashValue::LENGTH_IN_BITS - self.siblings.len()),
)
.fold(current_hash, |hash, (sibling_hash, bit)| {
if bit {
SparseMerkleInternalNode::new(*sibling_hash, hash).hash()
} else {
SparseMerkleInternalNode::new(hash, *sibling_hash).hash()
}
});
ensure!(
actual_root_hash == expected_root_hash,
"Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
actual_root_hash,
expected_root_hash,
);
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct AccumulatorConsistencyProof {
subtrees: Vec<HashValue>,
}
impl AccumulatorConsistencyProof {
pub fn new(subtrees: Vec<HashValue>) -> Self {
Self { subtrees }
}
pub fn subtrees(&self) -> &[HashValue] {
&self.subtrees
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct AccumulatorRangeProof<H> {
left_siblings: Vec<HashValue>,
right_siblings: Vec<HashValue>,
phantom: PhantomData<H>,
}
impl<H> AccumulatorRangeProof<H>
where
H: CryptoHasher,
{
pub fn new(left_siblings: Vec<HashValue>, right_siblings: Vec<HashValue>) -> Self {
Self {
left_siblings,
right_siblings,
phantom: PhantomData,
}
}
pub fn new_empty() -> Self {
Self::new(vec![], vec![])
}
pub fn left_siblings(&self) -> &Vec<HashValue> {
&self.left_siblings
}
pub fn right_siblings(&self) -> &Vec<HashValue> {
&self.right_siblings
}
pub fn verify(
&self,
expected_root_hash: HashValue,
first_leaf_index: Option<u64>,
leaf_hashes: &[HashValue],
) -> Result<()> {
if first_leaf_index.is_none() {
ensure!(
leaf_hashes.is_empty(),
"first_leaf_index indicated empty list while leaf_hashes is not empty.",
);
ensure!(
self.left_siblings.is_empty() && self.right_siblings.is_empty(),
"No siblings are needed.",
);
return Ok(());
}
ensure!(
self.left_siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
"Proof has more than {} ({}) left siblings.",
MAX_ACCUMULATOR_PROOF_DEPTH,
self.left_siblings.len(),
);
ensure!(
self.right_siblings.len() <= MAX_ACCUMULATOR_PROOF_DEPTH,
"Proof has more than {} ({}) right siblings.",
MAX_ACCUMULATOR_PROOF_DEPTH,
self.right_siblings.len(),
);
ensure!(
!leaf_hashes.is_empty(),
"leaf_hashes is empty while first_leaf_index indicated non-empty list.",
);
let mut left_sibling_iter = self.left_siblings.iter().peekable();
let mut right_sibling_iter = self.right_siblings.iter().peekable();
let mut first_pos = Position::from_leaf_index(
first_leaf_index.expect("first_leaf_index should not be None."),
);
let mut current_hashes = leaf_hashes.to_vec();
let mut parent_hashes = vec![];
while current_hashes.len() > 1
|| left_sibling_iter.peek().is_some()
|| right_sibling_iter.peek().is_some()
{
let mut children_iter = current_hashes.iter();
if first_pos.is_right_child() {
let left_hash = *left_sibling_iter.next().ok_or_else(|| {
format_err!("First child is a right child, but missing sibling on the left.")
})?;
let right_hash = *children_iter.next().expect("The first leaf must exist.");
parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
}
let mut children_iter = children_iter.as_slice().chunks_exact(2);
while let Some(chunk) = children_iter.next() {
let left_hash = chunk[0];
let right_hash = chunk[1];
parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
}
let remainder = children_iter.remainder();
assert!(remainder.len() <= 1);
if !remainder.is_empty() {
let left_hash = remainder[0];
let right_hash = *right_sibling_iter.next().ok_or_else(|| {
format_err!("Last child is a left child, but missing sibling on the right.")
})?;
parent_hashes.push(MerkleTreeInternalNode::<H>::new(left_hash, right_hash).hash());
}
first_pos = first_pos.parent();
current_hashes.clear();
std::mem::swap(&mut current_hashes, &mut parent_hashes);
}
ensure!(
current_hashes[0] == expected_root_hash,
"Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
current_hashes[0],
expected_root_hash,
);
Ok(())
}
}
impl<H> std::fmt::Debug for AccumulatorRangeProof<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"AccumulatorRangeProof {{ left_siblings: {:?}, right_siblings: {:?} }}",
self.left_siblings, self.right_siblings,
)
}
}
impl<H> PartialEq for AccumulatorRangeProof<H> {
fn eq(&self, other: &Self) -> bool {
self.left_siblings == other.left_siblings && self.right_siblings == other.right_siblings
}
}
impl<H> Eq for AccumulatorRangeProof<H> {}
pub type TransactionAccumulatorRangeProof = AccumulatorRangeProof<TransactionAccumulatorHasher>;
#[cfg(any(test, feature = "fuzzing"))]
pub type TestAccumulatorRangeProof = AccumulatorRangeProof<TestOnlyHasher>;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SparseMerkleRangeProof {
right_siblings: Vec<HashValue>,
}
impl SparseMerkleRangeProof {
pub fn new(right_siblings: Vec<HashValue>) -> Self {
Self { right_siblings }
}
pub fn right_siblings(&self) -> &[HashValue] {
&self.right_siblings
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct TransactionInfoWithProof {
ledger_info_to_transaction_info_proof: TransactionAccumulatorProof,
transaction_info: TransactionInfo,
}
impl TransactionInfoWithProof {
pub fn new(
ledger_info_to_transaction_info_proof: TransactionAccumulatorProof,
transaction_info: TransactionInfo,
) -> Self {
Self {
ledger_info_to_transaction_info_proof,
transaction_info,
}
}
pub fn ledger_info_to_transaction_info_proof(&self) -> &TransactionAccumulatorProof {
&self.ledger_info_to_transaction_info_proof
}
pub fn transaction_info(&self) -> &TransactionInfo {
&self.transaction_info
}
pub fn verify(&self, ledger_info: &LedgerInfo, transaction_version: Version) -> Result<()> {
verify_transaction_info(
ledger_info,
transaction_version,
&self.transaction_info,
&self.ledger_info_to_transaction_info_proof,
)?;
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccountStateProof {
transaction_info_with_proof: TransactionInfoWithProof,
transaction_info_to_account_proof: SparseMerkleProof<AccountStateBlob>,
}
impl AccountStateProof {
pub fn new(
transaction_info_with_proof: TransactionInfoWithProof,
transaction_info_to_account_proof: SparseMerkleProof<AccountStateBlob>,
) -> Self {
AccountStateProof {
transaction_info_with_proof,
transaction_info_to_account_proof,
}
}
pub fn transaction_info_with_proof(&self) -> &TransactionInfoWithProof {
&self.transaction_info_with_proof
}
pub fn transaction_info_to_account_proof(&self) -> &SparseMerkleProof<AccountStateBlob> {
&self.transaction_info_to_account_proof
}
pub fn verify(
&self,
ledger_info: &LedgerInfo,
state_version: Version,
account_address_hash: HashValue,
account_state_blob: Option<&AccountStateBlob>,
) -> Result<()> {
self.transaction_info_to_account_proof.verify(
self.transaction_info_with_proof
.transaction_info
.state_root_hash(),
account_address_hash,
account_state_blob,
)?;
self.transaction_info_with_proof
.verify(ledger_info, state_version)?;
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct EventProof {
transaction_info_with_proof: TransactionInfoWithProof,
transaction_info_to_event_proof: EventAccumulatorProof,
}
impl EventProof {
pub fn new(
transaction_info_with_proof: TransactionInfoWithProof,
transaction_info_to_event_proof: EventAccumulatorProof,
) -> Self {
EventProof {
transaction_info_with_proof,
transaction_info_to_event_proof,
}
}
pub fn transaction_info_with_proof(&self) -> &TransactionInfoWithProof {
&self.transaction_info_with_proof
}
pub fn verify(
&self,
ledger_info: &LedgerInfo,
event_hash: HashValue,
transaction_version: Version,
event_version_within_transaction: Version,
) -> Result<()> {
self.transaction_info_to_event_proof.verify(
self.transaction_info_with_proof
.transaction_info()
.event_root_hash(),
event_hash,
event_version_within_transaction,
)?;
self.transaction_info_with_proof
.verify(ledger_info, transaction_version)?;
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct TransactionListProof {
ledger_info_to_transaction_infos_proof: TransactionAccumulatorRangeProof,
transaction_infos: Vec<TransactionInfo>,
}
impl TransactionListProof {
pub fn new(
ledger_info_to_transaction_infos_proof: TransactionAccumulatorRangeProof,
transaction_infos: Vec<TransactionInfo>,
) -> Self {
Self {
ledger_info_to_transaction_infos_proof,
transaction_infos,
}
}
pub fn new_empty() -> Self {
Self::new(AccumulatorRangeProof::new_empty(), vec![])
}
pub fn transaction_infos(&self) -> &[TransactionInfo] {
&self.transaction_infos
}
pub fn left_siblings(&self) -> &Vec<HashValue> {
self.ledger_info_to_transaction_infos_proof.left_siblings()
}
pub fn unpack(self) -> (TransactionAccumulatorRangeProof, Vec<TransactionInfo>) {
(
self.ledger_info_to_transaction_infos_proof,
self.transaction_infos,
)
}
pub fn verify(
&self,
ledger_info: &LedgerInfo,
first_transaction_version: Option<Version>,
transaction_hashes: &[HashValue],
) -> Result<()> {
ensure!(
self.transaction_infos.len() == transaction_hashes.len(),
"The number of TransactionInfo objects ({}) does not match the number of \
transactions ({}).",
self.transaction_infos.len(),
transaction_hashes.len(),
);
itertools::zip_eq(transaction_hashes, &self.transaction_infos)
.map(|(txn_hash, txn_info)| {
ensure!(
*txn_hash == txn_info.transaction_hash(),
"The hash of transaction does not match the transaction info in proof. \
Transaction hash: {:x}. Transaction hash in txn_info: {:x}.",
txn_hash,
txn_info.transaction_hash(),
);
Ok(())
})
.collect::<Result<Vec<_>>>()?;
let txn_info_hashes: Vec<_> = self
.transaction_infos
.iter()
.map(CryptoHash::hash)
.collect();
self.ledger_info_to_transaction_infos_proof.verify(
ledger_info.transaction_accumulator_hash(),
first_transaction_version,
&txn_info_hashes,
)?;
Ok(())
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct AccumulatorExtensionProof<H> {
frozen_subtree_roots: Vec<HashValue>,
num_leaves: LeafCount,
leaves: Vec<HashValue>,
hasher: PhantomData<H>,
}
impl<H: CryptoHasher> AccumulatorExtensionProof<H> {
pub fn new(
frozen_subtree_roots: Vec<HashValue>,
num_leaves: LeafCount,
leaves: Vec<HashValue>,
) -> Self {
Self {
frozen_subtree_roots,
num_leaves,
leaves,
hasher: PhantomData,
}
}
pub fn verify(&self, original_root: HashValue) -> anyhow::Result<InMemoryAccumulator<H>> {
let original_tree =
InMemoryAccumulator::<H>::new(self.frozen_subtree_roots.clone(), self.num_leaves)?;
ensure!(
original_tree.root_hash() == original_root,
"Root hashes do not match. Actual root hash: {:x}. Expected root hash: {:x}.",
original_tree.root_hash(),
original_root
);
Ok(original_tree.append(self.leaves.as_slice()))
}
}