Skip to content

Commit

Permalink
fix!: burned commitment mmr calculation and cucumber prune mode (#4453)
Browse files Browse the repository at this point in the history
mmr header calculation for burned outputs
Fix cucumber prune mode

Description
---
Fixes the MMR root calculation for burned commitments. They were calculated correctly in the database and prune mode sync, but not during header sync calculation. 
Fixes pruned mode cucumber tests. Consensus values between local net and Esmeralda were not matching. 
Reduces local net header version back to 0 to match Esmeralda version. 

How Has This Been Tested?
---
Unit and cucumber tests


fixes: #4360
fixes: #4443
  • Loading branch information
SWvheerden committed Aug 11, 2022
1 parent 52bc2be commit 0c062f3
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 15 deletions.
23 changes: 17 additions & 6 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1237,9 +1237,7 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
metadata.best_block().to_hex()
)));
}

let deleted = db.fetch_deleted_bitmap()?;
let deleted = deleted.into_bitmap();
let deleted = db.fetch_deleted_bitmap()?.into_bitmap();

let BlockAccumulatedData {
kernels,
Expand All @@ -1258,14 +1256,26 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
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 deleted_outputs = Vec::new();

for kernel in body.kernels().iter() {
kernel_mmr.push(kernel.hash())?;
}

for output in body.outputs().iter() {
output_mmr.push(output.hash())?;
let output_hash = output.hash();
output_mmr.push(output_hash.clone())?;
witness_mmr.push(output.witness_hash())?;
if output.is_burned() {
let index = output_mmr
.find_leaf_index(&output_hash)?
.ok_or_else(|| ChainStorageError::ValueNotFound {
entity: "UTXO",
field: "hash",
value: output_hash.to_hex(),
})?;
deleted_outputs.push((index, output_hash));
}
}

for input in body.inputs().iter() {
Expand Down Expand Up @@ -1294,7 +1304,9 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
index
},
};

deleted_outputs.push((index, output_hash));
}
for (index, output_hash) in deleted_outputs {
if !output_mmr.delete(index) {
let num_leaves = u32::try_from(output_mmr.get_leaf_count())
.map_err(|_| ChainStorageError::CriticalError("UTXO MMR leaf count overflows u32".to_string()))?;
Expand All @@ -1304,7 +1316,6 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
output_hash.to_hex()
)));
}

return Err(ChainStorageError::InvalidOperation(format!(
"Could not delete index {} from the output MMR ({} leaves)",
index, num_leaves
Expand Down
12 changes: 6 additions & 6 deletions base_layer/core/src/consensus/consensus_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,18 +296,18 @@ impl ConsensusConstants {
vec![ConsensusConstants {
effective_from_height: 0,
coinbase_lock_height: 2,
blockchain_version: 2,
valid_blockchain_version_range: 0..=3,
blockchain_version: 0,
valid_blockchain_version_range: 0..=0,
future_time_limit: 540,
difficulty_block_window,
max_block_transaction_weight: 19500,
median_timestamp_count: 11,
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
emission_initial: 18_462_816_327 * uT,
emission_decay: &ESMERALDA_DECAY_PARAMS,
emission_tail: 800 * T,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
faucet_value: (10 * 4000) * T,
transaction_weight: TransactionWeight::latest(),
max_script_byte_size: 2048,
input_version_range,
Expand Down
23 changes: 20 additions & 3 deletions integration_tests/features/Sync.feature
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,23 @@ Feature: Block Sync
# All nodes should sync to tip
Then all nodes are at height 20

@critical @pruned @broken
@critical
Scenario: Sync burned output
Given I have a seed node NODE
And I have a base node NODE1 connected to all seed nodes
And I have 2 base nodes connected to all seed nodes
And I have wallet WALLET_A connected to all seed nodes
And I have mining node MINER connected to base node NODE and wallet WALLET_A
When mining node MINER mines 15 blocks
Then all nodes are at height 15
When I wait for wallet WALLET_A to have at least 55000000000 uT
When I create a burn transaction of 1000000 uT from WALLET_A at fee 100
When mining node MINER mines 10 blocks
Then all nodes are at height 25
Given I have a base node NODE2 connected to all seed nodes
Then all nodes are at height 25

@critical @pruned
Scenario: Pruned mode simple sync
Given I have 1 seed nodes
Given I have a SHA3 miner NODE1 connected to all seed nodes
Expand All @@ -45,9 +61,10 @@ Feature: Block Sync
Given I have a pruned node PNODE1 connected to node NODE1 with pruning horizon set to 5
Then all nodes are at height 20

@critical @pruned @broken
@critical @pruned
Scenario: Pruned node should handle burned output
Given I have a seed node NODE
And I have a base node NODE1 connected to all seed nodes
And I have 2 base nodes connected to all seed nodes
And I have wallet WALLET_A connected to all seed nodes
And I have mining node MINER connected to base node NODE and wallet WALLET_A
Expand All @@ -58,7 +75,7 @@ Feature: Block Sync
When mining node MINER mines 10 blocks
Then all nodes are at height 25
Given I have a pruned node PNODE1 connected to node NODE1 with pruning horizon set to 5
Then all nodes are at height 20
Then all nodes are at height 25

@critical
Scenario: When a new node joins the network, it receives all peers
Expand Down
1 change: 1 addition & 0 deletions integration_tests/features/support/world.js
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ class CustomWorld {
let result = true;
await waitFor(
async () => {
result = true;
await this.forEachClientAsync(async (client, name) => {
await waitFor(
async () => await client.getTipHeight(),
Expand Down

0 comments on commit 0c062f3

Please sign in to comment.