Skip to content

Commit

Permalink
feat: merge consensus breaking changes in #3195 #3193 with weatherwax…
Browse files Browse the repository at this point in the history
… compatibility (#3372)

Description
---
Block v1 (compatible with weatherwax at all heights):
- Kernel ordering using every kernel field
- Input MR commits to empty serialization of bitmap

Block v2 (Igor, breaking change)
- Kernel ordering (#3193)
- Input MR uses input hashes only without extaneous empty bitmap bytes
  (#3195)

Misc

- Add missing kernel order block validation
- Removed unnecessary transaction body sorting in wallet, it (still) is the responsibility of the GetNewBlockTemplate to assemble a final sorted block body.

Motivation and Context
---
Allow consensus breaking code to be merged without hard forking weatherwax. 
Igor will have to be reset.

To follow in subsequent PR: network breaking changes from DHT header malleability fix (#3243 ) 

How Has This Been Tested?
---
Archival sync weatherwax node from scratch, received propagated blocks
Washing machine between two weatherwax wallets
  • Loading branch information
sdbondi authored Sep 21, 2021
1 parent 73017a4 commit 79c9c1d
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 114 deletions.
6 changes: 5 additions & 1 deletion base_layer/core/src/blocks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ impl Block {
Self { header, body }
}

pub fn version(&self) -> u16 {
self.header.version
}

/// This function will calculate the total fees contained in a block
pub fn calculate_fees(&self) -> MicroTari {
self.body.kernels().iter().fold(0.into(), |sum, x| sum + x.fee)
Expand Down Expand Up @@ -239,7 +243,7 @@ impl BlockBuilder {
header: self.header,
body: AggregateBody::new(self.inputs, self.outputs, self.kernels),
};
block.body.sort();
block.body.sort(block.header.version);
block
}
}
Expand Down
8 changes: 4 additions & 4 deletions base_layer/core/src/blocks/genesis_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ pub fn get_stibbons_genesis_block_raw() -> Block {
excess_sig: sig,
}],
);
body.sort();
body.sort(1);
Block {
header: BlockHeader {
version: 0,
Expand Down Expand Up @@ -226,7 +226,7 @@ pub fn get_weatherwax_genesis_block_raw() -> Block {
excess_sig: sig,
}],
);
body.sort();
body.sort(1);
// set genesis timestamp
let genesis = DateTime::parse_from_rfc2822("07 Jul 2021 06:00:00 +0200").unwrap();
let timestamp = genesis.timestamp() as u64;
Expand Down Expand Up @@ -336,7 +336,7 @@ pub fn get_ridcully_genesis_block_raw() -> Block {
excess_sig: sig,
}],
);
body.sort();
body.sort(1);
Block {
header: BlockHeader {
version: 0,
Expand Down Expand Up @@ -419,7 +419,7 @@ pub fn get_igor_genesis_block_raw() -> Block {
excess_sig: sig,
}],
);
body.sort();
body.sort(2);
// set genesis timestamp
let genesis = DateTime::parse_from_rfc2822("27 Aug 2021 06:00:00 +0200").unwrap();
let timestamp = genesis.timestamp() as u64;
Expand Down
19 changes: 12 additions & 7 deletions base_layer/core/src/chain_storage/blockchain_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use std::{
collections::VecDeque,
convert::TryFrom,
mem,
ops::Bound,
ops::{Bound, RangeBounds},
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
time::Instant,
};
Expand All @@ -75,8 +75,7 @@ use tari_common_types::{
types::{BlockHash, Commitment, HashDigest, HashOutput, Signature},
};
use tari_crypto::tari_utilities::{hex::Hex, ByteArray, Hashable};
use tari_mmr::{MerkleMountainRange, MutableMmr};
use uint::static_assertions::_core::ops::RangeBounds;
use tari_mmr::{pruned_hashset::PrunedHashSet, MerkleMountainRange, MutableMmr};

const LOG_TARGET: &str = "c::cs::database";

Expand Down Expand Up @@ -229,7 +228,6 @@ where B: BlockchainBackend
/// Returns a reference to the consensus cosntants at the current height
pub fn consensus_constants(&self) -> Result<&ConsensusConstants, ChainStorageError> {
let height = self.get_height()?;

Ok(self.consensus_manager.consensus_constants(height))
}

Expand Down Expand Up @@ -649,7 +647,7 @@ where B: BlockchainBackend

pub fn prepare_new_block(&self, template: NewBlockTemplate) -> Result<Block, ChainStorageError> {
let NewBlockTemplate { header, mut body, .. } = template;
body.sort();
body.sort(header.version);
let mut header = BlockHeader::from(header);
// If someone advanced the median timestamp such that the local time is less than the median timestamp, we need
// to increase the timestamp to be greater than the median timestamp
Expand Down Expand Up @@ -995,7 +993,7 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul
let mut kernel_mmr = MerkleMountainRange::<HashDigest, _>::new(kernels);
let mut output_mmr = MutableMmr::<HashDigest, _>::new(outputs, deleted)?;
let mut witness_mmr = MerkleMountainRange::<HashDigest, _>::new(range_proofs);
let mut input_mmr = MutableMmr::<HashDigest, _>::new(Vec::new(), Bitmap::create())?;
let mut input_mmr = MerkleMountainRange::<HashDigest, _>::new(PrunedHashSet::default());

for kernel in body.kernels().iter() {
kernel_mmr.push(kernel.hash())?;
Expand Down Expand Up @@ -1052,10 +1050,17 @@ pub fn calculate_mmr_roots<T: BlockchainBackend>(db: &T, block: &Block) -> Resul

output_mmr.compress();

// TODO: #testnetreset clean up this code
let input_mr = if header.version == 1 {
MutableMmr::<HashDigest, _>::new(input_mmr.get_pruned_hash_set()?, Bitmap::create())?.get_merkle_root()?
} else {
input_mmr.get_merkle_root()?
};

let mmr_roots = MmrRoots {
kernel_mr: kernel_mmr.get_merkle_root()?,
kernel_mmr_size: kernel_mmr.get_leaf_count()? as u64,
input_mr: input_mmr.get_merkle_root()?,
input_mr,
output_mr: output_mmr.get_merkle_root()?,
output_mmr_size: output_mmr.get_leaf_count() as u64,
witness_mr: witness_mmr.get_merkle_root()?,
Expand Down
24 changes: 12 additions & 12 deletions base_layer/core/src/consensus/consensus_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ impl ConsensusConstants {
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
}]
Expand All @@ -218,7 +218,7 @@ impl ConsensusConstants {
pub fn ridcully() -> Vec<Self> {
let difficulty_block_window = 90;
let mut algos = HashMap::new();
// seting sha3/monero to 40/60 split
// setting sha3/monero to 40/60 split
algos.insert(PowAlgorithm::Sha3, PowAlgorithmConstants {
max_target_time: 1800,
min_difficulty: 60_000_000.into(),
Expand All @@ -242,7 +242,7 @@ impl ConsensusConstants {
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
}]
Expand Down Expand Up @@ -277,7 +277,7 @@ impl ConsensusConstants {
target_time: 200,
});
let mut algos2 = HashMap::new();
// seting sha3/monero to 40/60 split
// setting sha3/monero to 40/60 split
algos2.insert(PowAlgorithm::Sha3, PowAlgorithmConstants {
max_target_time: 1800,
min_difficulty: 60_000_000.into(),
Expand All @@ -302,7 +302,7 @@ impl ConsensusConstants {
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
},
Expand All @@ -317,7 +317,7 @@ impl ConsensusConstants {
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos2,
faucet_value: (5000 * 4000) * T,
},
Expand All @@ -326,7 +326,7 @@ impl ConsensusConstants {

pub fn weatherwax() -> Vec<Self> {
let mut algos = HashMap::new();
// seting sha3/monero to 40/60 split
// setting sha3/monero to 40/60 split
algos.insert(PowAlgorithm::Sha3, PowAlgorithmConstants {
max_target_time: 1800,
min_difficulty: 60_000_000.into(),
Expand All @@ -350,15 +350,15 @@ impl ConsensusConstants {
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
}]
}

pub fn igor() -> Vec<Self> {
let mut algos = HashMap::new();
// seting sha3/monero to 40/60 split
// setting sha3/monero to 40/60 split
algos.insert(PowAlgorithm::Sha3, PowAlgorithmConstants {
max_target_time: 1800,
min_difficulty: 60_000_000.into(),
Expand All @@ -374,15 +374,15 @@ impl ConsensusConstants {
vec![ConsensusConstants {
effective_from_height: 0,
coinbase_lock_height: 6,
blockchain_version: 1,
blockchain_version: 2,
future_time_limit: 540,
difficulty_block_window: 90,
max_block_transaction_weight: 19500,
median_timestamp_count: 11,
emission_initial: 5_538_846_115 * uT,
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: (5000 * 4000) * T,
}]
Expand Down Expand Up @@ -415,7 +415,7 @@ impl ConsensusConstants {
emission_initial: 10_000_000.into(),
emission_decay: &EMISSION_DECAY,
emission_tail: 100.into(),
max_randomx_seed_height: std::u64::MAX,
max_randomx_seed_height: u64::MAX,
proof_of_work: algos,
faucet_value: MicroTari::from(0),
}]
Expand Down
3 changes: 1 addition & 2 deletions base_layer/core/src/proto/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,7 @@ impl TryFrom<proto::types::AggregateBody> for AggregateBody {
let inputs = try_convert_all(body.inputs)?;
let outputs = try_convert_all(body.outputs)?;
let kernels = try_convert_all(body.kernels)?;
let mut body = AggregateBody::new(inputs, outputs, kernels);
body.sort();
let body = AggregateBody::new(inputs, outputs, kernels);
Ok(body)
}
}
Expand Down
19 changes: 16 additions & 3 deletions base_layer/core/src/transactions/aggregated_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub const LOG_TARGET: &str = "c::tx::aggregated_body";

/// The components of the block or transaction. The same struct can be used for either, since in Mimblewimble,
/// cut-through means that blocks and transactions have the same structure.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AggregateBody {
sorted: bool,
/// List of inputs spent by the transaction.
Expand Down Expand Up @@ -198,13 +198,18 @@ impl AggregateBody {
}

/// Sort the component lists of the aggregate body
pub fn sort(&mut self) {
pub fn sort(&mut self, version: u16) {
if self.sorted {
return;
}
self.inputs.sort();
self.outputs.sort();
self.kernels.sort();
// TODO: #testnetreset clean up this code
if version <= 1 {
self.kernels.sort_by(|a, b| a.deprecated_cmp(b));
} else {
self.kernels.sort();
}
self.sorted = true;
}

Expand Down Expand Up @@ -471,6 +476,14 @@ impl AggregateBody {
}
}

impl PartialEq for AggregateBody {
fn eq(&self, other: &Self) -> bool {
self.kernels == other.kernels && self.inputs == other.inputs && self.outputs == other.outputs
}
}

impl Eq for AggregateBody {}

/// This will strip away the offset of the transaction returning a pure aggregate body
impl From<Transaction> for AggregateBody {
fn from(transaction: Transaction) -> Self {
Expand Down
Loading

0 comments on commit 79c9c1d

Please sign in to comment.