From 054a314f015ab7a3f1e571f3ee0c7a58ad0ebb5a Mon Sep 17 00:00:00 2001 From: SW van Heerden Date: Tue, 11 Oct 2022 09:07:09 +0200 Subject: [PATCH] feat: move nonce to first in sha hash (#4778) Description --- This moves the nonce to the front of the hashing order when hashing for the sha3 difficulty. This is done so that mining cannot cache part most the header and only load the nonce in. This forces the miner to hash the complete header each time the nonce chances. Motivation and Context --- Fixes: #4767 How Has This Been Tested? --- Unit tests all pass. --- applications/tari_miner/src/difficulty.rs | 27 +------ .../core/src/consensus/consensus_constants.rs | 74 +++++++++++++------ base_layer/core/src/proof_of_work/sha3_pow.rs | 19 +++-- base_layer/core/tests/block_validation.rs | 1 + 4 files changed, 68 insertions(+), 53 deletions(-) diff --git a/applications/tari_miner/src/difficulty.rs b/applications/tari_miner/src/difficulty.rs index d4ef569167..3d1d354861 100644 --- a/applications/tari_miner/src/difficulty.rs +++ b/applications/tari_miner/src/difficulty.rs @@ -22,9 +22,8 @@ use std::convert::TryInto; -use sha3::{Digest, Sha3_256}; use tari_app_grpc::tari_rpc::BlockHeader as grpc_header; -use tari_core::{blocks::BlockHeader, large_ints::U256}; +use tari_core::{blocks::BlockHeader, large_ints::U256, proof_of_work::sha3_difficulty}; use tari_utilities::epoch_time::EpochTime; use crate::errors::MinerError; @@ -34,7 +33,6 @@ pub type Difficulty = u64; #[derive(Clone)] pub struct BlockHeaderSha3 { pub header: BlockHeader, - hash_merge_mining: Sha3_256, pub hashes: u64, } @@ -43,19 +41,7 @@ impl BlockHeaderSha3 { #[allow(clippy::cast_sign_loss)] pub fn new(header: grpc_header) -> Result { let header: BlockHeader = header.try_into().map_err(MinerError::BlockHeader)?; - - let hash_merge_mining = Sha3_256::new().chain(header.mining_hash()); - - Ok(Self { - hash_merge_mining, - header, - hashes: 0, - }) - } - - #[inline] - fn get_hash_before_nonce(&self) -> Sha3_256 { - self.hash_merge_mining.clone() + Ok(Self { header, hashes: 0 }) } /// This function will update the timestamp of the header, but only if the new timestamp is greater than the current @@ -65,7 +51,6 @@ impl BlockHeaderSha3 { // should only change the timestamp if we move it forward. if timestamp > self.header.timestamp.as_u64() { self.header.timestamp = EpochTime::from(timestamp); - self.hash_merge_mining = Sha3_256::new().chain(self.header.mining_hash()); } } @@ -82,13 +67,7 @@ impl BlockHeaderSha3 { #[inline] pub fn difficulty(&mut self) -> Difficulty { self.hashes = self.hashes.saturating_add(1); - let hash = self - .get_hash_before_nonce() - .chain(self.header.nonce.to_le_bytes()) - .chain(self.header.pow.to_bytes()) - .finalize(); - let hash = Sha3_256::digest(&hash); - big_endian_difficulty(&hash) + sha3_difficulty(&self.header).into() } #[allow(clippy::cast_possible_wrap)] diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index 4692e0a403..c2e420ea37 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -505,29 +505,52 @@ impl ConsensusConstants { target_time: 200, }); let (input_version_range, output_version_range, kernel_version_range) = version_zero(); - vec![ConsensusConstants { - effective_from_height: 0, - // Todo fix after test - coinbase_lock_height: 6, - blockchain_version: 0, - valid_blockchain_version_range: 0..=0, - future_time_limit: 540, - difficulty_block_window: 90, - max_block_transaction_weight: 127_795, - median_timestamp_count: 11, - emission_initial: 18_462_816_327 * uT, - emission_decay: &ESMERALDA_DECAY_PARAMS, - emission_tail: 800 * T, - max_randomx_seed_height: 3000, - proof_of_work: algos, - faucet_value: (10 * 4000) * T, - transaction_weight: TransactionWeight::v1(), - max_script_byte_size: 2048, - input_version_range, - output_version_range, - kernel_version_range, - permitted_output_types: Self::current_permitted_output_types(), - }] + vec![ + ConsensusConstants { + effective_from_height: 0, + coinbase_lock_height: 6, + blockchain_version: 0, + valid_blockchain_version_range: 0..=0, + future_time_limit: 540, + difficulty_block_window: 90, + max_block_transaction_weight: 127_795, + median_timestamp_count: 11, + emission_initial: 18_462_816_327 * uT, + emission_decay: &ESMERALDA_DECAY_PARAMS, + emission_tail: 800 * T, + max_randomx_seed_height: 3000, + proof_of_work: algos.clone(), + faucet_value: (10 * 4000) * T, + transaction_weight: TransactionWeight::v1(), + max_script_byte_size: 2048, + input_version_range: input_version_range.clone(), + output_version_range: output_version_range.clone(), + kernel_version_range: kernel_version_range.clone(), + permitted_output_types: Self::current_permitted_output_types(), + }, + ConsensusConstants { + effective_from_height: 23000, + coinbase_lock_height: 6, + blockchain_version: 1, + valid_blockchain_version_range: 0..=1, + future_time_limit: 540, + difficulty_block_window: 90, + max_block_transaction_weight: 127_795, + median_timestamp_count: 11, + emission_initial: 18_462_816_327 * uT, + emission_decay: &ESMERALDA_DECAY_PARAMS, + emission_tail: 800 * T, + max_randomx_seed_height: 3000, + proof_of_work: algos, + faucet_value: (10 * 4000) * T, + transaction_weight: TransactionWeight::v1(), + max_script_byte_size: 2048, + input_version_range, + output_version_range, + kernel_version_range, + permitted_output_types: Self::current_permitted_output_types(), + }, + ] } pub fn mainnet() -> Vec { @@ -653,6 +676,11 @@ impl ConsensusConstantsBuilder { self } + pub fn with_blockchain_version(mut self, version: u16) -> Self { + self.consensus.blockchain_version = version; + self + } + pub fn build(self) -> ConsensusConstants { self.consensus } diff --git a/base_layer/core/src/proof_of_work/sha3_pow.rs b/base_layer/core/src/proof_of_work/sha3_pow.rs index 4b79c29fa6..fe56685dd5 100644 --- a/base_layer/core/src/proof_of_work/sha3_pow.rs +++ b/base_layer/core/src/proof_of_work/sha3_pow.rs @@ -37,12 +37,19 @@ pub fn sha3_difficulty(header: &BlockHeader) -> Difficulty { } pub fn sha3_hash(header: &BlockHeader) -> Vec { - Sha3_256::new() - .chain(header.mining_hash()) - .chain(header.nonce.to_le_bytes()) - .chain(header.pow.to_bytes()) - .finalize() - .to_vec() + let sha = Sha3_256::new(); + match header.version { + 0 => sha + .chain(header.mining_hash()) + .chain(header.nonce.to_le_bytes()) + .chain(header.pow.to_bytes()), + _ => sha + .chain(header.nonce.to_le_bytes()) + .chain(header.mining_hash()) + .chain(header.pow.to_bytes()), + } + .finalize() + .to_vec() } fn sha3_difficulty_with_hash(header: &BlockHeader) -> (Difficulty, Vec) { diff --git a/base_layer/core/tests/block_validation.rs b/base_layer/core/tests/block_validation.rs index 9659a99b55..01037db622 100644 --- a/base_layer/core/tests/block_validation.rs +++ b/base_layer/core/tests/block_validation.rs @@ -102,6 +102,7 @@ fn test_monero_blocks() { max_difficulty: 1.into(), target_time: 200, }) + .with_blockchain_version(0) .build(); let cm = ConsensusManager::builder(network).add_consensus_constants(cc).build(); let header_validator = HeaderValidator::new(cm.clone());