From 2033a2d16c2f6e1da4ca86d4ed0cb9d7ede30916 Mon Sep 17 00:00:00 2001 From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com> Date: Tue, 24 Oct 2023 23:02:19 +0100 Subject: [PATCH] add rules for blocks TODO: the tests need re-ordering they are just all chucked in at the moment. --- consensus/Cargo.toml | 2 -- consensus/src/bin/scan_chain.rs | 23 ++++++++++++++- consensus/src/block.rs | 21 +++++++++++++- consensus/src/block/checks.rs | 27 ++++++++++++++---- consensus/src/block/miner_tx.rs | 5 ++-- consensus/src/context.rs | 2 +- consensus/src/context/hardforks.rs | 38 +++++++++---------------- consensus/src/transactions.rs | 4 ++- consensus/src/transactions/time_lock.rs | 2 +- cryptonight/build.rs | 2 +- net/monero-wire/src/serde_helpers.rs | 2 -- 11 files changed, 86 insertions(+), 42 deletions(-) diff --git a/consensus/Cargo.toml b/consensus/Cargo.toml index 5074e6e9..8bc42368 100644 --- a/consensus/Cargo.toml +++ b/consensus/Cargo.toml @@ -57,5 +57,3 @@ dirs = {version="5.0", optional = true} # here to help cargo to pick a version - remove me syn = "2.0.37" -[profile.dev] -opt-level = 3 diff --git a/consensus/src/bin/scan_chain.rs b/consensus/src/bin/scan_chain.rs index 6d1f051f..22adb621 100644 --- a/consensus/src/bin/scan_chain.rs +++ b/consensus/src/bin/scan_chain.rs @@ -132,7 +132,28 @@ where if current_height % 500 == 0 { tracing::info!("Saving cache to: {}", save_file.display()); - cache.write().unwrap().save(&save_file)?; + cache.read().unwrap().save(&save_file)?; + + let DatabaseResponse::BlockExtendedHeader(header) = database + .ready() + .await? + .call(DatabaseRequest::BlockExtendedHeader( + verified_block_info.height.into(), + )) + .await? + else { + panic!(); + }; + + assert_eq!(header.block_weight, verified_block_info.weight); + assert_eq!( + header.cumulative_difficulty, + verified_block_info.cumulative_difficulty + ); + assert_eq!( + header.long_term_weight, + verified_block_info.long_term_weight + ); } } } diff --git a/consensus/src/block.rs b/consensus/src/block.rs index ca15ed5d..e5f11e0c 100644 --- a/consensus/src/block.rs +++ b/consensus/src/block.rs @@ -15,7 +15,7 @@ use crate::{ ConsensusError, HardFork, }; -//mod checks; +mod checks; mod hash_worker; mod miner_tx; @@ -127,6 +127,8 @@ where tracing::debug!("got blockchain context: {:?}", context); + // TODO: reorder these tests so we do the cheap tests first. + let txs = if !txs.is_empty() { let VerifyTxResponse::BatchSetupOk(txs) = tx_verifier_svc .oneshot(VerifyTxRequest::BatchSetupVerifyBlock { @@ -159,6 +161,17 @@ where let hashing_blob = block.serialize_hashable(); + checks::block_size_sanity_check(block.serialize().len(), context.effective_median_weight)?; + checks::block_weight_check(block_weight, context.median_weight_for_block_reward)?; + + checks::check_amount_txs(block.txs.len())?; + checks::check_prev_id(&block, &context.top_hash)?; + if let Some(median_timestamp) = context.median_block_timestamp { + // will only be None for the first 60 blocks + checks::check_timestamp(&block, median_timestamp)?; + } + + // do POW test last let pow_hash = tokio::task::spawn_blocking(move || { hash_worker::calculate_pow_hash( &hashing_blob, @@ -169,6 +182,12 @@ where .await .unwrap()?; + checks::check_block_pow(&pow_hash, context.next_difficulty)?; + + context + .current_hard_fork + .check_block_version_vote(&block.header)?; + Ok(VerifiedBlockInformation { block_hash: block.hash(), block, diff --git a/consensus/src/block/checks.rs b/consensus/src/block/checks.rs index 0499051a..3bdde852 100644 --- a/consensus/src/block/checks.rs +++ b/consensus/src/block/checks.rs @@ -15,18 +15,22 @@ const BLOCK_FUTURE_TIME_LIMIT: u64 = 60 * 60 * 2; /// Returns if the blocks POW hash is valid for the current difficulty. /// /// See: https://cuprate.github.io/monero-book/consensus_rules/blocks/difficulty.html#checking-a-blocks-proof-of-work -pub fn check_block_pow(hash: &[u8; 32], difficulty: u128) -> bool { +pub fn check_block_pow(hash: &[u8; 32], difficulty: u128) -> Result<(), ConsensusError> { let int_hash = U256::from_le_slice(hash); let difficulty = U256::from_u128(difficulty); - int_hash.checked_mul(&difficulty).is_some().unwrap_u8() == 1 + if int_hash.checked_mul(&difficulty).is_some().unwrap_u8() != 1 { + Err(ConsensusError::BlockPOWInvalid) + } else { + Ok(()) + } } /// Sanity check on the block blob size. /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#block-weight-and-size -fn block_size_sanity_check( +pub fn block_size_sanity_check( block_blob_len: usize, effective_median: usize, ) -> Result<(), ConsensusError> { @@ -37,10 +41,21 @@ fn block_size_sanity_check( } } +/// Sanity check on number of txs in the block. +/// +/// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#amount-of-transactions +pub fn check_amount_txs(number_none_miner_txs: usize) -> Result<(), ConsensusError> { + if number_none_miner_txs + 1 > 0x10000000 { + Err(ConsensusError::BlockIsTooLarge) + } else { + Ok(()) + } +} + /// Sanity check on the block weight. /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#block-weight-and-siz -fn block_weight_check( +pub fn block_weight_check( block_weight: usize, median_for_block_reward: usize, ) -> Result<(), ConsensusError> { @@ -54,7 +69,7 @@ fn block_weight_check( /// Verifies the previous id is the last blocks hash /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#previous-id -fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), ConsensusError> { +pub fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), ConsensusError> { if &block.header.previous != top_hash { Err(ConsensusError::BlockIsNotApartOfChain) } else { @@ -65,7 +80,7 @@ fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), ConsensusErro /// Checks the blocks timestamp is in the valid range. /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#timestamp -fn check_timestamp(block: &Block, median_timestamp: u64) -> Result<(), ConsensusError> { +pub fn check_timestamp(block: &Block, median_timestamp: u64) -> Result<(), ConsensusError> { if block.header.timestamp < median_timestamp || block.header.timestamp > current_time() + BLOCK_FUTURE_TIME_LIMIT { diff --git a/consensus/src/block/miner_tx.rs b/consensus/src/block/miner_tx.rs index faeed8dc..de41cb42 100644 --- a/consensus/src/block/miner_tx.rs +++ b/consensus/src/block/miner_tx.rs @@ -46,7 +46,8 @@ pub fn calculate_block_reward( /// Checks the miner transactions version. /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#version -fn check_tx_version(tx_version: &TxVersion, hf: &HardFork) -> Result<(), ConsensusError> { +fn check_miner_tx_version(tx_version: &TxVersion, hf: &HardFork) -> Result<(), ConsensusError> { + // The TxVersion enum checks if the version is not 1 or 2 if hf >= &HardFork::V12 && tx_version != &TxVersion::RingCT { Err(ConsensusError::MinerTransaction("Version invalid")) } else { @@ -162,7 +163,7 @@ pub fn check_miner_tx( hf: &HardFork, ) -> Result { let tx_version = TxVersion::from_raw(tx.prefix.version)?; - check_tx_version(&tx_version, hf)?; + check_miner_tx_version(&tx_version, hf)?; if hf >= &HardFork::V12 && tx.rct_signatures.rct_type() != RctType::Null { return Err(ConsensusError::MinerTransaction("RctType is not null")); diff --git a/consensus/src/context.rs b/consensus/src/context.rs index 5017c2e4..11504410 100644 --- a/consensus/src/context.rs +++ b/consensus/src/context.rs @@ -137,7 +137,7 @@ pub struct BlockChainContext { /// The current cumulative difficulty. pub cumulative_difficulty: u128, /// The current effective median block weight. - effective_median_weight: usize, + pub effective_median_weight: usize, /// The median long term block weight. median_long_term_weight: usize, /// Median weight to use for block reward calculations. diff --git a/consensus/src/context/hardforks.rs b/consensus/src/context/hardforks.rs index 9e57a3d5..db3901e0 100644 --- a/consensus/src/context/hardforks.rs +++ b/consensus/src/context/hardforks.rs @@ -18,28 +18,6 @@ const BLOCK_TIME_V2: Duration = Duration::from_secs(120); const NUMB_OF_HARD_FORKS: usize = 16; -#[derive(Debug, Clone, Copy)] -pub struct BlockHFInfo { - pub version: HardFork, - pub vote: HardFork, -} - -impl BlockHFInfo { - pub fn from_block_header(block_header: &BlockHeader) -> Result { - BlockHFInfo::from_major_minor(block_header.major_version, block_header.minor_version) - } - - pub fn from_major_minor( - major_version: u8, - minor_version: u8, - ) -> Result { - Ok(BlockHFInfo { - version: HardFork::from_version(&major_version)?, - vote: HardFork::from_vote(&minor_version), - }) - } -} - /// Information about a given hard-fork. #[derive(Debug, Clone, Copy)] pub struct HFInfo { @@ -187,8 +165,20 @@ impl HardFork { /// Checks a blocks version and vote, assuming that `self` is the current hard-fork. /// /// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#version-and-vote - pub fn check_block_version_vote(&self, block_hf_info: &BlockHFInfo) -> bool { - self == &block_hf_info.version && &block_hf_info.vote >= self + pub fn check_block_version_vote( + &self, + block_header: &BlockHeader, + ) -> Result<(), ConsensusError> { + let version = HardFork::from_version(&block_header.major_version)?; + let vote = HardFork::from_vote(&block_header.minor_version); + + if self == &version && &vote >= self { + Ok(()) + } else { + Err(ConsensusError::InvalidHardForkVersion( + "Block version or vote incorrect", + )) + } } } diff --git a/consensus/src/transactions.rs b/consensus/src/transactions.rs index c5790ef7..28d0e700 100644 --- a/consensus/src/transactions.rs +++ b/consensus/src/transactions.rs @@ -236,7 +236,9 @@ where spent_kis.clone(), ) }) - }); + }) + .await + .unwrap()?; Ok(VerifyTxResponse::Ok) } diff --git a/consensus/src/transactions/time_lock.rs b/consensus/src/transactions/time_lock.rs index 8546842a..48d1177d 100644 --- a/consensus/src/transactions/time_lock.rs +++ b/consensus/src/transactions/time_lock.rs @@ -58,7 +58,7 @@ fn output_unlocked( /// https://cuprate.github.io/monero-book/consensus_rules/transactions/unlock_time.html#block-height fn check_block_time_lock(unlock_height: u64, current_chain_height: u64) -> bool { // current_chain_height = 1 + top height - unlock_height >= current_chain_height + unlock_height <= current_chain_height } /// /// diff --git a/cryptonight/build.rs b/cryptonight/build.rs index 92a7fea5..abf7ebbb 100644 --- a/cryptonight/build.rs +++ b/cryptonight/build.rs @@ -21,7 +21,7 @@ fn main() { .file("c/CryptonightR_JIT.c") .file("c/CryptonightR_template.S") .flag("-maes") - .flag("-Ofast") + .flag("-O2") .flag("-fexceptions") .compile("cryptonight") } diff --git a/net/monero-wire/src/serde_helpers.rs b/net/monero-wire/src/serde_helpers.rs index afdb99d1..efc8844d 100644 --- a/net/monero-wire/src/serde_helpers.rs +++ b/net/monero-wire/src/serde_helpers.rs @@ -1,5 +1,3 @@ -use std::fmt::Debug; - pub(crate) fn default_false() -> bool { false }