From ecda870d70179a58a54f8bf8e1f0c9480d333374 Mon Sep 17 00:00:00 2001 From: antiochp <30642645+antiochp@users.noreply.github.com> Date: Mon, 22 Jan 2018 13:45:47 -0500 Subject: [PATCH] add block validation consensus rule for block coinbase output and kernel counts --- core/src/consensus.rs | 14 ++++++++++++-- core/src/core/block.rs | 25 ++++++++++++++++++++----- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/core/src/consensus.rs b/core/src/consensus.rs index a960d9257..8cf31a613 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -44,6 +44,16 @@ pub fn reward(fee: u64) -> u64 { /// Number of blocks before a coinbase matures and can be spent pub const COINBASE_MATURITY: u64 = 1_000; +/// Max number of coinbase outputs in a valid block. +/// This is to prevent a miner generating an excessively large "compact block". +/// But we do techincally support blocks with multiple coinbase outputs/kernels. +pub const MAX_BLOCK_COINBASE_OUTPUTS: u64 = 1; + +/// Max number of coinbase kernels in a valid block. +/// This is to prevent a miner generating an excessively large "compact block". +/// But we do techincally support blocks with multiple coinbase outputs/kernels. +pub const MAX_BLOCK_COINBASE_KERNELS: u64 = 1; + /// Block interval, in seconds, the network will tune its next_target for. Note /// that we may reduce this value in the future as we get more data on mining /// with Cuckoo Cycle, networks improve and block propagation is optimized @@ -209,7 +219,7 @@ where let end_ts = window_end[window_end.len() / 2]; // Average difficulty and dampened average time - let diff_avg = diff_sum.into_num() as f64 / + let diff_avg = diff_sum.into_num() as f64 / Difficulty::from_num(DIFFICULTY_ADJUST_WINDOW).into_num() as f64; let ts_damp = (3 * BLOCK_TIME_WINDOW + (begin_ts - end_ts)) / 4; @@ -223,7 +233,7 @@ where }; let difficulty = - diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW).into_num() as f64 + diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW).into_num() as f64 / Difficulty::from_num(adj_ts).into_num() as f64; // All this ceil and f64 business is so that difficulty can always adjust // for smaller numbers < 10 diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 597850960..16743018f 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -73,6 +73,10 @@ pub enum Error { /// The lock_height needed to be reached for the coinbase output to mature lock_height: u64, }, + /// Limit on number of coinbase outputs in a valid block. + CoinbaseOutputCountExceeded, + /// Limit on number of coinbase kernels in a valid block. + CoinbaseKernelCountExceeded, /// Other unspecified error condition Other(String) } @@ -674,11 +678,12 @@ impl Block { Ok(()) } - // Validate the coinbase outputs generated by miners. Entails 2 main checks: - // - // * That the sum of all coinbase-marked outputs equal the supply. - // * That the sum of blinding factors for all coinbase-marked outputs match - // the coinbase-marked kernels. + /// Validate the coinbase outputs generated by miners. Entails 3 main checks: + /// + /// * That the block does not exceed the number of permitted coinbase outputs or kernels. + /// * That the sum of all coinbase-marked outputs equal the supply. + /// * That the sum of blinding factors for all coinbase-marked outputs match + /// the coinbase-marked kernels. fn verify_coinbase(&self) -> Result<(), Error> { let cb_outs = self.outputs .iter() @@ -692,6 +697,16 @@ impl Block { .cloned() .collect::>(); + // First check that we do not have too many coinbase outputs in the block. + if cb_outs.len() as u64 > consensus::MAX_BLOCK_COINBASE_OUTPUTS { + return Err(Error::CoinbaseOutputCountExceeded); + } + + // And that we do not have too many coinbase kernels in the block. + if cb_kerns.len() as u64 > consensus::MAX_BLOCK_COINBASE_KERNELS { + return Err(Error::CoinbaseKernelCountExceeded); + } + let over_commit; let out_adjust_sum; let kerns_sum;