link rules to monero-book.

need to do transactions.
This commit is contained in:
Boog900 2024-01-07 01:15:33 +00:00
parent 40e64cc9c3
commit 13957a5e7f
No known key found for this signature in database
GPG key ID: 5401367FB7302004
9 changed files with 124 additions and 58 deletions

View file

@ -30,22 +30,29 @@ pub enum BlockError {
PreviousIDIncorrect, PreviousIDIncorrect,
#[error("The blocks timestamp is invalid.")] #[error("The blocks timestamp is invalid.")]
TimeStampInvalid, TimeStampInvalid,
#[error("The block contains a duplicate transaction.")]
DuplicateTransaction,
#[error("Hard-fork error: {0}")] #[error("Hard-fork error: {0}")]
HardForkError(#[from] HardForkError), HardForkError(#[from] HardForkError),
#[error("Miner transaction error: {0}")] #[error("Miner transaction error: {0}")]
MinerTxError(#[from] MinerTxError), MinerTxError(#[from] MinerTxError),
} }
/// A trait to represent the RandomX VM.
pub trait RandomX { pub trait RandomX {
type Error; type Error;
fn calculate_hash(&self, buf: &[u8]) -> Result<[u8; 32], Self::Error>; fn calculate_hash(&self, buf: &[u8]) -> Result<[u8; 32], Self::Error>;
} }
/// Returns if this height is a RandomX seed height.
pub fn is_randomx_seed_height(height: u64) -> bool { pub fn is_randomx_seed_height(height: u64) -> bool {
height % RX_SEEDHASH_EPOCH_BLOCKS == 0 height % RX_SEEDHASH_EPOCH_BLOCKS == 0
} }
/// Returns the RandomX seed height for this block.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#randomx-seed
pub fn randomx_seed_height(height: u64) -> u64 { pub fn randomx_seed_height(height: u64) -> u64 {
if height <= RX_SEEDHASH_EPOCH_BLOCKS + RX_SEEDHASH_EPOCH_LAG { if height <= RX_SEEDHASH_EPOCH_BLOCKS + RX_SEEDHASH_EPOCH_LAG {
0 0
@ -55,6 +62,8 @@ pub fn randomx_seed_height(height: u64) -> u64 {
} }
/// Calculates the POW hash of this block. /// Calculates the POW hash of this block.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#pow-function
pub fn calculate_pow_hash<R: RandomX>( pub fn calculate_pow_hash<R: RandomX>(
randomx_vm: &R, randomx_vm: &R,
buf: &[u8], buf: &[u8],
@ -82,7 +91,7 @@ pub fn calculate_pow_hash<R: RandomX>(
/// Returns if the blocks POW hash is valid for the current difficulty. /// 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 /// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#checking-pow-hash
pub fn check_block_pow(hash: &[u8; 32], difficulty: u128) -> Result<(), BlockError> { pub fn check_block_pow(hash: &[u8; 32], difficulty: u128) -> Result<(), BlockError> {
let int_hash = U256::from_little_endian(hash); let int_hash = U256::from_little_endian(hash);
@ -102,7 +111,7 @@ pub fn check_block_pow(hash: &[u8; 32], difficulty: u128) -> Result<(), BlockErr
/// Sanity check on the block blob size. /// Sanity check on the block blob size.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#block-weight-and-size /// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#block-weight-and-size
fn block_size_sanity_check( fn block_size_sanity_check(
block_blob_len: usize, block_blob_len: usize,
effective_median: usize, effective_median: usize,
@ -114,20 +123,9 @@ 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
fn check_amount_txs(number_none_miner_txs: usize) -> Result<(), BlockError> {
if number_none_miner_txs + 1 > 0x10000000 {
Err(BlockError::TooManyTxs)
} else {
Ok(())
}
}
/// Sanity check on the block weight. /// Sanity check on the block weight.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#block-weight-and-siz /// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#block-weight-and-size
fn check_block_weight( fn check_block_weight(
block_weight: usize, block_weight: usize,
median_for_block_reward: usize, median_for_block_reward: usize,
@ -139,9 +137,20 @@ fn check_block_weight(
} }
} }
/// Sanity check on number of txs in the block.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#amount-of-transactions
fn check_amount_txs(number_none_miner_txs: usize) -> Result<(), BlockError> {
if number_none_miner_txs + 1 > 0x10000000 {
Err(BlockError::TooManyTxs)
} else {
Ok(())
}
}
/// Verifies the previous id is the last blocks hash /// Verifies the previous id is the last blocks hash
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#previous-id /// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#previous-id
fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), BlockError> { fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), BlockError> {
if &block.header.previous != top_hash { if &block.header.previous != top_hash {
Err(BlockError::PreviousIDIncorrect) Err(BlockError::PreviousIDIncorrect)
@ -152,7 +161,7 @@ fn check_prev_id(block: &Block, top_hash: &[u8; 32]) -> Result<(), BlockError> {
/// Checks the blocks timestamp is in the valid range. /// Checks the blocks timestamp is in the valid range.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks.html#timestamp /// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#timestamp
fn check_timestamp(block: &Block, median_timestamp: u64) -> Result<(), BlockError> { fn check_timestamp(block: &Block, median_timestamp: u64) -> Result<(), BlockError> {
if block.header.timestamp < median_timestamp if block.header.timestamp < median_timestamp
|| block.header.timestamp > current_unix_timestamp() + BLOCK_FUTURE_TIME_LIMIT || block.header.timestamp > current_unix_timestamp() + BLOCK_FUTURE_TIME_LIMIT
@ -163,21 +172,52 @@ fn check_timestamp(block: &Block, median_timestamp: u64) -> Result<(), BlockErro
} }
} }
/// Checks that all txs in the block have a unique hash.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks.html#no-duplicate-transactions
fn check_txs_unique(txs: &[[u8; 32]]) -> Result<(), BlockError> {
txs.windows(2).try_for_each(|window| {
if window[0] != window[1] {
Err(BlockError::DuplicateTransaction)?;
}
Ok(())
})
}
/// This struct contains the data needed to verify a block, implementers MUST make sure
/// the data in this struct is calculated correctly.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ContextToVerifyBlock { pub struct ContextToVerifyBlock {
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#median-weight-for-coinbase-checks
pub median_weight_for_block_reward: usize, pub median_weight_for_block_reward: usize,
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/weights.html#effective-median-weight
pub effective_median_weight: usize, pub effective_median_weight: usize,
/// The top hash of the blockchain, aka the block hash of the previous block to the one we are verifying.
pub top_hash: [u8; 32], pub top_hash: [u8; 32],
/// Contains the median timestamp over the last 60 blocks, if there is less than 60 blocks this should be [`None`]
pub median_block_timestamp: Option<u64>, pub median_block_timestamp: Option<u64>,
/// The current chain height.
pub chain_height: u64, pub chain_height: u64,
/// The current hard-fork.
pub current_hf: HardFork, pub current_hf: HardFork,
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#calculating-difficulty
pub next_difficulty: u128, pub next_difficulty: u128,
/// The amount of coins already minted.
pub already_generated_coins: u64, pub already_generated_coins: u64,
} }
/// Checks the block is valid returning the blocks hard-fork vote and the amount of coins generated. /// Checks the block is valid returning the blocks hard-fork `VOTE` and the amount of coins generated in this block.
///
/// This does not check the POW nor does it calculate the POW hash, this is because checking POW is very expensive and
/// to allow the computation of the POW hashes to be done separately. This also does not check the transactions in the
/// block are valid.
///
/// Missed block checks in this function:
///
/// https://monero-book.cuprate.org/consensus_rules/blocks.html#key-images
/// https://monero-book.cuprate.org/consensus_rules/blocks.html#checking-pow-hash
///
/// ///
/// Does not check the proof of work as that check is expensive and should be done last.
pub fn check_block( pub fn check_block(
block: &Block, block: &Block,
total_fees: u64, total_fees: u64,
@ -201,6 +241,7 @@ pub fn check_block(
block_size_sanity_check(block_blob_len, block_chain_ctx.effective_median_weight)?; block_size_sanity_check(block_blob_len, block_chain_ctx.effective_median_weight)?;
check_amount_txs(block.txs.len())?; check_amount_txs(block.txs.len())?;
check_txs_unique(&block.txs)?;
let generated_coins = check_miner_tx( let generated_coins = check_miner_tx(
&block.miner_tx, &block.miner_tx,

View file

@ -36,8 +36,8 @@ pub fn decomposed_amounts() -> &'static [u64; 172] {
/// ///
/// This is also used during miner tx verification. /// This is also used during miner tx verification.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/transactions/pre_rct.html#output-amount /// ref: https://monero-book.cuprate.org/consensus_rules/transactions/ring_signatures.html#output-amount
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#output-amounts /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#output-amounts
#[inline] #[inline]
pub fn is_decomposed_amount(amount: &u64) -> bool { pub fn is_decomposed_amount(amount: &u64) -> bool {
decomposed_amounts().binary_search(amount).is_ok() decomposed_amounts().binary_search(amount).is_ok()

View file

@ -25,7 +25,7 @@ fn genesis_miner_tx(network: &Network) -> Transaction {
/// Generates the Monero genesis block. /// Generates the Monero genesis block.
/// ///
/// ref: https://cuprate.github.io/monero-docs/consensus_rules/genesis_block.html /// ref: https://monero-book.cuprate.org/consensus_rules/genesis_block.html
pub fn generate_genesis_block(network: &Network) -> Block { pub fn generate_genesis_block(network: &Network) -> Block {
Block { Block {
header: BlockHeader { header: BlockHeader {

View file

@ -17,8 +17,12 @@ use std::{
mod tests; mod tests;
/// Target block time for hf 1. /// Target block time for hf 1.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds
const BLOCK_TIME_V1: Duration = Duration::from_secs(60); const BLOCK_TIME_V1: Duration = Duration::from_secs(60);
/// Target block time from v2. /// Target block time from v2.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds
const BLOCK_TIME_V2: Duration = Duration::from_secs(120); const BLOCK_TIME_V2: Duration = Duration::from_secs(120);
pub const NUMB_OF_HARD_FORKS: usize = 16; pub const NUMB_OF_HARD_FORKS: usize = 16;
@ -60,7 +64,7 @@ impl HFsInfo {
/// Returns the main-net hard-fork information. /// Returns the main-net hard-fork information.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/hardforks.html#Mainnet-Hard-Forks /// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#Mainnet-Hard-Forks
pub const fn main_net() -> HFsInfo { pub const fn main_net() -> HFsInfo {
Self([ Self([
HFInfo::new(0, 0), HFInfo::new(0, 0),
@ -82,6 +86,9 @@ impl HFsInfo {
]) ])
} }
/// Returns the test-net hard-fork information.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#Testnet-Hard-Forks
pub const fn test_net() -> HFsInfo { pub const fn test_net() -> HFsInfo {
Self([ Self([
HFInfo::new(0, 0), HFInfo::new(0, 0),
@ -103,6 +110,9 @@ impl HFsInfo {
]) ])
} }
/// Returns the test-net hard-fork information.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#Stagenet-Hard-Forks
pub const fn stage_net() -> HFsInfo { pub const fn stage_net() -> HFsInfo {
Self([ Self([
HFInfo::new(0, 0), HFInfo::new(0, 0),
@ -152,7 +162,7 @@ pub enum HardFork {
impl HardFork { impl HardFork {
/// Returns the hard-fork for a blocks `major_version` field. /// Returns the hard-fork for a blocks `major_version` field.
/// ///
/// https://cuprate.github.io/monero-docs/consensus_rules/hardforks.html#blocks-version-and-vote /// https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote
pub fn from_version(version: u8) -> Result<HardFork, HardForkError> { pub fn from_version(version: u8) -> Result<HardFork, HardForkError> {
Ok(match version { Ok(match version {
1 => HardFork::V1, 1 => HardFork::V1,
@ -177,7 +187,7 @@ impl HardFork {
/// Returns the hard-fork for a blocks `minor_version` (vote) field. /// Returns the hard-fork for a blocks `minor_version` (vote) field.
/// ///
/// https://cuprate.github.io/monero-docs/consensus_rules/hardforks.html#blocks-version-and-vote /// https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote
pub fn from_vote(vote: u8) -> HardFork { pub fn from_vote(vote: u8) -> HardFork {
if vote == 0 { if vote == 0 {
// A vote of 0 is interpreted as 1 as that's what Monero used to default to. // A vote of 0 is interpreted as 1 as that's what Monero used to default to.
@ -200,6 +210,8 @@ impl HardFork {
} }
/// Returns the target block time for this hardfork. /// Returns the target block time for this hardfork.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/difficulty.html#target-seconds
pub fn block_time(&self) -> Duration { pub fn block_time(&self) -> Duration {
match self { match self {
HardFork::V1 => BLOCK_TIME_V1, HardFork::V1 => BLOCK_TIME_V1,
@ -209,7 +221,7 @@ impl HardFork {
/// Checks a blocks version and vote, assuming that `self` is the current hard-fork. /// 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 /// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#blocks-version-and-vote
pub fn check_block_version_vote( pub fn check_block_version_vote(
&self, &self,
version: &HardFork, version: &HardFork,
@ -280,7 +292,7 @@ impl HFVotes {
/// Returns the total votes for a hard-fork. /// Returns the total votes for a hard-fork.
/// ///
/// https://cuprate.github.io/monero-docs/consensus_rules/hardforks.html#accepting-a-fork /// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#accepting-a-fork
pub fn votes_for_hf(&self, hf: &HardFork) -> u64 { pub fn votes_for_hf(&self, hf: &HardFork) -> u64 {
self.votes[*hf as usize - 1..].iter().sum() self.votes[*hf as usize - 1..].iter().sum()
} }
@ -293,7 +305,7 @@ impl HFVotes {
/// Checks if a future hard fork should be activated, returning the next hard-fork that should be /// Checks if a future hard fork should be activated, returning the next hard-fork that should be
/// activated. /// activated.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/hardforks.html#accepting-a-fork /// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#accepting-a-fork
pub fn current_fork( pub fn current_fork(
&self, &self,
current_hf: &HardFork, current_hf: &HardFork,
@ -323,7 +335,7 @@ impl HFVotes {
/// Returns the votes needed for a hard-fork. /// Returns the votes needed for a hard-fork.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/hardforks.html#accepting-a-fork /// ref: https://monero-book.cuprate.org/consensus_rules/hardforks.html#accepting-a-fork
pub fn votes_needed(threshold: u64, window: u64) -> u64 { pub fn votes_needed(threshold: u64, window: u64) -> u64 {
(threshold * window).div_ceil(100) (threshold * window).div_ceil(100)
} }

View file

@ -32,6 +32,7 @@ fn check_point_canonically_encoded(point: &curve25519_dalek::edwards::Compressed
.is_some() .is_some()
} }
/// Returns the current UNIX timestamp.
pub fn current_unix_timestamp() -> u64 { pub fn current_unix_timestamp() -> u64 {
SystemTime::now() SystemTime::now()
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
@ -39,6 +40,8 @@ pub fn current_unix_timestamp() -> u64 {
.as_secs() .as_secs()
} }
/// An internal function that returns an iterator or a parallel iterator if the
/// `rayon` feature is enabled.
#[cfg(feature = "rayon")] #[cfg(feature = "rayon")]
fn try_par_iter<T>(t: T) -> T::Iter fn try_par_iter<T>(t: T) -> T::Iter
where where
@ -47,6 +50,8 @@ where
t.into_par_iter() t.into_par_iter()
} }
/// An internal function that returns an iterator or a parallel iterator if the
/// `rayon` feature is enabled.
#[cfg(not(feature = "rayon"))] #[cfg(not(feature = "rayon"))]
fn try_par_iter<T>(t: T) -> impl std::iter::Iterator<Item = T::Item> fn try_par_iter<T>(t: T) -> impl std::iter::Iterator<Item = T::Item>
where where

View file

@ -39,6 +39,8 @@ const MINER_TX_TIME_LOCKED_BLOCKS: u64 = 60;
/// Calculates the base block reward without taking away the penalty for expanding /// Calculates the base block reward without taking away the penalty for expanding
/// the block. /// the block.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/reward.html#calculating-base-block-reward
fn calculate_base_reward(already_generated_coins: u64, hf: &HardFork) -> u64 { fn calculate_base_reward(already_generated_coins: u64, hf: &HardFork) -> u64 {
let target_mins = hf.block_time().as_secs() / 60; let target_mins = hf.block_time().as_secs() / 60;
let emission_speed_factor = 20 - (target_mins - 1); let emission_speed_factor = 20 - (target_mins - 1);
@ -47,6 +49,8 @@ fn calculate_base_reward(already_generated_coins: u64, hf: &HardFork) -> u64 {
} }
/// Calculates the miner reward for this block. /// Calculates the miner reward for this block.
///
/// ref: https://monero-book.cuprate.org/consensus_rules/blocks/reward.html#calculating-block-reward
pub fn calculate_block_reward( pub fn calculate_block_reward(
block_weight: usize, block_weight: usize,
median_bw: usize, median_bw: usize,
@ -71,7 +75,7 @@ pub fn calculate_block_reward(
/// Checks the miner transactions version. /// Checks the miner transactions version.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#version /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#version
fn check_miner_tx_version(tx_version: &TxVersion, hf: &HardFork) -> Result<(), MinerTxError> { fn check_miner_tx_version(tx_version: &TxVersion, hf: &HardFork) -> Result<(), MinerTxError> {
// The TxVersion enum checks if the version is not 1 or 2 // The TxVersion enum checks if the version is not 1 or 2
if hf >= &HardFork::V12 && tx_version != &TxVersion::RingCT { if hf >= &HardFork::V12 && tx_version != &TxVersion::RingCT {
@ -83,8 +87,7 @@ fn check_miner_tx_version(tx_version: &TxVersion, hf: &HardFork) -> Result<(), M
/// Checks the miner transactions inputs. /// Checks the miner transactions inputs.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#input /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#input
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#height
fn check_inputs(inputs: &[Input], chain_height: u64) -> Result<(), MinerTxError> { fn check_inputs(inputs: &[Input], chain_height: u64) -> Result<(), MinerTxError> {
if inputs.len() != 1 { if inputs.len() != 1 {
return Err(MinerTxError::IncorrectNumbOfInputs); return Err(MinerTxError::IncorrectNumbOfInputs);
@ -104,13 +107,13 @@ fn check_inputs(inputs: &[Input], chain_height: u64) -> Result<(), MinerTxError>
/// Checks the miner transaction has a correct time lock. /// Checks the miner transaction has a correct time lock.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#unlock-time /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#unlock-time
fn check_time_lock(time_lock: &Timelock, chain_height: u64) -> Result<(), MinerTxError> { fn check_time_lock(time_lock: &Timelock, chain_height: u64) -> Result<(), MinerTxError> {
match time_lock { match time_lock {
Timelock::Block(till_height) => { Timelock::Block(till_height) => {
// Lock times above this amount are timestamps not blocks. // Lock times above this amount are timestamps not blocks.
// This is just for safety though and shouldn't actually be hit. // This is just for safety though and shouldn't actually be hit.
if till_height >= &500_000_000 { if till_height > &500_000_000 {
Err(MinerTxError::InvalidLockTime)?; Err(MinerTxError::InvalidLockTime)?;
} }
if u64::try_from(*till_height).unwrap() != chain_height + MINER_TX_TIME_LOCKED_BLOCKS { if u64::try_from(*till_height).unwrap() != chain_height + MINER_TX_TIME_LOCKED_BLOCKS {
@ -125,7 +128,7 @@ fn check_time_lock(time_lock: &Timelock, chain_height: u64) -> Result<(), MinerT
/// Sums the outputs checking for overflow. /// Sums the outputs checking for overflow.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#output-amounts /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#output-amounts
fn sum_outputs(outputs: &[Output], hf: &HardFork) -> Result<u64, MinerTxError> { fn sum_outputs(outputs: &[Output], hf: &HardFork) -> Result<u64, MinerTxError> {
let mut sum: u64 = 0; let mut sum: u64 = 0;
for out in outputs { for out in outputs {
@ -140,7 +143,7 @@ fn sum_outputs(outputs: &[Output], hf: &HardFork) -> Result<u64, MinerTxError> {
/// Checks the total outputs amount is correct returning the amount of coins collected by the miner. /// Checks the total outputs amount is correct returning the amount of coins collected by the miner.
/// ///
/// https://cuprate.github.io/monero-book/consensus_rules/blocks/miner_tx.html#total-outputs /// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#total-outputs
fn check_total_output_amt( fn check_total_output_amt(
total_output: u64, total_output: u64,
reward: u64, reward: u64,
@ -160,6 +163,12 @@ fn check_total_output_amt(
} }
} }
/// Checks all miner transactions rules.
///
/// Excluding:
/// https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#v2-output-pool
///
/// as this needs to be done in a database.
pub fn check_miner_tx( pub fn check_miner_tx(
tx: &Transaction, tx: &Transaction,
total_fees: u64, total_fees: u64,
@ -172,6 +181,7 @@ pub fn check_miner_tx(
let tx_version = TxVersion::from_raw(tx.prefix.version).ok_or(MinerTxError::VersionInvalid)?; let tx_version = TxVersion::from_raw(tx.prefix.version).ok_or(MinerTxError::VersionInvalid)?;
check_miner_tx_version(&tx_version, hf)?; check_miner_tx_version(&tx_version, hf)?;
// ref: https://monero-book.cuprate.org/consensus_rules/blocks/miner_tx.html#ringct-type
if hf >= &HardFork::V12 && tx.rct_signatures.rct_type() != RctType::Null { if hf >= &HardFork::V12 && tx.rct_signatures.rct_type() != RctType::Null {
return Err(MinerTxError::RCTTypeNotNULL); return Err(MinerTxError::RCTTypeNotNULL);
} }

View file

@ -1,17 +1,18 @@
#![cfg(feature = "binaries")] #![cfg(feature = "binaries")]
use std::collections::{HashMap, HashSet}; use std::{
use std::ops::Deref; collections::{HashMap, HashSet},
use std::time::Duration; ops::Range,
use std::{ops::Range, path::PathBuf, sync::Arc}; path::PathBuf,
sync::Arc,
};
use clap::Parser; use clap::Parser;
use futures::{ use futures::{
channel::{mpsc, oneshot}, channel::{mpsc, oneshot},
SinkExt, StreamExt, TryFutureExt, SinkExt, StreamExt,
}; };
use monero_serai::{block::Block, transaction::Transaction}; use monero_serai::{block::Block, transaction::Transaction};
use rayon::prelude::*;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use tracing::level_filters::LevelFilter; use tracing::level_filters::LevelFilter;
@ -221,7 +222,7 @@ where
let mut randomx_vms: Option<HashMap<u64, RandomXVM>> = Some(HashMap::new()); let mut randomx_vms: Option<HashMap<u64, RandomXVM>> = Some(HashMap::new());
tokio::spawn(async move { tokio::spawn(async move {
while let Some(mut blocks) = incoming_blocks.next().await { while let Some(blocks) = incoming_blocks.next().await {
let unwrapped_rx_vms = randomx_vms.as_mut().unwrap(); let unwrapped_rx_vms = randomx_vms.as_mut().unwrap();
let blocks = rayon_spawn_async(move || { let blocks = rayon_spawn_async(move || {
@ -243,12 +244,9 @@ where
unwrapped_rx_vms.retain(|seed_height, _| seeds_needed.contains(seed_height)); unwrapped_rx_vms.retain(|seed_height, _| seeds_needed.contains(seed_height));
for seed_height in seeds_needed { for seed_height in seeds_needed {
if !unwrapped_rx_vms.contains_key(&seed_height) { unwrapped_rx_vms.entry(seed_height).or_insert_with(|| {
unwrapped_rx_vms.insert( RandomXVM::new(rx_seed_cache.get_seeds_hash(seed_height)).unwrap()
seed_height, });
RandomXVM::new(rx_seed_cache.get_seeds_hash(seed_height)).unwrap(),
);
}
} }
let arc_rx_vms = Arc::new(randomx_vms.take().unwrap()); let arc_rx_vms = Arc::new(randomx_vms.take().unwrap());

View file

@ -10,16 +10,14 @@ use monero_serai::block::Block;
use monero_serai::transaction::Input; use monero_serai::transaction::Input;
use tower::{Service, ServiceExt}; use tower::{Service, ServiceExt};
use monero_consensus::blocks::{BlockError, RandomX};
use monero_consensus::miner_tx::MinerTxError;
use monero_consensus::{ use monero_consensus::{
blocks::{calculate_pow_hash, check_block, check_block_pow}, blocks::{calculate_pow_hash, check_block, check_block_pow, BlockError, RandomX},
miner_tx::MinerTxError,
ConsensusError, HardFork, ConsensusError, HardFork,
}; };
use crate::{ use crate::{
context::{BlockChainContextRequest, BlockChainContextResponse}, context::{BlockChainContextRequest, BlockChainContextResponse},
helper::rayon_spawn_async,
transactions::{TransactionVerificationData, VerifyTxRequest, VerifyTxResponse}, transactions::{TransactionVerificationData, VerifyTxRequest, VerifyTxResponse},
ExtendedConsensusError, TxNotInPool, TxPoolRequest, TxPoolResponse, ExtendedConsensusError, TxNotInPool, TxPoolRequest, TxPoolResponse,
}; };
@ -294,10 +292,10 @@ where
} }
async fn verify_main_chain_block<C, TxV, TxP>( async fn verify_main_chain_block<C, TxV, TxP>(
block: Block, _block: Block,
context_svc: C, _context_svc: C,
tx_verifier_svc: TxV, _tx_verifier_svc: TxV,
tx_pool: TxP, _tx_pool: TxP,
) -> Result<VerifyBlockResponse, ExtendedConsensusError> ) -> Result<VerifyBlockResponse, ExtendedConsensusError>
where where
C: Service< C: Service<
@ -313,6 +311,9 @@ where
+ Send + Send
+ 'static, + 'static,
{ {
todo!("Single main chain block.");
/*
tracing::debug!("getting blockchain context"); tracing::debug!("getting blockchain context");
let BlockChainContextResponse::Context(checked_context) = context_svc let BlockChainContextResponse::Context(checked_context) = context_svc
.oneshot(BlockChainContextRequest::Get) .oneshot(BlockChainContextRequest::Get)
@ -379,4 +380,5 @@ where
hf_vote, hf_vote,
cumulative_difficulty: context.cumulative_difficulty + context.next_difficulty, cumulative_difficulty: context.cumulative_difficulty + context.next_difficulty,
})) }))
*/
} }

View file

@ -7,7 +7,6 @@ pub struct RandomXVM {
vms: ThreadLocal<VMInner>, vms: ThreadLocal<VMInner>,
cache: RandomXCache, cache: RandomXCache,
flags: RandomXFlag, flags: RandomXFlag,
seed: [u8; 32],
} }
impl RandomXVM { impl RandomXVM {
@ -20,7 +19,6 @@ impl RandomXVM {
vms: ThreadLocal::new(), vms: ThreadLocal::new(),
cache, cache,
flags, flags,
seed,
}) })
} }
} }