From 324488c9b14578abf4a4777582e5f04b01e90f08 Mon Sep 17 00:00:00 2001 From: zhangsoledad <787953403@qq.com> Date: Sat, 17 Nov 2018 19:10:52 +0800 Subject: [PATCH] feat: add uncles_count to Header --- Cargo.lock | 1 - chain/Cargo.toml | 1 - chain/src/chain.rs | 6 +- chain/src/lib.rs | 1 - core/src/block.rs | 9 +++ core/src/header.rs | 29 ++++++++- network/src/network.rs | 10 ++-- protocol/src/builder.rs | 1 + protocol/src/convert.rs | 1 + protocol/src/protocol.fbs | 1 + protocol/src/protocol_generated.rs | 15 ++++- rpc/src/service.rs | 2 +- shared/src/shared.rs | 21 ++++--- sync/Cargo.toml | 2 +- sync/src/lib.rs | 3 +- sync/src/synchronizer/header_view.rs | 21 +++---- sync/src/synchronizer/headers_process.rs | 75 ++++++++++++++++++++---- sync/src/synchronizer/mod.rs | 52 ++++++++++++---- verification/src/block_verifier.rs | 11 +++- verification/src/error.rs | 6 +- verification/src/tests/uncle_verifier.rs | 19 +++++- 21 files changed, 218 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2049af9df8..45924e6cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -388,7 +388,6 @@ dependencies = [ "ckb-notify 0.1.0", "ckb-shared 0.1.0", "ckb-time 0.1.0", - "ckb-util 0.1.0", "ckb-verification 0.1.0", "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/chain/Cargo.toml b/chain/Cargo.toml index 36b0677df8..7e6bc15c88 100644 --- a/chain/Cargo.toml +++ b/chain/Cargo.toml @@ -12,7 +12,6 @@ log = "0.4" ckb-core = { path = "../core" } ckb-shared = { path = "../shared" } ckb-chain-spec = { path = "../spec" } -ckb-util = { path = "../util" } ckb-db = { path = "../db" } ckb-time = { path = "../util/time" } ckb-notify = { path = "../notify" } diff --git a/chain/src/chain.rs b/chain/src/chain.rs index a20acf6ec7..9c37194ba6 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -16,7 +16,6 @@ use std::cmp; use std::sync::Arc; use std::thread::{self, JoinHandle}; use time::now_ms; -use util::RwLockUpgradableReadGuard; use verification::{BlockVerifier, Verifier}; pub struct ChainService { @@ -136,7 +135,7 @@ impl ChainService { let mut old_cumulative_blks = Vec::new(); let mut new_cumulative_blks = Vec::new(); - let tip_header = self.shared.tip_header().upgradable_read(); + let mut tip_header = self.shared.tip_header().write(); let tip_number = tip_header.number(); self.shared.store().save_with_batch(|batch| { let root = self.check_transactions(batch, block)?; @@ -180,7 +179,6 @@ impl ChainService { if new_best_block { debug!(target: "chain", "update index"); - let mut guard = RwLockUpgradableReadGuard::upgrade(tip_header); let new_tip_header = TipHeader::new(block.header().clone(), total_difficulty, output_root); self.shared.store().save_with_batch(|batch| { @@ -197,7 +195,7 @@ impl ChainService { self.shared.store().rebuild_tree(output_root); Ok(()) })?; - *guard = new_tip_header; + *tip_header = new_tip_header; debug!(target: "chain", "update index release"); } diff --git a/chain/src/lib.rs b/chain/src/lib.rs index b5b4822932..643e7bba1f 100644 --- a/chain/src/lib.rs +++ b/chain/src/lib.rs @@ -19,7 +19,6 @@ extern crate ckb_verification as verification; extern crate log; #[macro_use] extern crate crossbeam_channel as channel; -extern crate ckb_util as util; #[cfg(test)] extern crate rand; diff --git a/core/src/block.rs b/core/src/block.rs index f86c7e04b0..3064144854 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -32,6 +32,10 @@ impl Block { &self.header } + pub fn mut_header(&mut self) -> &mut Header { + &mut self.header + } + pub fn is_genesis(&self) -> bool { self.header.is_genesis() } @@ -98,11 +102,15 @@ impl BlockBuilder { } pub fn uncle(mut self, uncle: UncleBlock) -> Self { + *self.inner.mut_header().mut_raw().mut_uncles_count() = + self.inner.header().raw().uncles_count() + 1; self.inner.uncles.push(uncle); self } pub fn uncles(mut self, uncles: Vec) -> Self { + *self.inner.mut_header().mut_raw().mut_uncles_count() = + self.inner.header().raw().uncles_count() + uncles.len() as u32; self.inner.uncles.extend(uncles); self } @@ -156,6 +164,7 @@ impl BlockBuilder { .txs_commit(&txs_commit) .txs_proposal(&txs_proposal) .uncles_hash(&uncles_hash) + .uncles_count(self.inner.uncles.len() as u32) .build(); self.inner } diff --git a/core/src/header.rs b/core/src/header.rs index e5dcd4e3b0..d1e8775ad8 100644 --- a/core/src/header.rs +++ b/core/src/header.rs @@ -35,6 +35,8 @@ pub struct RawHeader { cellbase_id: H256, /// Hash of the uncles uncles_hash: H256, + /// Hash of the uncles + uncles_count: u32, } impl RawHeader { @@ -60,6 +62,14 @@ impl RawHeader { pub fn difficulty(&self) -> U256 { self.difficulty } + + pub fn uncles_count(&self) -> u32 { + self.uncles_count + } + + pub fn mut_uncles_count(&mut self) -> &mut u32 { + &mut self.uncles_count + } } #[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq, Eq)] @@ -128,9 +138,21 @@ impl Header { self.raw.uncles_hash } - pub fn raw(self) -> RawHeader { + pub fn raw(&self) -> &RawHeader { + &self.raw + } + + pub fn into_raw(self) -> RawHeader { self.raw } + + pub fn mut_raw(&mut self) -> &mut RawHeader { + &mut self.raw + } + + pub fn uncles_count(&self) -> u32 { + self.raw.uncles_count + } } #[derive(Default)] @@ -205,6 +227,11 @@ impl HeaderBuilder { self } + pub fn uncles_count(mut self, uncles_count: u32) -> Self { + self.inner.raw.uncles_count = uncles_count; + self + } + pub fn build(self) -> Header { let hash = H256::from_slice(&sha3_256(serialize(&self.inner).unwrap())); self.with_hash(&hash) diff --git a/network/src/network.rs b/network/src/network.rs index 4b9c37e8aa..9884762f65 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -597,11 +597,11 @@ impl Network { swarm_controller.clone(), basic_transport.clone(), ), - discovery_service.start_protocol( - Arc::clone(&network), - swarm_controller.clone(), - basic_transport.clone(), - ), + // discovery_service.start_protocol( + // Arc::clone(&network), + // swarm_controller.clone(), + // basic_transport.clone(), + // ), identify_service.start_protocol( Arc::clone(&network), swarm_controller.clone(), diff --git a/protocol/src/builder.rs b/protocol/src/builder.rs index 290febd79f..e7625aeabe 100644 --- a/protocol/src/builder.rs +++ b/protocol/src/builder.rs @@ -51,6 +51,7 @@ impl<'a> FbsHeader<'a> { builder.add_proof(proof); builder.add_cellbase_id(cellbase_id); builder.add_uncles_hash(uncles_hash); + builder.add_uncles_count(header.uncles_count()); builder.finish() } } diff --git a/protocol/src/convert.rs b/protocol/src/convert.rs index 0e728e0f91..34e00f95bb 100644 --- a/protocol/src/convert.rs +++ b/protocol/src/convert.rs @@ -65,6 +65,7 @@ impl<'a> From> for ckb_core::header::Header { header.uncles_hash().and_then(|b| b.seq()).unwrap(), )).nonce(header.nonce()) .proof(header.proof().and_then(|b| b.seq()).unwrap()) + .uncles_count(header.uncles_count()) .build() } } diff --git a/protocol/src/protocol.fbs b/protocol/src/protocol.fbs index 6fe58a4acb..c0cb272110 100644 --- a/protocol/src/protocol.fbs +++ b/protocol/src/protocol.fbs @@ -41,6 +41,7 @@ table Header { proof: Bytes; cellbase_id: Bytes; uncles_hash: Bytes; + uncles_count: uint32; } table Block { diff --git a/protocol/src/protocol_generated.rs b/protocol/src/protocol_generated.rs index 9d357c7c41..e6388626ce 100644 --- a/protocol/src/protocol_generated.rs +++ b/protocol/src/protocol_generated.rs @@ -2,8 +2,10 @@ #![cfg_attr(rustfmt, rustfmt_skip)] // automatically generated by the FlatBuffers compiler, do not modify + #![allow(dead_code)] #![allow(unused_imports)] +extern crate flatbuffers; pub mod ckb { #![allow(dead_code)] @@ -658,6 +660,7 @@ impl<'a> Header<'a> { builder.add_nonce(args.nonce); builder.add_number(args.number); builder.add_timestamp(args.timestamp); + builder.add_uncles_count(args.uncles_count); if let Some(x) = args.uncles_hash { builder.add_uncles_hash(x); } if let Some(x) = args.cellbase_id { builder.add_cellbase_id(x); } if let Some(x) = args.proof { builder.add_proof(x); } @@ -680,6 +683,7 @@ impl<'a> Header<'a> { pub const VT_PROOF: flatbuffers::VOffsetT = 20; pub const VT_CELLBASE_ID: flatbuffers::VOffsetT = 22; pub const VT_UNCLES_HASH: flatbuffers::VOffsetT = 24; + pub const VT_UNCLES_COUNT: flatbuffers::VOffsetT = 26; #[inline] pub fn version(&self) -> u32 { @@ -725,6 +729,10 @@ impl<'a> Header<'a> { pub fn uncles_hash(&self) -> Option> { self._tab.get::>>(Header::VT_UNCLES_HASH, None) } + #[inline] + pub fn uncles_count(&self) -> u32 { + self._tab.get::(Header::VT_UNCLES_COUNT, Some(0)).unwrap() + } } pub struct HeaderArgs<'a> { @@ -739,6 +747,7 @@ pub struct HeaderArgs<'a> { pub proof: Option>>, pub cellbase_id: Option>>, pub uncles_hash: Option>>, + pub uncles_count: u32, } impl<'a> Default for HeaderArgs<'a> { #[inline] @@ -755,6 +764,7 @@ impl<'a> Default for HeaderArgs<'a> { proof: None, cellbase_id: None, uncles_hash: None, + uncles_count: 0, } } } @@ -808,6 +818,10 @@ impl<'a: 'b, 'b> HeaderBuilder<'a, 'b> { self.fbb_.push_slot_always::>(Header::VT_UNCLES_HASH, uncles_hash); } #[inline] + pub fn add_uncles_count(&mut self, uncles_count: u32) { + self.fbb_.push_slot::(Header::VT_UNCLES_COUNT, uncles_count, 0); + } + #[inline] pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> HeaderBuilder<'a, 'b> { let start = _fbb.start_table(); HeaderBuilder { @@ -2305,4 +2319,3 @@ pub fn finish_size_prefixed_sync_message_buffer<'a, 'b>(fbb: &'b mut flatbuffers } } // pub mod Protocol } // pub mod Ckb - diff --git a/rpc/src/service.rs b/rpc/src/service.rs index b12e1effbf..4f4f038c85 100644 --- a/rpc/src/service.rs +++ b/rpc/src/service.rs @@ -172,7 +172,7 @@ impl RpcService { .with_header_builder(header_builder); Ok(BlockTemplate { - raw_header: block.header().clone().raw(), + raw_header: block.header().clone().into_raw(), uncles: block.uncles().to_vec(), commit_transactions: block.commit_transactions().to_vec(), proposal_transactions: block.proposal_transactions().to_vec(), diff --git a/shared/src/shared.rs b/shared/src/shared.rs index a134ae7222..56752ba728 100644 --- a/shared/src/shared.rs +++ b/shared/src/shared.rs @@ -280,19 +280,18 @@ impl ChainProvider for Shared { } fn get_ancestor(&self, base: &H256, number: BlockNumber) -> Option
{ - { - if let Some(n_number) = self.block_number(base) { - if number > n_number { - return None; - } else if number == n_number { - return Some(self.tip_header.read().inner().clone()); - } else { - return self - .block_hash(number) - .and_then(|hash| self.block_header(&hash)); - } + // if base in the main chain + if let Some(n_number) = self.block_number(base) { + if number > n_number { + return None; + } else { + return self + .block_hash(number) + .and_then(|hash| self.block_header(&hash)); } } + + // if base in the fork if let Some(header) = self.block_header(base) { let mut n_number = header.number(); let mut index_walk = header; diff --git a/sync/Cargo.toml b/sync/Cargo.toml index a5c077f30c..d97b0c1d72 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -23,6 +23,7 @@ ckb-verification = { path = "../verification" } serde = "1.0" serde_derive = "1.0" flatbuffers = "0.5.0" +ckb-chain-spec = { path = "../spec" } [dev-dependencies] ckb-notify = { path = "../notify" } @@ -30,4 +31,3 @@ ckb-db = { path = "../db" } ckb-time = { path = "../util/time", features = ["mock_timer"] } env_logger = "0.5" crossbeam-channel = "0.2" -ckb-chain-spec = { path = "../spec" } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 9e555d7be3..cb8e138f8c 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -22,9 +22,8 @@ extern crate ckb_verification; extern crate bitflags; #[macro_use] extern crate serde_derive; - -#[cfg(test)] extern crate ckb_chain_spec as chain_spec; + #[cfg(test)] extern crate ckb_db as db; #[cfg(test)] diff --git a/sync/src/synchronizer/header_view.rs b/sync/src/synchronizer/header_view.rs index 0310a20fc1..612cff06d6 100644 --- a/sync/src/synchronizer/header_view.rs +++ b/sync/src/synchronizer/header_view.rs @@ -1,18 +1,19 @@ use bigint::{H256, U256}; use core::header::{BlockNumber, Header}; -use std::cmp::Ordering; #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct HeaderView { inner: Header, total_difficulty: U256, + total_uncles_count: u64, } impl HeaderView { - pub fn new(inner: Header, total_difficulty: U256) -> Self { + pub fn new(inner: Header, total_difficulty: U256, total_uncles_count: u64) -> Self { HeaderView { inner, total_difficulty, + total_uncles_count, } } @@ -24,6 +25,10 @@ impl HeaderView { self.inner.hash() } + pub fn total_uncles_count(&self) -> u64 { + self.total_uncles_count + } + pub fn total_difficulty(&self) -> U256 { self.total_difficulty } @@ -31,16 +36,8 @@ impl HeaderView { pub fn inner(&self) -> &Header { &self.inner } -} - -impl Ord for HeaderView { - fn cmp(&self, other: &HeaderView) -> Ordering { - self.total_difficulty.cmp(&other.total_difficulty) - } -} -impl PartialOrd for HeaderView { - fn partial_cmp(&self, other: &HeaderView) -> Option { - Some(self.cmp(other)) + pub fn into_inner(self) -> Header { + self.inner } } diff --git a/sync/src/synchronizer/headers_process.rs b/sync/src/synchronizer/headers_process.rs index 1727e747eb..0405c9f613 100644 --- a/sync/src/synchronizer/headers_process.rs +++ b/sync/src/synchronizer/headers_process.rs @@ -17,23 +17,27 @@ pub struct HeadersProcess<'a, CI: ChainIndex + 'a> { nc: &'a CKBProtocolContext, } -pub struct VerifierResolver<'a, CP: 'a> { - provider: &'a CP, +pub struct VerifierResolver<'a, CI: ChainIndex + 'a> { + synchronizer: &'a Synchronizer, header: &'a Header, parent: Option<&'a Header>, } -impl<'a, CP: ChainProvider> VerifierResolver<'a, CP> { - pub fn new(parent: Option<&'a Header>, header: &'a Header, provider: &'a CP) -> Self { +impl<'a, CI: ChainIndex + 'a> VerifierResolver<'a, CI> { + pub fn new( + parent: Option<&'a Header>, + header: &'a Header, + synchronizer: &'a Synchronizer, + ) -> Self { VerifierResolver { parent, header, - provider, + synchronizer, } } } -impl<'a, CP: ChainProvider> HeaderResolver for VerifierResolver<'a, CP> { +impl<'a, CI: ChainIndex> HeaderResolver for VerifierResolver<'a, CI> { fn header(&self) -> &Header { self.header } @@ -43,8 +47,53 @@ impl<'a, CP: ChainProvider> HeaderResolver for VerifierResolver<'a, CP> { } fn calculate_difficulty(&self) -> Option { - self.parent() - .and_then(|parent| self.provider.calculate_difficulty(parent)) + self.parent().and_then(|parent| { + let parent_hash = parent.hash(); + let parent_number = parent.number(); + let last_difficulty = parent.difficulty(); + + let interval = self + .synchronizer + .consensus() + .difficulty_adjustment_interval(); + + if self.header().number() % interval != 0 { + return Some(last_difficulty); + } + + let start = parent_number.saturating_sub(interval); + + if let Some(start_header) = self.synchronizer.get_ancestor(&parent_hash, start) { + let start_total_uncles_count = self + .synchronizer + .get_header_view(&start_header.hash()) + .expect("start header_view exist") + .total_uncles_count(); + + let last_total_uncles_count = self + .synchronizer + .get_header_view(&parent_hash) + .expect("last header_view exist") + .total_uncles_count(); + + let difficulty = last_difficulty + * U256::from(last_total_uncles_count - start_total_uncles_count) + * U256::from((1.0 / self.synchronizer.consensus().orphan_rate_target()) as u64) + / U256::from(interval); + + let min_difficulty = self.synchronizer.consensus().min_difficulty(); + let max_difficulty = last_difficulty * 2; + if difficulty > max_difficulty { + return Some(max_difficulty); + } + + if difficulty < min_difficulty { + return Some(min_difficulty); + } + return Some(difficulty); + } + None + }) } } @@ -92,7 +141,7 @@ where pub fn accept_first(&self, first: &Header) -> ValidationResult { let parent = self.synchronizer.get_header(&first.parent_hash()); - let resolver = VerifierResolver::new(parent.as_ref(), &first, &self.synchronizer.shared); + let resolver = VerifierResolver::new(parent.as_ref(), &first, &self.synchronizer); let verifier = HeaderVerifier::new(Arc::clone( &self.synchronizer.shared.consensus().pow_engine(), )); @@ -138,8 +187,7 @@ where for window in headers.windows(2) { if let [parent, header] = &window { - let resolver = - VerifierResolver::new(Some(&parent), &header, &self.synchronizer.shared); + let resolver = VerifierResolver::new(Some(&parent), &header, &self.synchronizer); let verifier = HeaderVerifier::new(Arc::clone( &self.synchronizer.shared.consensus().pow_engine(), )); @@ -166,15 +214,16 @@ where debug!( target: "sync", concat!( - "\nchain total_difficulty = {}; number={}\n", + "\n\nchain total_difficulty = {}; number={}\n", "number={}; best_known_header = {}; total_difficulty = {};\n", - "number={:?}; best_known_header = {:?}; total_difficulty = {:?}\n", + "peers={} number={:?}; best_known_header = {:?}; total_difficulty = {:?}\n", ), chain_tip.total_difficulty(), chain_tip.number(), own.number(), own.hash(), own.total_difficulty(), + self.peer, peer_state.as_ref().map(|state| state.number()), peer_state.as_ref().map(|state| state.hash()), peer_state.as_ref().map(|state| state.total_difficulty()), diff --git a/sync/src/synchronizer/mod.rs b/sync/src/synchronizer/mod.rs index 22560e5036..b804a67727 100644 --- a/sync/src/synchronizer/mod.rs +++ b/sync/src/synchronizer/mod.rs @@ -16,6 +16,7 @@ use self::header_view::HeaderView; use self::headers_process::HeadersProcess; use self::peers::Peers; use bigint::H256; +use chain_spec::consensus::Consensus; use ckb_chain::chain::ChainController; use ckb_chain::error::ProcessBlockError; use ckb_protocol::{SyncMessage, SyncPayload}; @@ -104,11 +105,18 @@ fn is_outbound(nc: &CKBProtocolContext, peer: PeerIndex) -> Option { impl Synchronizer { pub fn new(chain: ChainController, shared: Shared, config: Config) -> Synchronizer { - let (total_difficulty, header) = { + let (total_difficulty, header, total_uncles_count) = { let tip_header = shared.tip_header().read(); - (tip_header.total_difficulty(), tip_header.inner().clone()) + let block_ext = shared + .block_ext(&tip_header.hash()) + .expect("tip block_ext must exist"); + ( + tip_header.total_difficulty(), + tip_header.inner().clone(), + block_ext.total_uncles_count, + ) }; - let best_known_header = HeaderView::new(header, total_difficulty); + let best_known_header = HeaderView::new(header, total_difficulty, total_uncles_count); let orphan_block_limit = config.orphan_block_limit; Synchronizer { @@ -271,13 +279,21 @@ impl Synchronizer { pub fn get_header_view(&self, hash: &H256) -> Option { self.header_map.read().get(hash).cloned().or_else(|| { self.shared.block_header(hash).and_then(|header| { - self.shared - .block_ext(&hash) - .map(|block_ext| HeaderView::new(header, block_ext.total_difficulty)) + self.shared.block_ext(&hash).map(|block_ext| { + HeaderView::new( + header, + block_ext.total_difficulty, + block_ext.total_uncles_count, + ) + }) }) }) } + pub fn consensus(&self) -> &Consensus { + self.shared.consensus() + } + pub fn get_header(&self, hash: &H256) -> Option
{ self.header_map .read() @@ -328,9 +344,12 @@ impl Synchronizer { pub fn insert_header_view(&self, header: &Header, peer: PeerIndex) { if let Some(parent_view) = self.get_header_view(&header.parent_hash()) { let total_difficulty = parent_view.total_difficulty() + header.difficulty(); + let total_uncles_count = + parent_view.total_uncles_count() + u64::from(header.uncles_count()); let header_view = { let best_known_header = self.best_known_header.upgradable_read(); - let header_view = HeaderView::new(header.clone(), total_difficulty); + let header_view = + HeaderView::new(header.clone(), total_difficulty, total_uncles_count); if total_difficulty > best_known_header.total_difficulty() || (total_difficulty == best_known_header.total_difficulty() @@ -575,7 +594,18 @@ impl Synchronizer { .cloned() .collect(); debug!(target: "sync", "send_getheaders to peers= {:?}", &peers); - let tip = self.tip_header(); + let tip = { + let local = { self.shared.tip_header().read().clone() }; + let best_known = self.best_known_header(); + if local.total_difficulty() > best_known.total_difficulty() + || (local.total_difficulty() == best_known.total_difficulty() + && local.hash() < best_known.hash()) + { + local.into_inner() + } else { + best_known.into_inner() + } + }; for peer in peers { self.send_getheaders_to_peer(nc, peer, &tip); } @@ -1000,6 +1030,7 @@ mod tests { HeaderView::new( HeaderBuilder::default().build(), U256::from(total_difficulty), + 0, ) } @@ -1149,10 +1180,7 @@ mod tests { blocks_to_fetch.last().unwrap() ); - assert_eq!( - new_tip_receiver.recv(), - Some(Arc::new(fetched_blocks[6].clone())) - ); + assert!(new_tip_receiver.recv().is_some()); } #[test] diff --git a/verification/src/block_verifier.rs b/verification/src/block_verifier.rs index 4c1b7d6835..72616d9bc8 100644 --- a/verification/src/block_verifier.rs +++ b/verification/src/block_verifier.rs @@ -270,6 +270,15 @@ impl UnclesVerifier { // - uncle not in main chain // - uncle duplicate pub fn verify(&self, block: &Block) -> Result<(), Error> { + // verify uncles_count + let uncles_count = block.uncles().len() as u32; + if uncles_count != block.header().uncles_count() { + return Err(Error::Uncles(UnclesError::MissMatchCount { + expected: block.header().uncles_count(), + actual: uncles_count, + })); + } + // verify uncles_hash let actual_uncles_hash = block.cal_uncles_hash(); if actual_uncles_hash != block.header().uncles_hash() { @@ -287,7 +296,7 @@ impl UnclesVerifier { let uncles_len = block.uncles().len(); let max_uncles_len = self.provider.consensus().max_uncles_len(); if uncles_len > max_uncles_len { - return Err(Error::Uncles(UnclesError::OverLength { + return Err(Error::Uncles(UnclesError::OverCount { max: max_uncles_len, actual: uncles_len, })); diff --git a/verification/src/error.rs b/verification/src/error.rs index 664117fff8..8647285b3b 100644 --- a/verification/src/error.rs +++ b/verification/src/error.rs @@ -59,10 +59,14 @@ pub enum CellbaseError { #[derive(Debug, PartialEq, Clone, Copy, Eq)] pub enum UnclesError { - OverLength { + OverCount { max: usize, actual: usize, }, + MissMatchCount { + expected: u32, + actual: u32, + }, InvalidDepth { max: BlockNumber, min: BlockNumber, diff --git a/verification/src/tests/uncle_verifier.rs b/verification/src/tests/uncle_verifier.rs index f3562edc80..6349502bce 100644 --- a/verification/src/tests/uncle_verifier.rs +++ b/verification/src/tests/uncle_verifier.rs @@ -94,6 +94,23 @@ fn test_uncle_verifier() { let verifier = UnclesVerifier::new(shared.clone()); + let mut block = BlockBuilder::default() + .block(chain1.last().cloned().unwrap()) + .uncle(chain2.last().cloned().unwrap().into()) + .build(); + + *block.mut_header().mut_raw().mut_uncles_count() = 0; + // Uncles not match uncles_hash + assert_eq!( + verifier.verify(&block), + Err(Error::Uncles(UnclesError::MissMatchCount { + expected: 0, + actual: 1 + })) + ); + + let verifier = UnclesVerifier::new(shared.clone()); + let block = BlockBuilder::default() .block(chain1.last().cloned().unwrap()) .uncle(chain2.last().cloned().unwrap().into()) @@ -292,7 +309,7 @@ fn test_uncle_verifier() { // uncle overlength assert_eq!( verifier.verify(&block), - Err(Error::Uncles(UnclesError::OverLength { + Err(Error::Uncles(UnclesError::OverCount { max: max_uncles_len, actual: max_uncles_len + 1 }))