Skip to content

Commit

Permalink
Add hashing API to the MMR
Browse files Browse the repository at this point in the history
Added hashing API to the MMR by virtue of forcing the hashing type to be
`D: Digest + DomainDigest` instead of only `D: Digest` at the lower level
MMR methods and functions.
  • Loading branch information
hansieodendaal committed Aug 12, 2022
1 parent 2c76031 commit e942f8e
Show file tree
Hide file tree
Showing 24 changed files with 353 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@ use tari_common_types::types::{Commitment, RangeProofService};
use tari_comms::{connectivity::ConnectivityRequester, peer_manager::NodeId};
use tari_crypto::{
commitment::HomomorphicCommitment,
hash::blake2::Blake256,
tari_utilities::{hex::Hex, Hashable},
};
use tari_mmr::{MerkleMountainRange, MutableMmr};
use tari_mmr::{
BaseLayerKernelMmrHasherBlake256,
BaseLayerOutputMmrHasherBlake256,
BaseLayerWitnessMmrHasherBlake256,
MerkleMountainRange,
MutableMmr,
};
use tokio::task;

use super::error::HorizonSyncError;
Expand Down Expand Up @@ -326,7 +331,7 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> {
.fetch_block_accumulated_data(current_header.header().prev_hash.clone())
.await?;
let kernel_pruned_set = block_data.dissolve().0;
let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(kernel_pruned_set);
let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(kernel_pruned_set);

for hash in kernel_hashes.drain(..) {
kernel_mmr.push(hash)?;
Expand Down Expand Up @@ -487,8 +492,8 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> {
.await?;
let (_, output_pruned_set, witness_pruned_set, _) = block_data.dissolve();

let mut output_mmr = MerkleMountainRange::<Blake256, _>::new(output_pruned_set);
let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(witness_pruned_set);
let mut output_mmr = MerkleMountainRange::<BaseLayerOutputMmrHasherBlake256, _>::new(output_pruned_set);
let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(witness_pruned_set);
let mut constants = self.rules.consensus_constants(current_header.height()).clone();
let mut last_sync_timer = Instant::now();
let mut avg_latency = RollingAverageTime::new(20);
Expand Down Expand Up @@ -596,7 +601,10 @@ impl<'a, B: BlockchainBackend + 'static> HorizonStateSynchronization<'a, B> {
bitmap.run_optimize();

let pruned_output_set = output_mmr.get_pruned_hash_set()?;
let output_mmr = MutableMmr::<Blake256, _>::new(pruned_output_set.clone(), bitmap.clone())?;
let output_mmr = MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(
pruned_output_set.clone(),
bitmap.clone(),
)?;

let mmr_root = output_mmr.get_merkle_root()?;
if mmr_root != current_header.header().output_mr {
Expand Down
84 changes: 51 additions & 33 deletions base_layer/core/src/blocks/genesis_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,18 @@ pub fn get_igor_genesis_block() -> ChainBlock {
// user this code to generate the correct header mr fields for igor if the gen block changes.
// use croaring::Bitmap;
// use tari_mmr::{MerkleMountainRange, MutableMmr};
// use tari_crypto::hash::blake2::Blake256;
// use tari_mmr::{BaseLayerOutputMmrHasherBlake256, BaseLayerWitnessMmrHasherBlake256, MerkleMountainRange,
// MutableMmr};
//
// let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
// let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(Vec::new());
// for k in block.body.kernels() {
// println!("k: {}", k);
// kernel_mmr.push(k.hash()).unwrap();
// }
//
// let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
// let mut output_mmr = MutableMmr::<Blake256, _>::new(Vec::new(), Bitmap::create()).unwrap();
// let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(Vec::new());
// let mut output_mmr = MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(Vec::new(),
// Bitmap::create()).unwrap();
//
// for o in block.body.outputs() {
// witness_mmr.push(o.witness_hash()).unwrap();
Expand All @@ -111,14 +113,16 @@ pub fn get_igor_genesis_block() -> ChainBlock {
}

fn get_igor_genesis_block_raw() -> Block {
// Note: Use print_new_genesis_block_igor in core/tests/helpers/block_builders.rs to generate the required fields
// below
let sig = Signature::new(
PublicKey::from_hex("b4d81516b2cd8402a56639fe68ce0a9d9e73912573d659f98ad59268e93d6662").unwrap(),
PrivateKey::from_hex("ac4b4e9e3934c0c83457ef73e885e4db7bf76e8af2599ae56601fb33b2535f01").unwrap(),
PublicKey::from_hex("90e9cd591ed69e325fbdf0b36fd4aeab8b1917542ff94c32b0e38896827d1943").unwrap(),
PrivateKey::from_hex("cbf10a5453e09990ecb22a55935acf2d6ad10237dde94fca56495ae2fead110b").unwrap(),
);
let coinbase_meta_sig = CommitmentSignature::new(
Commitment::from_hex("fcbdc5e0323f53e866e6e2a1b67950befb8178d418d48840a7447e3dfed3b15f").unwrap(),
PrivateKey::from_hex("049449f8e8c5383fc5a0ef11292d0fa60258799bd504f060943e45c9c0741b0b").unwrap(),
PrivateKey::from_hex("50f09f1fa93e2dfab8a3826c00aa73af904e20a5d4e4a55cb26cce2f508b2306").unwrap(),
Commitment::from_hex("1abc2df9fe3c6a3e68ef0e7219dd3dd617646e67857c39f4fcef7ee044191272").unwrap(),
PrivateKey::from_hex("fdbef6a0e7560d555c0c5cef216cae1549dbb43c9e0747ec42551f5efb318105").unwrap(),
PrivateKey::from_hex("1d317a93fd9aaad4ba172b0be0e7b2676287e68fb47cd0b8e6613506253be601").unwrap(),
);
let mut body = AggregateBody::new(
vec![],
Expand All @@ -129,14 +133,14 @@ fn get_igor_genesis_block_raw() -> Block {
.. Default::default()
},
Commitment::from_hex(
"9e43749e3c3c2d4c64b5af6aa5b465f0be595b432089656fb4c60281e0c37372",
"1805b11acc21796deeccecde810583fcf2d850bea46bce6beab6a76459eeeb26",
)
.unwrap(),
BulletRangeProof::from_hex("015eaff14d2c754884db429c2c5aab3328c65afd4a6947ae7861617f774f96ab01a4c0cf5e4ae46dc9b3c11ae3f01d755d589240f206747305c607aedbb31a3b51e8b009a1639e54db0cd3ab98ece1e0f363c1b823d4141bac15c1525234ab6d5dcc77e7447a7617e550a54168ff5347047f84de7a64140b63a6e695e86138aa7d46fd56aa774102214610665fc18b26ddb17f16ea262ceb573711b276eabdf33586551dd16e4265df736610a1239f986a73404a58cf6f83fa9acb5fa3225d87609a6fb7a4cff9c33e2ca93edbb51434c74685f950edb58bfe0dc29f3827588a6c14128763e8085decc4982c6ae5d3f944e52588b6a501b1289a4ef4d30883854360b93412d25f323627139d591bdbb91a5b175322a379ea2cdbbfb81f9e0af56352fcbb9082fd8e7616a810a83f8d26f3a4f6b4568aabd88b57bc8747c833921f0cc8431a991922aa5b69ad2a5c58a10eee09668e85784c58c0150d0f4022473056870677acedd1fe336f1c8bafe888ec8a7293f6e689a6854ebbc6e99b76fa21ca5b19a4bdca5982f266dae0c573facf5a01e0a55000b9b789eae8f5551ad3536eccc3064617e6f2b4b2641eb033753e17fb2a65390952b5c2923c5596e1e16ee24aba2013b9437032f8c90bf57ecc88bf72c249dc6570e742f9616ca4e21e3ca507085b62f8d532c4add40bcef53a1558fae7e89e9cd360bfcacc5603244508ebb223a54256d20ba52b91e6d82fe130e24d079bc9b116afa4664c0925d38c0ca064ccf210f02e60d85809d076d323a6ea9a6b3970a0d1192ed72622c5f6c600").unwrap(),
BulletRangeProof::from_hex("01369dfde898b40805d6a8964f3f8aff6d1bb17beaf71da91793fe097c0ee8b03930abd4672a4a90dd3610110d6e152c5105de7fdc50c582f810dc2be235dee61dfce10d7b487004f5023956fc346569be554c8d2a43c71f7d5fc83c2019aac07ae8f432cd6f18e98c2ce49908e4212e4f91b99c71bb87e4efe845096c87497c15189394092ce32b6a2f06765cc2124c6a07adc28f629cb26905c0da0d70ab112a301018acda9bdee5165662bb8afe3b43a4d373110086366bc18fd90683a4336b5a01008e174c134ceea61c04fe14cd16bce83bd36219410a5367e95a32460d42a89205c892870300a237652ed1d9d4c824c1eefc3f1da648bc22db11efc75b5e7cd8b709e1f89d53e81ff1267b896a74fb7f3870bbb413f5fdbfc34b66652b2fbcce1794db2416489b1b57ccbb034c4b88772368d8d9397726d9e52d40b2736a221ae6348790b58320df517cbd603f1f27ccf11980af0689ed529cad70631171823574480731971e546240e00f5358ac5bae24588a873e7649c97be62381b965c01f1372cd1eeff2048a5e0363c0ecf227ffbf1591b51f8f1a963b0db2266b00229ec70db46ed31812f13a0d1c432b71b8e7d0cdd9f293590b4bdb7ebe93e90fde0173afce419de1ff4af3cef277130e271c4a4417fff0d5d60e5483ccc7e236b1347e47063037252ae063f12ce903bc7947aedfcd70aa85a7ef628f31d9fe076508dba9f8b2091876b2f5795f68bbdd267ceb5d6b4ddfe3bf225b54fedd79001acda500080212469bd0e99c4721fda2363b16915c97c5bf8b1f8d4de8be760d").unwrap(),
// For genesis block: A default script can never be spent, intentionally
script!(Nop),
// Script offset never checked for coinbase, thus can use default
PublicKey::from_hex("383977b6d4e6f1a572c65e50cafcbef2f86ce5b422447347661a040b0ed8f534").unwrap(),
PublicKey::from_hex("3ec3bc4ab31d3266bec5e7ed977bb766ab9b1d8951547ae7f653dc6109334e38").unwrap(),
// For genesis block: Metadata signature will never be checked
coinbase_meta_sig,
Covenant::default(),
Expand All @@ -149,7 +153,7 @@ fn get_igor_genesis_block_raw() -> Block {
MicroTari(0),
0,
Commitment::from_hex(
"886df7670975f532d880c92dfc13ed9c69a91e926382cfb128aa8590a88a4a24",
"660d5125fee9784c7c4d7ae5c533591418bf081a3ff21097f0bf9157af5aa91a",
)
.unwrap(),
sig,None
Expand All @@ -167,10 +171,10 @@ fn get_igor_genesis_block_raw() -> Block {
height: 0,
prev_hash: vec![0; BLOCK_HASH_LENGTH],
timestamp: timestamp.into(),
output_mr: from_hex("5cc6ab2569eea3b659ec1d7e6cc26d38ad906a6487eab95b70df37058e1121a4").unwrap(),
witness_mr: from_hex("76cac93115260256e50fe49c75e66d5fb007f57aa3af64f05e395e3fb17ef05e").unwrap(),
output_mr: from_hex("331daafb9d16ab1b11a20dabb2ece9e609dfdef752793562173ed238d4e52d7f").unwrap(),
witness_mr: from_hex("33af10f6bd6e0cc06e1f2def2e0f61371a9ff62ef0cdee47ed76caa6ce3778dc").unwrap(),
output_mmr_size: 1,
kernel_mr: from_hex("ac0346f6f2fb0031269d59f88d90eb9c143d89d8dff424eba05a3e34757c2f9d").unwrap(),
kernel_mr: from_hex("1830a7f405c7d50c386322e30d0de71d075ac11ec590c77e2826b7e65f0ed935").unwrap(),
kernel_mmr_size: 1,
input_mr: vec![0; BLOCK_HASH_LENGTH],
total_kernel_offset: PrivateKey::from_hex(
Expand Down Expand Up @@ -216,17 +220,23 @@ pub fn get_esmeralda_genesis_block() -> ChainBlock {
// NB: `esmerlada_genesis_sanity_check` must pass

// use croaring::Bitmap;
// use tari_crypto::hash::blake2::Blake256;
// use tari_mmr::{MerkleMountainRange, MutableMmr};
// use tari_mmr::{
// BaseLayerKernelMmrHasherBlake256,
// BaseLayerOutputMmrHasherBlake256,
// BaseLayerWitnessMmrHasherBlake256,
// MerkleMountainRange,
// MutableMmr,
// };
//
// let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
// let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(Vec::new());
// for k in block.body.kernels() {
// println!("k: {}", k);
// kernel_mmr.push(k.hash()).unwrap();
// }
//
// let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
// let mut output_mmr = MutableMmr::<Blake256, _>::new(Vec::new(), Bitmap::create()).unwrap();
// let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(Vec::new());
// let mut output_mmr = MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(Vec::new(),
// Bitmap::create()).unwrap();
//
// for o in block.body.outputs() {
// witness_mmr.push(o.witness_hash()).unwrap();
Expand All @@ -241,9 +251,9 @@ pub fn get_esmeralda_genesis_block() -> ChainBlock {
// println!("output mr: {}", block.header.output_mr.to_hex());

// Hardcode the Merkle roots once they've been computed above
block.header.kernel_mr = from_hex("7335c07777472b7e0cbd0cc19889581aa0230fac6de28a8705809e6e0560ed63").unwrap();
block.header.witness_mr = from_hex("81ef01da185ea7f6865b7043e4a9130d58182a46bc34059bba048c8a9313d731").unwrap();
block.header.output_mr = from_hex("822a833a1bb1fbfe179682be0e121f31453eef499db7ab03ace78bd50658140a").unwrap();
block.header.kernel_mr = from_hex("a3ebc99443f546cadea6146ec12a841fc3d51d2c322029273d6bb44d9879d81a").unwrap();
block.header.witness_mr = from_hex("2ccdd0aeb1ff7b41ce0a6f1f3123a71138d705e9abf36b684271decca8e20855").unwrap();
block.header.output_mr = from_hex("b15724ad00693d13e574909af476fd980ea0ba183462b2389442043d785a3f0d").unwrap();

let accumulated_data = BlockHeaderAccumulatedData {
hash: block.hash(),
Expand All @@ -258,7 +268,8 @@ pub fn get_esmeralda_genesis_block() -> ChainBlock {
}

fn get_esmeralda_genesis_block_raw() -> Block {
// Note: Use print_new_genesis_block in core/tests/helpers/block_builders.rs to generate the required fields below
// Note: Use print_new_genesis_block_esme in core/tests/helpers/block_builders.rs to generate the required fields
// below
let excess_sig = Signature::new(
PublicKey::from_hex("b4e82e14ab54f7fe025a832160ae589fbd2ccd8daa66d04e0e3c058b23c5d339").unwrap(),
PrivateKey::from_hex("c40cd89e2433f8ace92f544d291a8cc65686c2512cc6e1d01f68cf8856f3630e").unwrap(),
Expand Down Expand Up @@ -347,8 +358,13 @@ mod test {

use croaring::Bitmap;
use tari_common_types::types::Commitment;
use tari_crypto::hash::blake2::Blake256;
use tari_mmr::{MerkleMountainRange, MutableMmr};
use tari_mmr::{
BaseLayerKernelMmrHasherBlake256,
BaseLayerOutputMmrHasherBlake256,
BaseLayerWitnessMmrHasherBlake256,
MerkleMountainRange,
MutableMmr,
};

use super::*;
use crate::{
Expand Down Expand Up @@ -390,13 +406,14 @@ mod test {
.any(|k| k.features.contains(KernelFeatures::COINBASE_KERNEL)));

// Check MMR
let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(Vec::new());
for k in block.block().body.kernels() {
kernel_mmr.push(k.hash()).unwrap();
}

let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
let mut output_mmr = MutableMmr::<Blake256, _>::new(Vec::new(), Bitmap::create()).unwrap();
let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(Vec::new());
let mut output_mmr =
MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(Vec::new(), Bitmap::create()).unwrap();

for o in block.block().body.outputs() {
o.verify_metadata_signature().unwrap();
Expand Down Expand Up @@ -456,13 +473,14 @@ mod test {
.any(|k| k.features.contains(KernelFeatures::COINBASE_KERNEL)));

// Check MMR
let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(Vec::new());
for k in block.block().body.kernels() {
kernel_mmr.push(k.hash()).unwrap();
}

let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(Vec::new());
let mut output_mmr = MutableMmr::<Blake256, _>::new(Vec::new(), Bitmap::create()).unwrap();
let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(Vec::new());
let mut output_mmr =
MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(Vec::new(), Bitmap::create()).unwrap();
assert_eq!(block.block().body.kernels().len(), 1);
assert_eq!(block.block().body.outputs().len(), 1);
for o in block.block().body.outputs() {
Expand Down
19 changes: 13 additions & 6 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,15 @@ use tari_common_types::{
chain_metadata::ChainMetadata,
types::{BlockHash, Commitment, FixedHash, HashOutput, PublicKey, Signature},
};
use tari_crypto::hash::blake2::Blake256;
use tari_mmr::{pruned_hashset::PrunedHashSet, MerkleMountainRange, MutableMmr};
use tari_mmr::{
pruned_hashset::PrunedHashSet,
BaseLayerInputMmrHasherBlake256,
BaseLayerKernelMmrHasherBlake256,
BaseLayerOutputMmrHasherBlake256,
BaseLayerWitnessMmrHasherBlake256,
MerkleMountainRange,
MutableMmr,
};
use tari_utilities::{epoch_time::EpochTime, hex::Hex, ByteArray, Hashable};

use crate::{
Expand Down Expand Up @@ -1252,10 +1259,10 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
value: header.prev_hash.to_hex(),
})?;

let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(kernels);
let mut output_mmr = MutableMmr::<Blake256, _>::new(outputs, deleted)?;
let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(range_proofs);
let mut input_mmr = MerkleMountainRange::<Blake256, _>::new(PrunedHashSet::default());
let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(kernels);
let mut output_mmr = MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(outputs, deleted)?;
let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(range_proofs);
let mut input_mmr = MerkleMountainRange::<BaseLayerInputMmrHasherBlake256, _>::new(PrunedHashSet::default());
let mut deleted_outputs = Vec::new();

for kernel in body.kernels().iter() {
Expand Down
16 changes: 12 additions & 4 deletions base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ use tari_common_types::{
types::{BlockHash, Commitment, FixedHash, HashOutput, PublicKey, Signature, BLOCK_HASH_LENGTH},
};
use tari_crypto::hash::blake2::Blake256;
use tari_mmr::{Hash, MerkleMountainRange, MutableMmr};
use tari_mmr::{
BaseLayerKernelMmrHasherBlake256,
BaseLayerOutputMmrHasherBlake256,
BaseLayerWitnessMmrHasherBlake256,
Hash,
MerkleMountainRange,
MutableMmr,
};
use tari_storage::lmdb_store::{db, LMDBBuilder, LMDBConfig, LMDBStore};
use tari_utilities::{
hash::Hashable,
Expand Down Expand Up @@ -1282,7 +1289,7 @@ impl LMDBDatabase {
..
} = data;

let mut kernel_mmr = MerkleMountainRange::<Blake256, _>::new(pruned_kernel_set);
let mut kernel_mmr = MerkleMountainRange::<BaseLayerKernelMmrHasherBlake256, _>::new(pruned_kernel_set);

for kernel in kernels {
total_kernel_sum = &total_kernel_sum + &kernel.excess;
Expand All @@ -1297,8 +1304,9 @@ impl LMDBDatabase {
})?;
self.insert_kernel(txn, &block_hash, &kernel, pos)?;
}
let mut output_mmr = MutableMmr::<Blake256, _>::new(pruned_output_set, Bitmap::create())?;
let mut witness_mmr = MerkleMountainRange::<Blake256, _>::new(pruned_proof_set);
let mut output_mmr =
MutableMmr::<BaseLayerOutputMmrHasherBlake256, _>::new(pruned_output_set, Bitmap::create())?;
let mut witness_mmr = MerkleMountainRange::<BaseLayerWitnessMmrHasherBlake256, _>::new(pruned_proof_set);

let leaf_count = witness_mmr.get_leaf_count()?;

Expand Down
1 change: 1 addition & 0 deletions base_layer/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,5 @@ pub mod large_ints {
pub struct U512(8);
}
}

pub use large_ints::{U256, U512};
Loading

0 comments on commit e942f8e

Please sign in to comment.