From b07ad5fa3dc788bbeb36de03725eba38748c8a65 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 13 Apr 2018 21:14:22 +0800 Subject: [PATCH 01/64] Add light client TODO item --- ethcore/light/src/client/header_chain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 84b7916eef8..d7e1db68471 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -446,6 +446,7 @@ impl HeaderChain { let raw = header.encoded().into_inner(); transaction.put_vec(self.col, &hash[..], raw); + // TODO: For engines when required, use cryptoeconomic guarantees. let (best_num, is_new_best) = { let cur_best = self.best_block.read(); if cur_best.total_difficulty < total_difficulty { From 3c891b921a9a5dd4af811cf29e943b38e8fce624 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 13 Apr 2018 22:49:11 +0800 Subject: [PATCH 02/64] Move existing total-difficulty-based fork choice check to Engine --- ethcore/src/blockchain/blockchain.rs | 73 ++++++++++----------- ethcore/src/client/client.rs | 7 +- ethcore/src/engines/mod.rs | 12 ++++ ethcore/src/snapshot/tests/proof_of_work.rs | 2 +- ethcore/src/test_helpers.rs | 4 +- 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5dffc9ec371..853a88f3755 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -896,7 +896,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, is_new_best: bool) -> ImportRoute { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -915,7 +915,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header); + let info = self.block_info(&header, is_new_best); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -940,12 +940,11 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView) -> BlockInfo { + fn block_info(&self, header: &HeaderView, is_new_best: bool) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let is_new_best = parent_details.total_difficulty + header.difficulty() > self.best_block_total_difficulty(); BlockInfo { hash: hash, @@ -1451,7 +1450,7 @@ mod tests { // when let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + bc.insert_block(&mut batch, &first.last().encoded(), vec![], true); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1481,7 +1480,7 @@ mod tests { assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.encoded(), vec![]); + bc.insert_block(&mut batch, &first.encoded(), vec![], true); db.write(batch).unwrap(); bc.commit(); @@ -1507,7 +1506,7 @@ mod tests { let mut batch = db.transaction(); for block in generator { block_hashes.push(block.hash()); - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], true); bc.commit(); } db.write(batch).unwrap(); @@ -1547,14 +1546,10 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis.last().encoded(), db.clone()); - let mut batch = db.transaction(); for b in generator { - bc.insert_block(&mut batch, &b.encoded(), vec![]); - bc.commit(); + insert_block(&db, &bc, &b.encoded(), vec![]); } - db.write(batch).unwrap(); - assert_eq!(uncle_headers, bc.find_uncle_headers(&b4a_hash, 3).unwrap()); // TODO: insert block that already includes one of them as an uncle to check it's not allowed. } @@ -1588,9 +1583,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![], true); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![], false); bc.commit(); db.write(batch).unwrap(); @@ -1602,7 +1597,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); bc.commit(); db.write(batch).unwrap(); @@ -1663,9 +1658,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![], true); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![], false); bc.commit(); db.write(batch).unwrap(); @@ -1681,7 +1676,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); bc.commit(); db.write(batch).unwrap(); @@ -1721,16 +1716,16 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![]); + let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![], true); bc.commit(); - let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![]); + let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); bc.commit(); - let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![]); + let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![], true); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); let mut batch = db.transaction(); - let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![]); + let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![], true); bc.commit(); db.write(batch).unwrap(); @@ -1835,7 +1830,7 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![]); + bc.insert_block(&mut batch, &first.last().encoded(), vec![], true); db.write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); @@ -1894,7 +1889,7 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); - bc.insert_block(&mut batch, &b1, vec![]); + bc.insert_block(&mut batch, &b1, vec![], true); db.write(batch).unwrap(); bc.commit(); @@ -1906,8 +1901,16 @@ mod tests { } fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + use views::BlockView; + + let block = BlockView::new(bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let is_new_best = parent_details.total_difficulty + header.difficulty() > bc.best_block_total_difficulty(); + let mut batch = db.transaction(); - let res = bc.insert_block(&mut batch, bytes, receipts); + let res = bc.insert_block(&mut batch, bytes, receipts, is_new_best); db.write(batch).unwrap(); bc.commit(); res @@ -2158,12 +2161,12 @@ mod tests { let mut batch = db.transaction(); // create a longer fork for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], true); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + bc.insert_block(&mut batch, &uncle.last().encoded(), vec![], false); db.write(batch).unwrap(); bc.commit(); } @@ -2190,7 +2193,7 @@ mod tests { // create a longer fork for (i, block) in generator.into_iter().enumerate() { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], true); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2201,7 +2204,7 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![]); + bc.insert_block(&mut batch, &uncle.last().encoded(), vec![], false); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, @@ -2251,11 +2254,7 @@ mod tests { // and a non-canonical fork of 8 from genesis. let fork_hash = { for block in fork_generator { - let mut batch = db.transaction(); - - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 7); @@ -2263,11 +2262,7 @@ mod tests { }; for block in next_generator { - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &block.encoded(), vec![]); - bc.commit(); - - db.write(batch).unwrap(); + insert_block(&db, &bc, &block.encoded(), vec![]); } assert_eq!(bc.best_block_number(), 10); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a8ce3f65c3c..28212446364 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -497,6 +497,8 @@ impl Importer { // // The header passed is from the original block data and is sealed. fn commit_block(&self, block: B, header: &Header, block_data: &[u8], client: &Client) -> ImportRoute where B: IsBlock + Drain { + use std::ops::Deref; + let hash = &header.hash(); let number = header.number(); let parent = header.parent_hash(); @@ -530,7 +532,8 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let route = chain.insert_block(&mut batch, block_data, receipts.clone()); + let is_new_best = client.engine.is_new_best(block_data, chain.best_block_total_difficulty(), chain.deref().deref()); + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), is_new_best); client.tracedb.read().import(&mut batch, TraceImportRequest { traces: traces.into(), @@ -2256,7 +2259,7 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new()); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), true); go_thread.store(true, Ordering::SeqCst); }); go diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 65fa13b54e8..de948b12d11 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -49,6 +49,8 @@ use header::{Header, BlockNumber}; use snapshot::SnapshotComponents; use spec::CommonParams; use transaction::{UnverifiedTransaction, SignedTransaction}; +use views::BlockView; +use blockchain::BlockProvider; use ethkey::Signature; use parity_machine::{Machine, LocalizedMachine as Localized}; @@ -338,6 +340,16 @@ pub trait Engine: Sync + Send { fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp > parent_timestamp } + + /// Check whether a given block is the best block. + fn is_new_best(&self, bytes: &[u8], best_block_total_difficulty: U256, provider: &BlockProvider) -> bool { + let block = BlockView::new(bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + + parent_details.total_difficulty + header.difficulty() > best_block_total_difficulty + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index e41b61e6e06..2972b8e4fee 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -49,7 +49,7 @@ fn chunk_and_restore(amount: u64) { // build the blockchain. let mut batch = DBTransaction::new(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![]); + bc.insert_block(&mut batch, &block.encoded(), vec![], true); bc.commit(); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 4c013dd251d..55f2ba0dd9a 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -268,7 +268,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![]); + bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], true); bc.commit(); } db.write(batch).unwrap(); @@ -283,7 +283,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![]); + bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], true); bc.commit(); } db.write(batch).unwrap(); From d2723761141c92ce835033cde72ff77f9832c059 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 17:37:42 +0800 Subject: [PATCH 03/64] Abstract total difficulty and block provider as Machine::BlockMetadata and Machine::BlockProvider --- ethcore/src/client/client.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 4 ++++ ethcore/src/engines/basic_authority.rs | 4 ++++ ethcore/src/engines/instant_seal.rs | 4 ++++ ethcore/src/engines/mod.rs | 17 ++++++++++------- ethcore/src/engines/null_engine.rs | 4 ++++ ethcore/src/engines/tendermint/mod.rs | 4 ++++ ethcore/src/ethereum/ethash.rs | 4 ++++ ethcore/src/machine.rs | 2 ++ machine/src/lib.rs | 4 ++++ 10 files changed, 41 insertions(+), 8 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 28212446364..a8df9861466 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -532,7 +532,7 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let is_new_best = client.engine.is_new_best(block_data, chain.best_block_total_difficulty(), chain.deref().deref()); + let is_new_best = client.engine.is_new_best(block_data, &chain.best_block_total_difficulty(), chain.deref().deref()); let route = chain.insert_block(&mut batch, block_data, receipts.clone(), is_new_best); client.tracedb.read().import(&mut batch, TraceImportRequest { diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 8282e5738a8..01fdb751147 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1315,6 +1315,10 @@ impl Engine for AuthorityRound { Some(Box::new(::snapshot::PoaSnapshot)) } } + + fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + } } #[cfg(test)] diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index c4eafd851c6..20be7ba9de0 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -191,6 +191,10 @@ impl Engine for BasicAuthority { fn snapshot_components(&self) -> Option> { None } + + fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + } } #[cfg(test)] diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 40a96e2b713..2bccd377891 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -61,6 +61,10 @@ impl Engine for InstantSeal fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp >= parent_timestamp } + + fn is_new_best(&self, _bytes: &[u8], _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { + true + } } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index de948b12d11..7917349a8eb 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -342,14 +342,17 @@ pub trait Engine: Sync + Send { } /// Check whether a given block is the best block. - fn is_new_best(&self, bytes: &[u8], best_block_total_difficulty: U256, provider: &BlockProvider) -> bool { - let block = BlockView::new(bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + fn is_new_best(&self, bytes: &[u8], best_block_metadata: &M::BlockMetadata, provider: &M::BlockProvider) -> bool; +} - parent_details.total_difficulty + header.difficulty() > best_block_total_difficulty - } +/// Check whether a given block is the best block based on the default total difficulty rule. +pub fn total_difficulty_is_new_best(bytes: &[u8], best_block_total_difficulty: U256, provider: &BlockProvider) -> bool { + let block = BlockView::new(bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + + parent_details.total_difficulty + header.difficulty() > best_block_total_difficulty } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index f20a9cdfd9d..572ddfa2008 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -105,4 +105,8 @@ impl Engine for NullEngine { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } + + fn is_new_best(&self, _bytes: &[u8], _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { + true + } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 011e3f8d425..a26a6c7b507 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -769,6 +769,10 @@ impl Engine for Tendermint { *self.client.write() = Some(client.clone()); self.validators.register_client(client); } + + fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + } } #[cfg(test)] diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 41ab777d4a7..b21ee702ec8 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -365,6 +365,10 @@ impl Engine for Arc { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } + + fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + engines::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + } } impl Ethash { diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index fa6a62454e1..3cc5b925c87 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -409,6 +409,8 @@ impl ::parity_machine::Machine for EthereumMachine { type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; type AuxiliaryRequest = AuxiliaryRequest; + type BlockProvider = ::blockchain::BlockProvider; + type BlockMetadata = U256; type Error = Error; } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 3a45c38d2ef..ab29962a8df 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -81,8 +81,12 @@ pub trait Machine: for<'a> LocalizedMachine<'a> { type LiveBlock: LiveBlock; /// A handle to a blockchain client for this machine. type EngineClient: ?Sized; + /// A handle to the block provider for this machine. + type BlockProvider: ?Sized; /// A description of needed auxiliary data. type AuxiliaryRequest; + /// Extra data related to consensus rules stored together with each block. + type BlockMetadata; /// Errors which can occur when querying or interacting with the machine. type Error; From c4d349cfb82b5c501db463a2e94a9dae3135a526 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 18:28:28 +0800 Subject: [PATCH 04/64] Decouple "generate_metadata" logic to Engine --- ethcore/src/blockchain/blockchain.rs | 92 ++++++++++++--------- ethcore/src/client/client.rs | 8 +- ethcore/src/engines/authority_round/mod.rs | 8 +- ethcore/src/engines/basic_authority.rs | 8 +- ethcore/src/engines/instant_seal.rs | 9 +- ethcore/src/engines/mod.rs | 16 +++- ethcore/src/engines/null_engine.rs | 10 ++- ethcore/src/engines/tendermint/mod.rs | 8 +- ethcore/src/ethereum/ethash.rs | 8 +- ethcore/src/snapshot/tests/proof_of_work.rs | 4 +- ethcore/src/test_helpers.rs | 6 +- 11 files changed, 114 insertions(+), 63 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 853a88f3755..79be2a57a10 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -896,7 +896,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, is_new_best: bool) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, metadata: U256, is_new_best: bool) -> ImportRoute { // create views onto rlp let block = BlockView::new(bytes); let header = block.header_view(); @@ -915,7 +915,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header, is_new_best); + let info = self.block_info(&header, metadata, is_new_best); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -940,7 +940,7 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView, is_new_best: bool) -> BlockInfo { + fn block_info(&self, header: &HeaderView, metadata: U256, is_new_best: bool) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); @@ -949,7 +949,7 @@ impl BlockChain { BlockInfo { hash: hash, number: number, - total_difficulty: parent_details.total_difficulty + header.difficulty(), + total_difficulty: metadata, location: if is_new_best { // on new best block we need to make sure that all ancestors // are moved to "canon chain" @@ -1415,7 +1415,7 @@ mod tests { use std::sync::Arc; use rustc_hex::FromHex; use hash::keccak; - use kvdb::KeyValueDB; + use kvdb::{KeyValueDB, DBTransaction}; use kvdb_memorydb; use ethereum_types::*; use receipt::{Receipt, TransactionOutcome}; @@ -1438,6 +1438,33 @@ mod tests { BlockChain::new(Config::default(), genesis, db) } + fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + insert_block_commit(db, bc, bytes, receipts, true) + } + + fn insert_block_commit(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec, commit: bool) -> ImportRoute { + let mut batch = db.transaction(); + let res = insert_block_batch(&mut batch, bc, bytes, receipts); + db.write(batch).unwrap(); + if commit { + bc.commit(); + } + res + } + + fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { + use views::BlockView; + + let block = BlockView::new(bytes); + let header = block.header_view(); + let parent_hash = header.parent_hash(); + let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); + let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); + let is_new_best = block_total_difficulty > bc.best_block_total_difficulty(); + + bc.insert_block(batch, bytes, receipts, block_total_difficulty, is_new_best) + } + #[test] fn should_cache_best_block() { // given @@ -1449,8 +1476,7 @@ mod tests { assert_eq!(bc.best_block_number(), 0); // when - let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![], true); + insert_block_commit(&db, &bc, &first.last().encoded(), vec![], false); assert_eq!(bc.best_block_number(), 0); bc.commit(); // NOTE no db.write here (we want to check if best block is cached) @@ -1480,7 +1506,7 @@ mod tests { assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.encoded(), vec![], true); + insert_block_batch(&mut batch, &bc, &first.encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1506,7 +1532,7 @@ mod tests { let mut batch = db.transaction(); for block in generator { block_hashes.push(block.hash()); - bc.insert_block(&mut batch, &block.encoded(), vec![], true); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } db.write(batch).unwrap(); @@ -1583,9 +1609,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![], true); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![], false); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1597,7 +1623,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1658,9 +1684,9 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b1a.last().encoded(), vec![], true); + let _ = insert_block_batch(&mut batch, &bc, &b1a.last().encoded(), vec![]); bc.commit(); - let _ = bc.insert_block(&mut batch, &b1b.last().encoded(), vec![], false); + let _ = insert_block_batch(&mut batch, &bc, &b1b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1676,7 +1702,7 @@ mod tests { // now let's make forked chain the canon chain let mut batch = db.transaction(); - let _ = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); + let _ = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1716,16 +1742,16 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); let mut batch = db.transaction(); - let ir1 = bc.insert_block(&mut batch, &b1.last().encoded(), vec![], true); + let ir1 = insert_block_batch(&mut batch, &bc, &b1.last().encoded(), vec![]); bc.commit(); - let ir2 = bc.insert_block(&mut batch, &b2.last().encoded(), vec![], true); + let ir2 = insert_block_batch(&mut batch, &bc, &b2.last().encoded(), vec![]); bc.commit(); - let ir3b = bc.insert_block(&mut batch, &b3b.last().encoded(), vec![], true); + let ir3b = insert_block_batch(&mut batch, &bc, &b3b.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); assert_eq!(bc.block_hash(3).unwrap(), b3b_hash); let mut batch = db.transaction(); - let ir3a = bc.insert_block(&mut batch, &b3a.last().encoded(), vec![], true); + let ir3a = insert_block_batch(&mut batch, &bc, &b3a.last().encoded(), vec![]); bc.commit(); db.write(batch).unwrap(); @@ -1830,7 +1856,7 @@ mod tests { let bc = new_chain(&genesis.last().encoded(), db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch = db.transaction(); - bc.insert_block(&mut batch, &first.last().encoded(), vec![], true); + insert_block_batch(&mut batch, &bc, &first.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); assert_eq!(bc.best_block_hash(), first_hash); @@ -1889,7 +1915,7 @@ mod tests { let db = new_db(); let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); - bc.insert_block(&mut batch, &b1, vec![], true); + insert_block_batch(&mut batch, &bc, &b1, vec![]); db.write(batch).unwrap(); bc.commit(); @@ -1900,22 +1926,6 @@ mod tests { } } - fn insert_block(db: &Arc, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { - use views::BlockView; - - let block = BlockView::new(bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let is_new_best = parent_details.total_difficulty + header.difficulty() > bc.best_block_total_difficulty(); - - let mut batch = db.transaction(); - let res = bc.insert_block(&mut batch, bytes, receipts, is_new_best); - db.write(batch).unwrap(); - bc.commit(); - res - } - #[test] fn test_logs() { let t1 = Transaction { @@ -2161,12 +2171,12 @@ mod tests { let mut batch = db.transaction(); // create a longer fork for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![], true); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.commit(); } assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![], false); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); db.write(batch).unwrap(); bc.commit(); } @@ -2193,7 +2203,7 @@ mod tests { // create a longer fork for (i, block) in generator.into_iter().enumerate() { - bc.insert_block(&mut batch, &block.encoded(), vec![], true); + insert_block_batch(&mut batch, &bc, &block.encoded(), vec![]); bc.insert_epoch_transition(&mut batch, i as u64, EpochTransition { block_hash: block.hash(), block_number: i as u64 + 1, @@ -2204,7 +2214,7 @@ mod tests { assert_eq!(bc.best_block_number(), 5); - bc.insert_block(&mut batch, &uncle.last().encoded(), vec![], false); + insert_block_batch(&mut batch, &bc, &uncle.last().encoded(), vec![]); bc.insert_epoch_transition(&mut batch, 999, EpochTransition { block_hash: uncle.last().hash(), block_number: 1, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a8df9861466..5bd3a44f9c5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -532,8 +532,9 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let is_new_best = client.engine.is_new_best(block_data, &chain.best_block_total_difficulty(), chain.deref().deref()); - let route = chain.insert_block(&mut batch, block_data, receipts.clone(), is_new_best); + let block_metadata = client.engine.generate_metadata(block_data, chain.deref().deref()); + let is_new_best = client.engine.is_new_best(block_data, &block_metadata, &chain.best_block_total_difficulty(), chain.deref().deref()); + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), block_metadata, is_new_best); client.tracedb.read().import(&mut batch, TraceImportRequest { traces: traces.into(), @@ -2247,6 +2248,7 @@ mod tests { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; + use ethereum_types::U256; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; @@ -2259,7 +2261,7 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), true); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), U256::zero(), true); go_thread.store(true, Ordering::SeqCst); }); go diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 01fdb751147..4f0ec475af3 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1316,8 +1316,12 @@ impl Engine for AuthorityRound { } } - fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { + super::total_difficulty_generate_metadata(bytes, provider) + } + + fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 20be7ba9de0..18a323c3dd0 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,8 +192,12 @@ impl Engine for BasicAuthority { None } - fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { + super::total_difficulty_generate_metadata(bytes, provider) + } + + fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 2bccd377891..5159cd34ac6 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -33,7 +33,8 @@ impl InstantSeal { } impl Engine for InstantSeal - where M::LiveBlock: Transactions + where M::LiveBlock: Transactions, + M::BlockMetadata: Default { fn name(&self) -> &str { "InstantSeal" @@ -62,7 +63,11 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn is_new_best(&self, _bytes: &[u8], _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { + fn generate_metadata(&self, _bytes: &[u8], _provider: &M::BlockProvider) -> M::BlockMetadata { + M::BlockMetadata::default() + } + + fn is_new_best(&self, _bytes: &[u8], _block_metadata: &M::BlockMetadata, _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { true } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 7917349a8eb..d40076c0d45 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -341,18 +341,26 @@ pub trait Engine: Sync + Send { header_timestamp > parent_timestamp } + /// Generate metadata for a new block. + fn generate_metadata(&self, bytes: &[u8], provider: &M::BlockProvider) -> M::BlockMetadata; + /// Check whether a given block is the best block. - fn is_new_best(&self, bytes: &[u8], best_block_metadata: &M::BlockMetadata, provider: &M::BlockProvider) -> bool; + fn is_new_best(&self, bytes: &[u8], block_metadata: &M::BlockMetadata, best_block_metadata: &M::BlockMetadata, provider: &M::BlockProvider) -> bool; } -/// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_is_new_best(bytes: &[u8], best_block_total_difficulty: U256, provider: &BlockProvider) -> bool { +/// Generate metadata for a new block based on the default total difficulty rule. +pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider) -> U256 { let block = BlockView::new(bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - parent_details.total_difficulty + header.difficulty() > best_block_total_difficulty + parent_details.total_difficulty + header.difficulty() +} + +/// Check whether a given block is the best block based on the default total difficulty rule. +pub fn total_difficulty_is_new_best(_bytes: &[u8], block_total_difficulty: U256, best_block_total_difficulty: U256, _provider: &BlockProvider) -> bool { + block_total_difficulty > best_block_total_difficulty } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 572ddfa2008..d979f64ceb4 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -56,7 +56,9 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine + where M::BlockMetadata: Default +{ fn name(&self) -> &str { "NullEngine" } @@ -106,7 +108,11 @@ impl Engine for NullEngine { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn is_new_best(&self, _bytes: &[u8], _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { + fn generate_metadata(&self, _bytes: &[u8], _provider: &M::BlockProvider) -> M::BlockMetadata { + M::BlockMetadata::default() + } + + fn is_new_best(&self, _bytes: &[u8], _block_metadata: &M::BlockMetadata, _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { true } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index a26a6c7b507..e625adff86e 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -770,8 +770,12 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { + super::total_difficulty_generate_metadata(bytes, provider) + } + + fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index b21ee702ec8..3b82576d032 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -366,8 +366,12 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn is_new_best(&self, bytes: &[u8], best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - engines::total_difficulty_is_new_best(bytes, *best_block_metadata, provider) + fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { + engines::total_difficulty_generate_metadata(bytes, provider) + } + + fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { + engines::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 2972b8e4fee..8a9216a245f 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -48,8 +48,10 @@ fn chunk_and_restore(amount: u64) { // build the blockchain. let mut batch = DBTransaction::new(); + let mut total_difficulty = *genesis.header.difficulty(); for block in generator { - bc.insert_block(&mut batch, &block.encoded(), vec![], true); + total_difficulty = total_difficulty + *block.header.difficulty(); + bc.insert_block(&mut batch, &block.encoded(), vec![], total_difficulty, true); bc.commit(); } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 55f2ba0dd9a..ff102432dbc 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -268,7 +268,8 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], true); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], U256::zero(), true); bc.commit(); } db.write(batch).unwrap(); @@ -283,7 +284,8 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], true); + // Total difficulty is always 0 here. + bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], U256::zero(), true); bc.commit(); } db.write(batch).unwrap(); From 1d8149ab0955a90dfbaa17c51a2b0704554bb32a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 14 Apr 2018 20:26:36 +0800 Subject: [PATCH 05/64] Use fixed BlockMetadata and BlockProvider type for null and instantseal In this way they can use total difficulty fork choice check --- ethcore/src/engines/instant_seal.rs | 13 ++++++------- ethcore/src/engines/null_engine.rs | 12 +++++------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 5159cd34ac6..9119b27f3b5 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -32,9 +32,8 @@ impl InstantSeal { } } -impl Engine for InstantSeal - where M::LiveBlock: Transactions, - M::BlockMetadata: Default +impl> Engine for InstantSeal + where M::LiveBlock: Transactions { fn name(&self) -> &str { "InstantSeal" @@ -63,12 +62,12 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn generate_metadata(&self, _bytes: &[u8], _provider: &M::BlockProvider) -> M::BlockMetadata { - M::BlockMetadata::default() + fn generate_metadata(&self, bytes: &[u8], provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> <::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata { + super::total_difficulty_generate_metadata(bytes, provider) } - fn is_new_best(&self, _bytes: &[u8], _block_metadata: &M::BlockMetadata, _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { - true + fn is_new_best(&self, bytes: &[u8], block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, best_block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index d979f64ceb4..5b02e73aa8e 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -56,9 +56,7 @@ impl Default for NullEngine { } } -impl Engine for NullEngine - where M::BlockMetadata: Default -{ +impl> Engine for NullEngine { fn name(&self) -> &str { "NullEngine" } @@ -108,11 +106,11 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn generate_metadata(&self, _bytes: &[u8], _provider: &M::BlockProvider) -> M::BlockMetadata { - M::BlockMetadata::default() + fn generate_metadata(&self, bytes: &[u8], provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> <::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata { + super::total_difficulty_generate_metadata(bytes, provider) } - fn is_new_best(&self, _bytes: &[u8], _block_metadata: &M::BlockMetadata, _best_block_metadata: &M::BlockMetadata, _provider: &M::BlockProvider) -> bool { - true + fn is_new_best(&self, bytes: &[u8], block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, best_block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> bool { + super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) } } From d3ef8770eb6a7078397b4d8d5f17a413e593b3cb Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 19:51:15 +0800 Subject: [PATCH 06/64] Extend blockdetails with metadatas and finalized info --- ethcore/src/blockchain/blockchain.rs | 6 +++ ethcore/src/blockchain/extras.rs | 64 +++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 5dffc9ec371..75685c763a2 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -508,6 +508,8 @@ impl BlockChain { total_difficulty: header.difficulty(), parent: header.parent_hash(), children: vec![], + finalized: false, + metadatas: vec![], }; let mut batch = DBTransaction::new(); @@ -772,6 +774,8 @@ impl BlockChain { total_difficulty: info.total_difficulty, parent: header.parent_hash(), children: Vec::new(), + finalized: false, + metadatas: Vec::new(), }; let mut update = HashMap::new(); @@ -1179,6 +1183,8 @@ impl BlockChain { total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], + finalized: false, + metadatas: vec![], }; // write to batch diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 97583a693a6..bfd3e40dabc 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -23,6 +23,8 @@ use db::Key; use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; +use rlp; +use bytes::Bytes; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; @@ -167,7 +169,7 @@ impl Key for u64 { } /// Familial details concerning a block -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] +#[derive(Debug, Clone)] pub struct BlockDetails { /// Block number pub number: BlockNumber, @@ -177,6 +179,57 @@ pub struct BlockDetails { pub parent: H256, /// List of children block hashes pub children: Vec, + /// Whether the block is considered finalized + pub finalized: bool, + /// Metadata information + pub metadatas: Vec, +} + +impl rlp::Encodable for BlockDetails { + fn rlp_append(&self, stream: &mut rlp::RlpStream) { + let use_short_version = self.metadatas.len() == 0 && !self.finalized; + + match use_short_version { + true => { stream.begin_list(4); }, + false => { stream.begin_list(6); }, + } + + stream.append(&self.number); + stream.append(&self.total_difficulty); + stream.append(&self.parent); + stream.append_list(&self.children); + if !use_short_version { + stream.append(&self.finalized); + stream.append_list(&self.metadatas); + } + } +} + +impl rlp::Decodable for BlockDetails { + fn decode(rlp: &rlp::UntrustedRlp) -> Result { + let use_short_version = match rlp.item_count()? { + 4 => true, + 6 => false, + _ => return Err(rlp::DecoderError::RlpIncorrectListLen), + }; + + Ok(BlockDetails { + number: rlp.val_at(0)?, + total_difficulty: rlp.val_at(1)?, + parent: rlp.val_at(2)?, + children: rlp.list_at(3)?, + finalized: if use_short_version { + false + } else { + rlp.val_at(4)? + }, + metadatas: if use_short_version { + Vec::new() + } else { + rlp.list_at(5)? + }, + }) + } } impl HeapSizeOf for BlockDetails { @@ -185,6 +238,15 @@ impl HeapSizeOf for BlockDetails { } } +/// Metadata key and value +#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] +pub struct BlockMetadata { + /// Key of the metadata + pub key: Bytes, + /// Value of the metadata + pub value: Bytes, +} + /// Represents address of certain transaction within block #[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] pub struct TransactionAddress { From f3252987270638a6bfa7f9061fba1e36e0d9c874 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 20:23:29 +0800 Subject: [PATCH 07/64] Extra data update: mark_finalized and update_metadatas --- ethcore/src/blockchain/blockchain.rs | 34 +++++++++++++++++++++++++--- ethcore/src/blockchain/extras.rs | 17 ++++++++++---- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 75685c763a2..7b1a9b03302 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -509,7 +509,7 @@ impl BlockChain { parent: header.parent_hash(), children: vec![], finalized: false, - metadatas: vec![], + metadatas: HashMap::new(), }; let mut batch = DBTransaction::new(); @@ -775,7 +775,7 @@ impl BlockChain { parent: header.parent_hash(), children: Vec::new(), finalized: false, - metadatas: Vec::new(), + metadatas: HashMap::new(), }; let mut update = HashMap::new(); @@ -983,6 +983,34 @@ impl BlockChain { } } + /// Mark a block to be considered finalized. Panic if the hash does not exist. + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) { + let mut block_details = self.block_details(&block_hash).unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + block_details.finalized = true; + + self.prepare_details_update(batch, block_hash, block_details); + } + + /// Update metadata detail for an existing block. + pub fn update_metadatas(&self, batch: &mut DBTransaction, block_hash: H256, metadatas: HashMap) { + let mut block_details = self.block_details(&block_hash).unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + for (key, value) in metadatas { + block_details.metadatas.insert(key, value); + } + + self.prepare_details_update(batch, block_hash, block_details); + } + + /// Prepares extras block detail update. + fn prepare_details_update(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { + let mut details_map = HashMap::new(); + details_map.insert(block_hash, block_details); + + // We're only updating one existing value. So it shouldn't suffer from cache decoherence problem. + let mut write_details = self.pending_block_details.write(); + batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, details_map, CacheUpdatePolicy::Overwrite); + } + /// Prepares extras update. fn prepare_update(&self, batch: &mut DBTransaction, update: ExtrasUpdate, is_best: bool) { @@ -1184,7 +1212,7 @@ impl BlockChain { parent: parent_hash, children: vec![], finalized: false, - metadatas: vec![], + metadatas: HashMap::new(), }; // write to batch diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index bfd3e40dabc..10fd7c3f9cd 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -18,6 +18,7 @@ use std::ops; use std::io::Write; +use std::collections::HashMap; use blooms::{GroupPosition, BloomGroup}; use db::Key; use engines::epoch::{Transition as EpochTransition}; @@ -182,7 +183,7 @@ pub struct BlockDetails { /// Whether the block is considered finalized pub finalized: bool, /// Metadata information - pub metadatas: Vec, + pub metadatas: HashMap, } impl rlp::Encodable for BlockDetails { @@ -200,7 +201,11 @@ impl rlp::Encodable for BlockDetails { stream.append_list(&self.children); if !use_short_version { stream.append(&self.finalized); - stream.append_list(&self.metadatas); + + let metadatas: Vec = self.metadatas.clone().into_iter().map(|(key, value)| { + BlockMetadata { key, value } + }).collect(); + stream.append_list(&metadatas); } } } @@ -224,9 +229,11 @@ impl rlp::Decodable for BlockDetails { rlp.val_at(4)? }, metadatas: if use_short_version { - Vec::new() + HashMap::new() } else { - rlp.list_at(5)? + let metadatas: Vec = rlp.list_at(5)?; + + metadatas.into_iter().map(|metadata| (metadata.key, metadata.value)).collect() }, }) } @@ -240,7 +247,7 @@ impl HeapSizeOf for BlockDetails { /// Metadata key and value #[derive(Debug, Clone, RlpEncodable, RlpDecodable)] -pub struct BlockMetadata { +struct BlockMetadata { /// Key of the metadata pub key: Bytes, /// Value of the metadata From 6756cef8a75d83a761df3b1ca32d9ef79e49aa14 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 20:44:02 +0800 Subject: [PATCH 08/64] Check finalized block in Blockchain --- ethcore/src/blockchain/blockchain.rs | 32 +++++++++++++++++++--------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7b1a9b03302..33752fb88fb 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -965,16 +965,28 @@ impl BlockChain { assert_eq!(number, parent_details.number + 1); - match route.blocks.len() { - 0 => BlockLocation::CanonChain, - _ => { - let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); - let enacted = route.blocks.into_iter().skip(route.index).collect::>(); - BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { - ancestor: route.ancestor, - enacted: enacted, - retracted: retracted, - }) + // If anything on the tree route is finalized, refuse to reorg. The common ancestor can be finalized, + // but nothing in between. + let finalized_block = route.blocks.iter() + .map(|route_hash| self.block_details(&route_hash).unwrap_or_else(|| panic!("Invalid block hash in tree route: {:?}", route_hash))) + .enumerate() + .take_while(|&(i, _)| i < route.index) + .any(|(_, details)| details.finalized); + + if finalized_block { + BlockLocation::Branch + } else { + match route.blocks.len() { + 0 => BlockLocation::CanonChain, + _ => { + let retracted = route.blocks.iter().take(route.index).cloned().collect::>().into_iter().collect::>(); + let enacted = route.blocks.into_iter().skip(route.index).collect::>(); + BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { + ancestor: route.ancestor, + enacted: enacted, + retracted: retracted, + }) + } } } } else { From 7c958b46750cbdc1b35bf4013ec593946c68626c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 20:53:32 +0800 Subject: [PATCH 09/64] Fix a test constructor in verification mod --- ethcore/src/verification/verification.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 5b0700bfd9c..d3fd0596a61 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -454,6 +454,8 @@ mod tests { total_difficulty: header.difficulty().clone(), parent: header.parent_hash().clone(), children: Vec::new(), + finalized: false, + metadatas: Default::default(), } }) } From e491abf6d4ae35059c07fa38ba0bdbc67a35df58 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 22:36:25 +0800 Subject: [PATCH 10/64] Add total difficulty trait --- machine/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index ab29962a8df..b4a91e8ea16 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -119,3 +119,10 @@ pub trait WithBalances: Machine { _indirect: &[(Address, U256)], ) -> Result<(), Self::Error> { Ok(()) } } + +/// Metadata with total difficulty information. +pub trait TotalDifficulty { + type Value: Ord + Add; + + fn total_difficulty(&self) -> &Self::Value; +} From 5459695df5c4782ec4ff909ad065f54b4c22a798 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 22:37:19 +0800 Subject: [PATCH 11/64] Fix type import --- machine/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index b4a91e8ea16..d01baefae4a 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -20,6 +20,7 @@ extern crate ethereum_types; use ethereum_types::{H256, U256, Address}; +use std::ops::Add; /// A header. This contains important metadata about the block, as well as a /// "seal" that indicates validity to a consensus engine. From 7fe0d79b8111e1da968039b38348bf1e6df5d9ae Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 16 Apr 2018 22:41:43 +0800 Subject: [PATCH 12/64] Db migration to V13 with metadata column --- parity/db/rocksdb/migration.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/parity/db/rocksdb/migration.rs b/parity/db/rocksdb/migration.rs index df6a4b5dc9c..16309e42806 100644 --- a/parity/db/rocksdb/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -40,6 +40,13 @@ pub const TO_V12: ChangeColumns = ChangeColumns { version: 12, }; +/// The migration from v12 to v13. +/// Adds a column for metadata storage. +pub const TO_V13: ChangeColumns = ChangeColumns { + pre_columns: Some(8), + post_columns: Some(9), + version: 13, +}; /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; @@ -155,6 +162,7 @@ fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> R let mut manager = MigrationManager::new(default_migration_settings(compaction_profile)); manager.add_migration(TO_V11).map_err(|_| Error::MigrationImpossible)?; manager.add_migration(TO_V12).map_err(|_| Error::MigrationImpossible)?; + manager.add_migration(TO_V13).map_err(|_| Error::MigrationImpossible)?; Ok(manager) } From ce105c6bbd34013bac018c030c7898eba9a5e421 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 00:04:04 +0800 Subject: [PATCH 13/64] Address grumbles --- ethcore/src/blockchain/blockchain.rs | 39 +++++++++++++++------------- ethcore/src/client/test_client.rs | 4 ++- ethcore/src/error.rs | 26 +++++++++++++++++++ ethcore/types/src/tree_route.rs | 4 +++ 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 33752fb88fb..bd0ebba2a64 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -40,6 +40,7 @@ use types::blockchain_info::BlockChainInfo; use types::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute, Config}; +use error::MetadataError; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; use encoded; @@ -649,7 +650,9 @@ impl BlockChain { /// `None` is returned. pub fn tree_route(&self, from: H256, to: H256) -> Option { let mut from_branch = vec![]; + let mut is_from_route_finalized = false; let mut to_branch = vec![]; + let mut is_to_route_finalized = false; let mut from_details = self.block_details(&from)?; let mut to_details = self.block_details(&to)?; @@ -661,12 +664,14 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.finalized; } while to_details.number > from_details.number { to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; + is_to_route_finalized = is_to_route_finalized || to_details.finalized; } assert_eq!(from_details.number, to_details.number); @@ -676,10 +681,12 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; + is_from_route_finalized = is_from_route_finalized || from_details.finalized; to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; + is_to_route_finalized = is_to_route_finalized || to_details.finalized; } let index = from_branch.len(); @@ -689,7 +696,9 @@ impl BlockChain { Some(TreeRoute { blocks: from_branch, ancestor: current_from, - index: index + index: index, + is_from_route_finalized: is_from_route_finalized, + is_to_route_finalized: is_to_route_finalized, }) } @@ -965,15 +974,7 @@ impl BlockChain { assert_eq!(number, parent_details.number + 1); - // If anything on the tree route is finalized, refuse to reorg. The common ancestor can be finalized, - // but nothing in between. - let finalized_block = route.blocks.iter() - .map(|route_hash| self.block_details(&route_hash).unwrap_or_else(|| panic!("Invalid block hash in tree route: {:?}", route_hash))) - .enumerate() - .take_while(|&(i, _)| i < route.index) - .any(|(_, details)| details.finalized); - - if finalized_block { + if route.is_from_route_finalized { BlockLocation::Branch } else { match route.blocks.len() { @@ -995,26 +996,28 @@ impl BlockChain { } } - /// Mark a block to be considered finalized. Panic if the hash does not exist. - pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) { - let mut block_details = self.block_details(&block_hash).unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + /// Mark a block to be considered finalized. + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Result<(), MetadataError> { + let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; block_details.finalized = true; - self.prepare_details_update(batch, block_hash, block_details); + self.update_block_details(batch, block_hash, block_details); + Ok(()) } /// Update metadata detail for an existing block. - pub fn update_metadatas(&self, batch: &mut DBTransaction, block_hash: H256, metadatas: HashMap) { - let mut block_details = self.block_details(&block_hash).unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + pub fn update_metadatas(&self, batch: &mut DBTransaction, block_hash: H256, metadatas: HashMap) -> Result<(), MetadataError> { + let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; for (key, value) in metadatas { block_details.metadatas.insert(key, value); } - self.prepare_details_update(batch, block_hash, block_details); + self.update_block_details(batch, block_hash, block_details); + Ok(()) } /// Prepares extras block detail update. - fn prepare_details_update(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { + fn update_block_details(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { let mut details_map = HashMap::new(); details_map.insert(block_hash, block_details); diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 02067afd002..f96a4b3e8e0 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -742,7 +742,9 @@ impl BlockChainClient for TestBlockChainClient { } } if adding { Vec::new() } else { blocks } - } + }, + is_from_route_finalized: false, + is_to_route_finalized: false, }) } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 4c8157a82f1..527bd90c619 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -147,6 +147,23 @@ impl fmt::Display for BlockError { } } +#[derive(Debug, Clone, Copy, PartialEq)] +/// Errors related to metadata operations +pub enum MetadataError { + /// The metadata block trying to set is unknown. + UnknownBlock, +} + +impl fmt::Display for MetadataError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let msg = match *self { + MetadataError::UnknownBlock => "unknown block", + }; + + f.write_fmt(format_args!("Block metadata error ({})", msg)) + } +} + #[derive(Debug, Clone, Copy, PartialEq)] /// Import to the block queue result pub enum ImportError { @@ -247,6 +264,8 @@ pub enum Error { Ethkey(EthkeyError), /// Account Provider error. AccountProvider(AccountsError), + /// Block metadata error. + Metadata(MetadataError), } impl fmt::Display for Error { @@ -271,6 +290,7 @@ impl fmt::Display for Error { Error::Engine(ref err) => err.fmt(f), Error::Ethkey(ref err) => err.fmt(f), Error::AccountProvider(ref err) => err.fmt(f), + Error::Metadata(ref err) => err.fmt(f), } } } @@ -285,6 +305,12 @@ impl error::Error for Error { /// Result of import block operation. pub type ImportResult = Result; +impl From for Error { + fn from(err: MetadataError) -> Error { + Error::Metadata(err) + } +} + impl From for Error { fn from(err: ClientError) -> Error { match err { diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index b3fe431ab99..4df6c2a7091 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -27,4 +27,8 @@ pub struct TreeRoute { pub ancestor: H256, /// An index where best common ancestor would be. pub index: usize, + /// Whether it has finalized blocks from `from` (inclusive) to `ancestor` (exclusive). + pub is_from_route_finalized: bool, + /// Whether it has finalized blocks from `ancestor` (exclusive) to `to` (inclusive). + pub is_to_route_finalized: bool, } From 45b8ce771677789caaf3efb85bb9ca05f8a68694 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 00:06:28 +0800 Subject: [PATCH 14/64] metadatas -> metadata --- ethcore/src/blockchain/blockchain.rs | 12 ++++++------ ethcore/src/blockchain/extras.rs | 10 +++++----- ethcore/src/verification/verification.rs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index bd0ebba2a64..b3e78e036a0 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -510,7 +510,7 @@ impl BlockChain { parent: header.parent_hash(), children: vec![], finalized: false, - metadatas: HashMap::new(), + metadata: HashMap::new(), }; let mut batch = DBTransaction::new(); @@ -784,7 +784,7 @@ impl BlockChain { parent: header.parent_hash(), children: Vec::new(), finalized: false, - metadatas: HashMap::new(), + metadata: HashMap::new(), }; let mut update = HashMap::new(); @@ -1006,10 +1006,10 @@ impl BlockChain { } /// Update metadata detail for an existing block. - pub fn update_metadatas(&self, batch: &mut DBTransaction, block_hash: H256, metadatas: HashMap) -> Result<(), MetadataError> { + pub fn update_metadata(&self, batch: &mut DBTransaction, block_hash: H256, metadata: HashMap) -> Result<(), MetadataError> { let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; - for (key, value) in metadatas { - block_details.metadatas.insert(key, value); + for (key, value) in metadata { + block_details.metadata.insert(key, value); } self.update_block_details(batch, block_hash, block_details); @@ -1227,7 +1227,7 @@ impl BlockChain { parent: parent_hash, children: vec![], finalized: false, - metadatas: HashMap::new(), + metadata: HashMap::new(), }; // write to batch diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 10fd7c3f9cd..2444fa7d971 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -183,12 +183,12 @@ pub struct BlockDetails { /// Whether the block is considered finalized pub finalized: bool, /// Metadata information - pub metadatas: HashMap, + pub metadata: HashMap, } impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = self.metadatas.len() == 0 && !self.finalized; + let use_short_version = self.metadata.len() == 0 && !self.finalized; match use_short_version { true => { stream.begin_list(4); }, @@ -202,10 +202,10 @@ impl rlp::Encodable for BlockDetails { if !use_short_version { stream.append(&self.finalized); - let metadatas: Vec = self.metadatas.clone().into_iter().map(|(key, value)| { + let metadata: Vec = self.metadata.clone().into_iter().map(|(key, value)| { BlockMetadata { key, value } }).collect(); - stream.append_list(&metadatas); + stream.append_list(&metadata); } } } @@ -228,7 +228,7 @@ impl rlp::Decodable for BlockDetails { } else { rlp.val_at(4)? }, - metadatas: if use_short_version { + metadata: if use_short_version { HashMap::new() } else { let metadatas: Vec = rlp.list_at(5)?; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index d3fd0596a61..df9522d95c9 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -455,7 +455,7 @@ mod tests { parent: header.parent_hash().clone(), children: Vec::new(), finalized: false, - metadatas: Default::default(), + metadata: Default::default(), } }) } From f86d4cf9d7b5b9306c60b72ca9372368668ee66b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 00:52:07 +0800 Subject: [PATCH 15/64] Use generic type for update_metadata to avoid passing HashMap all around --- ethcore/src/blockchain/blockchain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index b3e78e036a0..25bf2ecd1b1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1006,8 +1006,9 @@ impl BlockChain { } /// Update metadata detail for an existing block. - pub fn update_metadata(&self, batch: &mut DBTransaction, block_hash: H256, metadata: HashMap) -> Result<(), MetadataError> { + pub fn update_metadata>>(&self, batch: &mut DBTransaction, block_hash: H256, metadata: T) -> Result<(), MetadataError> { let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; + let metadata: HashMap = metadata.into(); for (key, value) in metadata { block_details.metadata.insert(key, value); } From c6dd811c98d57728f2cffd201a7b959f799d480b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 16:38:38 +0800 Subject: [PATCH 16/64] Remove metadata in blockdetails --- ethcore/src/blockchain/extras.rs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 2444fa7d971..4de71102411 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -182,17 +182,15 @@ pub struct BlockDetails { pub children: Vec, /// Whether the block is considered finalized pub finalized: bool, - /// Metadata information - pub metadata: HashMap, } impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = self.metadata.len() == 0 && !self.finalized; + let use_short_version = !self.finalized; match use_short_version { true => { stream.begin_list(4); }, - false => { stream.begin_list(6); }, + false => { stream.begin_list(5); }, } stream.append(&self.number); @@ -201,11 +199,6 @@ impl rlp::Encodable for BlockDetails { stream.append_list(&self.children); if !use_short_version { stream.append(&self.finalized); - - let metadata: Vec = self.metadata.clone().into_iter().map(|(key, value)| { - BlockMetadata { key, value } - }).collect(); - stream.append_list(&metadata); } } } @@ -214,7 +207,7 @@ impl rlp::Decodable for BlockDetails { fn decode(rlp: &rlp::UntrustedRlp) -> Result { let use_short_version = match rlp.item_count()? { 4 => true, - 6 => false, + 5 => false, _ => return Err(rlp::DecoderError::RlpIncorrectListLen), }; @@ -228,13 +221,6 @@ impl rlp::Decodable for BlockDetails { } else { rlp.val_at(4)? }, - metadata: if use_short_version { - HashMap::new() - } else { - let metadatas: Vec = rlp.list_at(5)?; - - metadatas.into_iter().map(|metadata| (metadata.key, metadata.value)).collect() - }, }) } } From fb1cc21b551fd1ba663da9a7b0a1655e99705dc5 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 20:05:26 +0800 Subject: [PATCH 17/64] [WIP] Implement a generic metadata architecture --- ethcore/src/block.rs | 11 ++++++- ethcore/src/blockchain/blockchain.rs | 32 +++++++++++++++++++- ethcore/src/blockchain/cache.rs | 4 ++- ethcore/src/client/client.rs | 3 ++ ethcore/src/db.rs | 4 ++- ethcore/src/header.rs | 39 +++++++++++++++++++++--- machine/src/lib.rs | 44 +++++++++++++++++++++++----- 7 files changed, 122 insertions(+), 15 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index e3622c293df..9648ffe5f79 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -94,6 +94,9 @@ pub struct ExecutedBlock { state: State, traces: Tracing, last_hashes: Arc, + finalized: bool, + local_metadata: Option, + global_metadata: Option, } impl ExecutedBlock { @@ -112,6 +115,7 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, + finalized: false, } } @@ -206,6 +210,12 @@ impl ::parity_machine::Transactions for ExecutedBlock { } } +impl ::parity_machine::Finalizable for ExecutedBlock { + fn mark_finalized(&mut self) { + self.finalized = true; + } +} + /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -789,4 +799,3 @@ mod tests { assert!(orig_db.journal_db().keys().iter().filter(|k| orig_db.journal_db().get(k.0) != db.journal_db().get(k.0)).next() == None); } } - diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index aca244abcde..09be42e0b31 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -162,6 +162,7 @@ enum CacheId { TransactionAddresses(H256), BlocksBlooms(GroupPosition), BlockReceipts(H256), + Metadata(Option), } impl bc::group::BloomGroupDatabase for BlockChain { @@ -900,6 +901,30 @@ impl BlockChain { self.cache_man.lock().note_used(CacheId::BlockDetails(block_hash)); } + /// Read the metadata from the database. If the parameter is provided, read from the block's metadata. Otherwise, + /// read the global metadata. + pub fn metadata(&self, hash: &Option) -> Option { + // Check cache first + { + let read = self.metadata.read(); + if let Some(v) = read.get(hash) { + return Some(v.clone()); + } + } + + // Read from DB and populate cache + let b = self.db.get(db::COL_METADATA, match hash { + Some(hash) => hash.as_ref(), + None => &[0], + }).expect("Low level database error. Some issue with disk?"); + + let mut write = self.metadata.write(); + write.insert(hash, b.clone()); + + self.cache_man.lock().note_used(CacheId::Metadata(hash)); + Some(b) + } + /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. @@ -1377,6 +1402,7 @@ impl BlockChain { transaction_addresses: self.transaction_addresses.read().heap_size_of_children(), blocks_blooms: self.blocks_blooms.read().heap_size_of_children(), block_receipts: self.block_receipts.read().heap_size_of_children(), + metadata: self.metadata.read().heap_size_of_children(), } } @@ -1391,6 +1417,7 @@ impl BlockChain { let mut transaction_addresses = self.transaction_addresses.write(); let mut blocks_blooms = self.blocks_blooms.write(); let mut block_receipts = self.block_receipts.write(); + let mut metadata = self.metadata.write(); let mut cache_man = self.cache_man.lock(); cache_man.collect_garbage(current_size, | ids | { @@ -1403,6 +1430,7 @@ impl BlockChain { CacheId::TransactionAddresses(ref h) => { transaction_addresses.remove(h); } CacheId::BlocksBlooms(ref h) => { blocks_blooms.remove(h); } CacheId::BlockReceipts(ref h) => { block_receipts.remove(h); } + CacheId::Metadata(ref h) => { metadata.remove(h); } } } @@ -1413,6 +1441,7 @@ impl BlockChain { transaction_addresses.shrink_to_fit(); blocks_blooms.shrink_to_fit(); block_receipts.shrink_to_fit(); + metadata.shrink_to_fit(); block_headers.heap_size_of_children() + block_bodies.heap_size_of_children() + @@ -1420,7 +1449,8 @@ impl BlockChain { block_hashes.heap_size_of_children() + transaction_addresses.heap_size_of_children() + blocks_blooms.heap_size_of_children() + - block_receipts.heap_size_of_children() + block_receipts.heap_size_of_children() + + metadata.heap_size_of_children() }); } diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs index 999be423df7..a30daa33b53 100644 --- a/ethcore/src/blockchain/cache.rs +++ b/ethcore/src/blockchain/cache.rs @@ -27,11 +27,13 @@ pub struct CacheSize { pub blocks_blooms: usize, /// Block receipts size. pub block_receipts: usize, + /// Metadata size. + pub metadata: usize, } impl CacheSize { /// Total amount used by the cache. pub fn total(&self) -> usize { - self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts + self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts + self.metadata } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index aaeb2d5769d..a296466d997 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -540,6 +540,9 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); + let global_metadata: Option = block.block().global_metadata(); + let local_metadata: Option = block.block().local_metadata(); + let block_metadata = client.engine.generate_metadata(block_data, chain.deref().deref()); let is_new_best = client.engine.is_new_best(block_data, &block_metadata, &chain.best_block_total_difficulty(), chain.deref().deref()); let route = chain.insert_block(&mut batch, block_data, receipts.clone(), block_metadata, is_new_best); diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index d11adc7710d..b9dad603322 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -41,8 +41,10 @@ pub const COL_ACCOUNT_BLOOM: Option = Some(5); pub const COL_NODE_INFO: Option = Some(6); /// Column for the light client chain. pub const COL_LIGHT_CHAIN: Option = Some(7); +/// Column for engine metadata. +pub const COL_METADATA: Option = Some(8); /// Number of columns in DB -pub const NUM_COLUMNS: Option = Some(8); +pub const NUM_COLUMNS: Option = Some(9); /// Modes for updating caches. #[derive(Clone, Copy)] diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index a31aa029b31..2227f8f71d6 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -34,6 +34,14 @@ enum Seal { Without, } +/// Extended block header, wrapping `Header` with finalized and total difficulty information. +#[derive(Debug, Clone, Eq)] +pub struct ExtendedHeader { + pub header: Header, + pub finalized: bool, + pub total_difficulty: U256, +} + /// A block header. /// /// Reflects the specific RLP fields of a block in the chain with additional room for the seal @@ -368,21 +376,44 @@ impl HeapSizeOf for Header { impl ::parity_machine::Header for Header { fn bare_hash(&self) -> H256 { Header::bare_hash(self) } - fn hash(&self) -> H256 { Header::hash(self) } - fn seal(&self) -> &[Vec] { Header::seal(self) } - fn author(&self) -> &Address { Header::author(self) } - fn number(&self) -> BlockNumber { Header::number(self) } } impl ::parity_machine::ScoredHeader for Header { + type Value = U256; + fn score(&self) -> &U256 { self.difficulty() } fn set_score(&mut self, score: U256) { self.set_difficulty(score) } } +impl ::parity_machine::Header for ExtendedHeader { + fn bare_hash(&self) -> H256 { self.header.bare_hash() } + fn hash(&self) -> H256 { self.header.hash() } + fn seal(&self) -> &[Vec] { self.header.seal() } + fn author(&self) -> &Address { self.header.author() } + fn number(&self) -> BlockNumber { self.header.number() } +} + +impl ::parity_machine::ScoredHeader for ExtendedHeader { + type Value = U256; + + fn score(&self) -> &U256 { self.header.difficulty() } + fn set_score(&mut self, score: U256) { self.set_difficulty(score) } +} + +impl ::parity_machine::TotalScoredHeader for ExtendedHeader { + type Value = U256; + + fn total_score(&self) -> &U256 { &self.total_difficulty } +} + +impl ::parity_machine::FinalizedHeader for ExtendedHeader { + fn is_finalized(&self) -> bool { self.finalized } +} + #[cfg(test)] mod tests { use rustc_hex::FromHex; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index d01baefae4a..bbc77845de9 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -41,13 +41,29 @@ pub trait Header { fn number(&self) -> u64; } -/// a header with an associated score (difficulty in PoW terms) +/// A header with an associated score (difficulty in PoW terms) pub trait ScoredHeader: Header { + type Value; + /// Get the score of this header. - fn score(&self) -> &U256; + fn score(&self) -> &Value; /// Set the score of this header. - fn set_score(&mut self, score: U256); + fn set_score(&mut self, score: Value); +} + +/// A header with associated total score. +pub trait TotalScoredHeader: Header { + type Value; + + /// Get the total score of this header. + fn total_score(&self) -> &Value; +} + +/// A header with finalized information. +pub trait FinalizedHeader: Header { + /// Get whether this header is considered finalized, so that it will never be replaced in reorganization. + fn is_finalized(&self) -> bool; } /// A "live" block is one which is in the process of the transition. @@ -74,6 +90,24 @@ pub trait Transactions: LiveBlock { fn transactions(&self) -> &[Self::Transaction]; } +/// Trait for blocks which have finalized information. +pub trait Finalizable: LiveBlock { + /// Mark the block as finalized. + fn mark_finalized(&mut self); +} + +/// A state machine with block metadata. +pub trait WithMetadata: LiveBlock { + /// Get the current global metadata. + fn global_metadata>>>(&self) -> T; + /// Get the current live block metadata. + fn local_metadata>>>(&self) -> T; + /// Set the current global metadata when the live block is committed. + fn set_global_metadata>>>(&mut self, value: T); + /// Set the current live block metadata. + fn set_local_metadata>>>(&mut self, value: T); +} + /// Generalization of types surrounding blockchain-suitable state machines. pub trait Machine: for<'a> LocalizedMachine<'a> { /// The block header type. @@ -82,12 +116,8 @@ pub trait Machine: for<'a> LocalizedMachine<'a> { type LiveBlock: LiveBlock; /// A handle to a blockchain client for this machine. type EngineClient: ?Sized; - /// A handle to the block provider for this machine. - type BlockProvider: ?Sized; /// A description of needed auxiliary data. type AuxiliaryRequest; - /// Extra data related to consensus rules stored together with each block. - type BlockMetadata; /// Errors which can occur when querying or interacting with the machine. type Error; From 5cb681330e505bdb923bb1a5f56a4734741e416f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 20:56:54 +0800 Subject: [PATCH 18/64] [WIP] Metadata insertion logic in BlockChain --- ethcore/src/blockchain/blockchain.rs | 50 ++++++++-------------------- ethcore/src/blockchain/extras.rs | 2 +- ethcore/src/blockchain/update.rs | 12 +++++++ 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 09be42e0b31..9ecdf6b6bf6 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -928,7 +928,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, metadata: U256, is_new_best: bool) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { // create views onto rlp let block = view!(BlockView, bytes); let header = block.header_view(); @@ -964,6 +964,7 @@ impl BlockChain { block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), + metadata: self.prepare_metadata_update(hash, extras.global_metadata, extras.local_metadata), info: info.clone(), block: bytes, }, true); @@ -972,7 +973,7 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView, metadata: U256, is_new_best: bool) -> BlockInfo { + fn block_info(&self, header: &HeaderView, extras: ExtrasInsert) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); @@ -981,8 +982,8 @@ impl BlockChain { BlockInfo { hash: hash, number: number, - total_difficulty: metadata, - location: if is_new_best { + total_difficulty: parent_details.total_difficulty + header.difficulty(), + location: if extras.is_new_best { // on new best block we need to make sure that all ancestors // are moved to "canon chain" // find the route between old best block and the new one @@ -1010,39 +1011,9 @@ impl BlockChain { } } else { BlockLocation::Branch - } - } - } - - /// Mark a block to be considered finalized. - pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Result<(), MetadataError> { - let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; - block_details.finalized = true; - - self.update_block_details(batch, block_hash, block_details); - Ok(()) - } - - /// Update metadata detail for an existing block. - pub fn update_metadata>>(&self, batch: &mut DBTransaction, block_hash: H256, metadata: T) -> Result<(), MetadataError> { - let mut block_details = self.block_details(&block_hash).ok_or(MetadataError::UnknownBlock)?; - let metadata: HashMap = metadata.into(); - for (key, value) in metadata { - block_details.metadata.insert(key, value); + }, + is_finalized: extras.is_finalized, } - - self.update_block_details(batch, block_hash, block_details); - Ok(()) - } - - /// Prepares extras block detail update. - fn update_block_details(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { - let mut details_map = HashMap::new(); - details_map.insert(block_hash, block_details); - - // We're only updating one existing value. So it shouldn't suffer from cache decoherence problem. - let mut write_details = self.pending_block_details.write(); - batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, details_map, CacheUpdatePolicy::Overwrite); } /// Prepares extras update. @@ -1263,6 +1234,13 @@ impl BlockChain { block_receipts } + /// This function returns modified metadata. + fn prepare_metadata_update(&self, hash: H256, global_metadata: Option, local_metadata: Option) -> HashMap, Option> { + let mut metadata = HashMap::new(); + metadata.push(None, global_metadata); + metadata.push(Some(hash), local_metadata); + } + /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { let block = view!(BlockView, block_bytes); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 4de71102411..f6eb8dc6116 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -181,7 +181,7 @@ pub struct BlockDetails { /// List of children block hashes pub children: Vec, /// Whether the block is considered finalized - pub finalized: bool, + pub is_finalized: bool, } impl rlp::Encodable for BlockDetails { diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index a5251c1ed8e..2887199ae46 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -22,3 +22,15 @@ pub struct ExtrasUpdate<'a> { /// Modified transaction addresses (None signifies removed transactions). pub transactions_addresses: HashMap>, } + +/// Extra information in block insertion. +pub struct ExtrasInsert { + /// Is the inserted block considered the best block. + is_new_best: bool, + /// Is the inserted block considered finalized. + is_finalized: bool, + /// New local metadata. + local_metadata: Option>, + /// New global metadata. + global_metadata: Option>, +} From f972609ad30cf164afb8afab513cbf4021761f65 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 20:58:32 +0800 Subject: [PATCH 19/64] typo: Value -> Self::Value --- machine/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index bbc77845de9..f46e5818806 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -46,10 +46,10 @@ pub trait ScoredHeader: Header { type Value; /// Get the score of this header. - fn score(&self) -> &Value; + fn score(&self) -> &Self::Value; /// Set the score of this header. - fn set_score(&mut self, score: Value); + fn set_score(&mut self, score: Self::Value); } /// A header with associated total score. @@ -57,7 +57,7 @@ pub trait TotalScoredHeader: Header { type Value; /// Get the total score of this header. - fn total_score(&self) -> &Value; + fn total_score(&self) -> &Self::Value; } /// A header with finalized information. From 493e6f080a37c1eafbeaa4c7991fe910f7dbfca1 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:12:03 +0800 Subject: [PATCH 20/64] [WIP] Temporarily remove Engine::is_new_best interface So that we don't have too many type errors. --- ethcore/src/blockchain/mod.rs | 1 + ethcore/src/client/client.rs | 14 +++++++++----- ethcore/src/engines/authority_round/mod.rs | 8 -------- ethcore/src/engines/basic_authority.rs | 8 -------- ethcore/src/engines/instant_seal.rs | 10 +--------- ethcore/src/engines/mod.rs | 6 ------ ethcore/src/engines/null_engine.rs | 10 +--------- ethcore/src/engines/tendermint/mod.rs | 8 -------- ethcore/src/ethereum/ethash.rs | 8 -------- ethcore/src/machine.rs | 2 -- 10 files changed, 12 insertions(+), 63 deletions(-) diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 062068c704d..f991692dedf 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -33,4 +33,5 @@ pub use self::cache::CacheSize; pub use self::config::Config; pub use self::extras::{BlockReceipts, BlockDetails, TransactionAddress}; pub use self::import_route::ImportRoute; +pub use self::update::ExtrasInsert; pub use types::tree_route::TreeRoute; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a296466d997..3e2fbaa33be 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -32,7 +32,7 @@ use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress, ExtrasInsert}; use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ @@ -542,10 +542,14 @@ impl Importer { state.journal_under(&mut batch, number, hash).expect("DB commit failed"); let global_metadata: Option = block.block().global_metadata(); let local_metadata: Option = block.block().local_metadata(); - - let block_metadata = client.engine.generate_metadata(block_data, chain.deref().deref()); - let is_new_best = client.engine.is_new_best(block_data, &block_metadata, &chain.best_block_total_difficulty(), chain.deref().deref()); - let route = chain.insert_block(&mut batch, block_data, receipts.clone(), block_metadata, is_new_best); + let is_finalized = block.block().is_finalized(); + let is_new_best = true; + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { + is_new_best: is_new_best, + is_finalized: is_finalized, + global_metadata: global_metadata, + local_metadata: local_metadata + }); client.tracedb.read().import(&mut batch, TraceImportRequest { traces: traces.into(), diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 75ba14c1bc2..013445ba35f 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1319,14 +1319,6 @@ impl Engine for AuthorityRound { Some(Box::new(::snapshot::PoaSnapshot)) } } - - fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { - super::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } #[cfg(test)] diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 75987de8a8b..bbefddccb74 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -191,14 +191,6 @@ impl Engine for BasicAuthority { fn snapshot_components(&self) -> Option> { None } - - fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { - super::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } #[cfg(test)] diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 9119b27f3b5..40a96e2b713 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -32,7 +32,7 @@ impl InstantSeal { } } -impl> Engine for InstantSeal +impl Engine for InstantSeal where M::LiveBlock: Transactions { fn name(&self) -> &str { @@ -61,14 +61,6 @@ impl bool { header_timestamp >= parent_timestamp } - - fn generate_metadata(&self, bytes: &[u8], provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> <::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata { - super::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, best_block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 173f2c0359f..ceb0ce473bf 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -340,12 +340,6 @@ pub trait Engine: Sync + Send { fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp > parent_timestamp } - - /// Generate metadata for a new block. - fn generate_metadata(&self, bytes: &[u8], provider: &M::BlockProvider) -> M::BlockMetadata; - - /// Check whether a given block is the best block. - fn is_new_best(&self, bytes: &[u8], block_metadata: &M::BlockMetadata, best_block_metadata: &M::BlockMetadata, provider: &M::BlockProvider) -> bool; } /// Generate metadata for a new block based on the default total difficulty rule. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 5b02e73aa8e..f20a9cdfd9d 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -56,7 +56,7 @@ impl Default for NullEngine { } } -impl> Engine for NullEngine { +impl Engine for NullEngine { fn name(&self) -> &str { "NullEngine" } @@ -105,12 +105,4 @@ impl Option> { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - - fn generate_metadata(&self, bytes: &[u8], provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> <::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata { - super::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, best_block_metadata: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockMetadata, provider: &<::machine::EthereumMachine as ::parity_machine::Machine>::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 1f9d598353e..5021ef9865a 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -759,14 +759,6 @@ impl Engine for Tendermint { *self.client.write() = Some(client.clone()); self.validators.register_client(client); } - - fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { - super::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - super::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } #[cfg(test)] diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 701f82bbc55..7d43395286f 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -365,14 +365,6 @@ impl Engine for Arc { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - - fn generate_metadata(&self, bytes: &[u8], provider: &::BlockProvider) -> ::BlockMetadata { - engines::total_difficulty_generate_metadata(bytes, provider) - } - - fn is_new_best(&self, bytes: &[u8], block_metadata: &::BlockMetadata, best_block_metadata: &::BlockMetadata, provider: &::BlockProvider) -> bool { - engines::total_difficulty_is_new_best(bytes, *block_metadata, *best_block_metadata, provider) - } } impl Ethash { diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index bd323feb01c..7d488e0d0c9 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -409,8 +409,6 @@ impl ::parity_machine::Machine for EthereumMachine { type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; type AuxiliaryRequest = AuxiliaryRequest; - type BlockProvider = ::blockchain::BlockProvider; - type BlockMetadata = U256; type Error = Error; } From cb5bfcfe20f078a8f47189a2863c364e1e3fa9a2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:15:01 +0800 Subject: [PATCH 21/64] [WIP] Fix more type errors --- ethcore/src/blockchain/blockchain.rs | 6 +++--- ethcore/src/blockchain/extras.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 9ecdf6b6bf6..7637250c300 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -38,7 +38,7 @@ use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainD use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions}; use types::blockchain_info::BlockChainInfo; use types::tree_route::TreeRoute; -use blockchain::update::ExtrasUpdate; +use blockchain::update::{ExtrasUpdate, ExtrasInsert}; use blockchain::{CacheSize, ImportRoute, Config}; use error::MetadataError; use db::{self, Writable, Readable, CacheUpdatePolicy}; @@ -947,7 +947,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header, metadata, is_new_best); + let info = self.block_info(&header, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -973,7 +973,7 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView, extras: ExtrasInsert) -> BlockInfo { + fn block_info(&self, header: &HeaderView, extras: &ExtrasInsert) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index f6eb8dc6116..382126da66d 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -204,7 +204,7 @@ impl rlp::Encodable for BlockDetails { } impl rlp::Decodable for BlockDetails { - fn decode(rlp: &rlp::UntrustedRlp) -> Result { + fn decode(rlp: &rlp::Rlp) -> Result { let use_short_version = match rlp.item_count()? { 4 => true, 5 => false, From fc809c7702c0d08713a1aceec18340d44b4b8087 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:15:51 +0800 Subject: [PATCH 22/64] [WIP] ExtendedHeader::PartialEq --- ethcore/src/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 2227f8f71d6..5099da9e172 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -35,7 +35,7 @@ enum Seal { } /// Extended block header, wrapping `Header` with finalized and total difficulty information. -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtendedHeader { pub header: Header, pub finalized: bool, From d517ba351b133c8d847bc8c4e67af700e0e5706e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:32:02 +0800 Subject: [PATCH 23/64] [WIP] Change metadata type Option> to Vec --- ethcore/src/block.rs | 20 ++++++++++++++++++++ machine/src/lib.rs | 8 ++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 9648ffe5f79..a78071749b7 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -216,6 +216,24 @@ impl ::parity_machine::Finalizable for ExecutedBlock { } } +impl ::parity_machine::WithMetadata for ExecutedBlock { + fn global_metadata(&self) -> &[u8] { + &self.global_metadata + } + + fn local_metadata(&self) -> &[u8] { + &self.local_metadata + } + + fn set_global_metadata(&mut self, value: Vec) { + self.global_metadata = value; + } + + fn set_local_metadata(&mut self, value: Vec) { + self.local_metadata = value; + } +} + /// Block that is ready for transactions to be added. /// /// It's a bit like a Vec, except that whenever a transaction is pushed, we execute it and @@ -234,6 +252,8 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, unclosed_state: State, + unclosed_local_metadata: Option, + unclosed_global_metadata: Option, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f46e5818806..b66d3e9dd5a 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -99,13 +99,13 @@ pub trait Finalizable: LiveBlock { /// A state machine with block metadata. pub trait WithMetadata: LiveBlock { /// Get the current global metadata. - fn global_metadata>>>(&self) -> T; + fn global_metadata(&self) -> &[u8]; /// Get the current live block metadata. - fn local_metadata>>>(&self) -> T; + fn local_metadata(&self) -> &[u8]; /// Set the current global metadata when the live block is committed. - fn set_global_metadata>>>(&mut self, value: T); + fn set_global_metadata(&mut self, value: Vec); /// Set the current live block metadata. - fn set_local_metadata>>>(&mut self, value: T); + fn set_local_metadata(&mut self, value: Vec); } /// Generalization of types surrounding blockchain-suitable state machines. From ac37c31aaa56677b1787b3ad2ee2bf9a87f6346c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:34:37 +0800 Subject: [PATCH 24/64] [WIP] Remove Metadata Error --- ethcore/src/block.rs | 8 +++++--- ethcore/src/error.rs | 17 ----------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index a78071749b7..5302d53b649 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -95,13 +95,13 @@ pub struct ExecutedBlock { traces: Tracing, last_hashes: Arc, finalized: bool, - local_metadata: Option, - global_metadata: Option, + local_metadata: Vec, + global_metadata: Vec, } impl ExecutedBlock { /// Create a new block from the given `state`. - fn new(state: State, last_hashes: Arc, tracing: bool) -> ExecutedBlock { + fn new(state: State, last_hashes: Arc, tracing: bool, global_metadata: Vec, local_metadata: Vec) -> ExecutedBlock { ExecutedBlock { header: Default::default(), transactions: Default::default(), @@ -116,6 +116,8 @@ impl ExecutedBlock { }, last_hashes: last_hashes, finalized: false, + global_metadata: global_metadata, + local_metadata: local_metadata, } } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 527bd90c619..493deb1e17e 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -147,23 +147,6 @@ impl fmt::Display for BlockError { } } -#[derive(Debug, Clone, Copy, PartialEq)] -/// Errors related to metadata operations -pub enum MetadataError { - /// The metadata block trying to set is unknown. - UnknownBlock, -} - -impl fmt::Display for MetadataError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match *self { - MetadataError::UnknownBlock => "unknown block", - }; - - f.write_fmt(format_args!("Block metadata error ({})", msg)) - } -} - #[derive(Debug, Clone, Copy, PartialEq)] /// Import to the block queue result pub enum ImportError { From 0f36e50baf0de528a0151bdc6827783304b1d914 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:35:41 +0800 Subject: [PATCH 25/64] [WIP] Clean up error conversion --- ethcore/src/block.rs | 2 +- ethcore/src/error.rs | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 5302d53b649..170200221c2 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -94,7 +94,7 @@ pub struct ExecutedBlock { state: State, traces: Tracing, last_hashes: Arc, - finalized: bool, + is_finalized: bool, local_metadata: Vec, global_metadata: Vec, } diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 493deb1e17e..4c8157a82f1 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -247,8 +247,6 @@ pub enum Error { Ethkey(EthkeyError), /// Account Provider error. AccountProvider(AccountsError), - /// Block metadata error. - Metadata(MetadataError), } impl fmt::Display for Error { @@ -273,7 +271,6 @@ impl fmt::Display for Error { Error::Engine(ref err) => err.fmt(f), Error::Ethkey(ref err) => err.fmt(f), Error::AccountProvider(ref err) => err.fmt(f), - Error::Metadata(ref err) => err.fmt(f), } } } @@ -288,12 +285,6 @@ impl error::Error for Error { /// Result of import block operation. pub type ImportResult = Result; -impl From for Error { - fn from(err: MetadataError) -> Error { - Error::Metadata(err) - } -} - impl From for Error { fn from(err: ClientError) -> Error { match err { From ef3aa6344e27b588f564cd6e8cc7c4c407b732ea Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:42:05 +0800 Subject: [PATCH 26/64] [WIP] finalized -> is_finalized --- ethcore/src/blockchain/extras.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 382126da66d..0e739702b5b 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -186,7 +186,7 @@ pub struct BlockDetails { impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = !self.finalized; + let use_short_version = !self.is_finalized; match use_short_version { true => { stream.begin_list(4); }, @@ -198,7 +198,7 @@ impl rlp::Encodable for BlockDetails { stream.append(&self.parent); stream.append_list(&self.children); if !use_short_version { - stream.append(&self.finalized); + stream.append(&self.is_finalized); } } } @@ -216,7 +216,7 @@ impl rlp::Decodable for BlockDetails { total_difficulty: rlp.val_at(1)?, parent: rlp.val_at(2)?, children: rlp.list_at(3)?, - finalized: if use_short_version { + is_finalized: if use_short_version { false } else { rlp.val_at(4)? From 3957c49943021c688617da7b9fb0b09ffae7f4e5 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:45:25 +0800 Subject: [PATCH 27/64] [WIP] Mark all fields in ExtrasInsert as pub --- ethcore/src/blockchain/blockchain.rs | 13 +++++++------ ethcore/src/blockchain/update.rs | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7637250c300..7756977d1cd 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -199,6 +199,7 @@ pub struct BlockChain { transaction_addresses: RwLock>, blocks_blooms: RwLock>, block_receipts: RwLock>, + metadata: RwLock, Vec>>, db: Arc, @@ -1201,7 +1202,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool) -> HashMap { let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1216,8 +1217,7 @@ impl BlockChain { total_difficulty: info.total_difficulty, parent: parent_hash, children: vec![], - finalized: false, - metadata: HashMap::new(), + is_finalized: is_finalized, }; // write to batch @@ -1235,10 +1235,11 @@ impl BlockChain { } /// This function returns modified metadata. - fn prepare_metadata_update(&self, hash: H256, global_metadata: Option, local_metadata: Option) -> HashMap, Option> { + fn prepare_metadata_update(&self, hash: H256, global_metadata: Vec, local_metadata: Vec) -> HashMap, Vec> { let mut metadata = HashMap::new(); - metadata.push(None, global_metadata); - metadata.push(Some(hash), local_metadata); + metadata.insert(None, global_metadata); + metadata.insert(Some(hash), local_metadata); + metadata } /// This function returns modified transaction addresses. diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 2887199ae46..533216ebbea 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -26,11 +26,11 @@ pub struct ExtrasUpdate<'a> { /// Extra information in block insertion. pub struct ExtrasInsert { /// Is the inserted block considered the best block. - is_new_best: bool, + pub is_new_best: bool, /// Is the inserted block considered finalized. - is_finalized: bool, + pub is_finalized: bool, /// New local metadata. - local_metadata: Option>, + pub local_metadata: Option>, /// New global metadata. - global_metadata: Option>, + pub global_metadata: Option>, } From bc9cc87a72f880652b791d51722c675f8b5982a0 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 21:46:15 +0800 Subject: [PATCH 28/64] [WIP] Remove unused import --- ethcore/src/blockchain/blockchain.rs | 1 - ethcore/src/blockchain/extras.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7756977d1cd..8596fd8b8d0 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -40,7 +40,6 @@ use types::blockchain_info::BlockChainInfo; use types::tree_route::TreeRoute; use blockchain::update::{ExtrasUpdate, ExtrasInsert}; use blockchain::{CacheSize, ImportRoute, Config}; -use error::MetadataError; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; use encoded; diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 0e739702b5b..3f5c84d5d1f 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -18,7 +18,6 @@ use std::ops; use std::io::Write; -use std::collections::HashMap; use blooms::{GroupPosition, BloomGroup}; use db::Key; use engines::epoch::{Transition as EpochTransition}; From 4983b6869589c92398c023ce621f5a4e57b5293e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 22:28:15 +0800 Subject: [PATCH 29/64] [WIP] Keep only local metadata info --- ethcore/src/block.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 170200221c2..2224e828383 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -95,8 +95,7 @@ pub struct ExecutedBlock { traces: Tracing, last_hashes: Arc, is_finalized: bool, - local_metadata: Vec, - global_metadata: Vec, + metadata: Vec, } impl ExecutedBlock { @@ -115,7 +114,7 @@ impl ExecutedBlock { Tracing::Disabled }, last_hashes: last_hashes, - finalized: false, + is_finalized: false, global_metadata: global_metadata, local_metadata: local_metadata, } @@ -214,25 +213,17 @@ impl ::parity_machine::Transactions for ExecutedBlock { impl ::parity_machine::Finalizable for ExecutedBlock { fn mark_finalized(&mut self) { - self.finalized = true; + self.is_finalized = true; } } impl ::parity_machine::WithMetadata for ExecutedBlock { - fn global_metadata(&self) -> &[u8] { - &self.global_metadata + fn metadata(&self) -> &[u8] { + &self.metadata } - fn local_metadata(&self) -> &[u8] { - &self.local_metadata - } - - fn set_global_metadata(&mut self, value: Vec) { - self.global_metadata = value; - } - - fn set_local_metadata(&mut self, value: Vec) { - self.local_metadata = value; + fn set_metadata(&mut self, value: Vec) { + self.metadata = value; } } From 6009dfa97ef44768477d95a6f0029f754a5ce5ea Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 22:38:58 +0800 Subject: [PATCH 30/64] Mark metadata as optional --- ethcore/src/block.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 2224e828383..ac131ec8b37 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -95,12 +95,12 @@ pub struct ExecutedBlock { traces: Tracing, last_hashes: Arc, is_finalized: bool, - metadata: Vec, + metadata: Option>, } impl ExecutedBlock { /// Create a new block from the given `state`. - fn new(state: State, last_hashes: Arc, tracing: bool, global_metadata: Vec, local_metadata: Vec) -> ExecutedBlock { + fn new(state: State, last_hashes: Arc, tracing: bool) -> ExecutedBlock { ExecutedBlock { header: Default::default(), transactions: Default::default(), @@ -115,8 +115,7 @@ impl ExecutedBlock { }, last_hashes: last_hashes, is_finalized: false, - global_metadata: global_metadata, - local_metadata: local_metadata, + metadata: None, } } @@ -218,11 +217,11 @@ impl ::parity_machine::Finalizable for ExecutedBlock { } impl ::parity_machine::WithMetadata for ExecutedBlock { - fn metadata(&self) -> &[u8] { + fn metadata(&self) -> Option<&[u8]> { &self.metadata } - fn set_metadata(&mut self, value: Vec) { + fn set_metadata(&mut self, value: Option>) { self.metadata = value; } } From 13b1b5bc8b9f85c0682af28ed79b971b5206e311 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 22:40:29 +0800 Subject: [PATCH 31/64] [WIP] Revert metadata db change in BlockChain --- ethcore/src/blockchain/blockchain.rs | 4 +--- ethcore/src/blockchain/update.rs | 6 ++---- ethcore/src/header.rs | 2 +- machine/src/lib.rs | 8 ++------ 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8596fd8b8d0..6e120bbcdb3 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -198,7 +198,6 @@ pub struct BlockChain { transaction_addresses: RwLock>, blocks_blooms: RwLock>, block_receipts: RwLock>, - metadata: RwLock, Vec>>, db: Arc, @@ -960,7 +959,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, extras.is_finalized, extras.metadata), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -1012,7 +1011,6 @@ impl BlockChain { } else { BlockLocation::Branch }, - is_finalized: extras.is_finalized, } } diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 533216ebbea..f4e4a6d346a 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -29,8 +29,6 @@ pub struct ExtrasInsert { pub is_new_best: bool, /// Is the inserted block considered finalized. pub is_finalized: bool, - /// New local metadata. - pub local_metadata: Option>, - /// New global metadata. - pub global_metadata: Option>, + /// New block local metadata. + pub metadata: Option>, } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 5099da9e172..3b35a2c6ce4 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -38,7 +38,7 @@ enum Seal { #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtendedHeader { pub header: Header, - pub finalized: bool, + pub is_finalized: bool, pub total_difficulty: U256, } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index b66d3e9dd5a..e2a39eb16bc 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -98,14 +98,10 @@ pub trait Finalizable: LiveBlock { /// A state machine with block metadata. pub trait WithMetadata: LiveBlock { - /// Get the current global metadata. - fn global_metadata(&self) -> &[u8]; /// Get the current live block metadata. - fn local_metadata(&self) -> &[u8]; - /// Set the current global metadata when the live block is committed. - fn set_global_metadata(&mut self, value: Vec); + fn metadata(&self) -> &[u8]; /// Set the current live block metadata. - fn set_local_metadata(&mut self, value: Vec); + fn set_metadata(&mut self, value: Vec); } /// Generalization of types surrounding blockchain-suitable state machines. From 723e8a9695e85bdbee740e40db90e92d3c76390b Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Apr 2018 22:44:01 +0800 Subject: [PATCH 32/64] [WIP] Put finalization in unclosed state --- ethcore/src/block.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index ac131ec8b37..5d3ad3b4dc2 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -244,8 +244,8 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, unclosed_state: State, - unclosed_local_metadata: Option, - unclosed_global_metadata: Option, + unclosed_finalization_state: bool, + unclosed_metadata: Option>, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. From cf34f0de49432ceea57686ecffb09b159342378f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 01:16:47 +0800 Subject: [PATCH 33/64] Use metadata interface in BlockDetail --- ethcore/src/block.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 3 +-- ethcore/src/blockchain/extras.rs | 12 ++++++++++-- machine/src/lib.rs | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 5d3ad3b4dc2..0ac819f0c97 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -218,7 +218,7 @@ impl ::parity_machine::Finalizable for ExecutedBlock { impl ::parity_machine::WithMetadata for ExecutedBlock { fn metadata(&self) -> Option<&[u8]> { - &self.metadata + self.metadata.as_ref() } fn set_metadata(&mut self, value: Option>) { diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 6e120bbcdb3..7c5c0a2cd81 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -161,7 +161,6 @@ enum CacheId { TransactionAddresses(H256), BlocksBlooms(GroupPosition), BlockReceipts(H256), - Metadata(Option), } impl bc::group::BloomGroupDatabase for BlockChain { @@ -504,7 +503,7 @@ impl BlockChain { parent: header.parent_hash(), children: vec![], finalized: false, - metadata: HashMap::new(), + metadata: None, }; let mut batch = DBTransaction::new(); diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 3f5c84d5d1f..7a405942ae0 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -181,6 +181,8 @@ pub struct BlockDetails { pub children: Vec, /// Whether the block is considered finalized pub is_finalized: bool, + /// Additional block metadata + pub metadata: Option>, } impl rlp::Encodable for BlockDetails { @@ -189,7 +191,7 @@ impl rlp::Encodable for BlockDetails { match use_short_version { true => { stream.begin_list(4); }, - false => { stream.begin_list(5); }, + false => { stream.begin_list(6); }, } stream.append(&self.number); @@ -198,6 +200,7 @@ impl rlp::Encodable for BlockDetails { stream.append_list(&self.children); if !use_short_version { stream.append(&self.is_finalized); + stream.append(&self.metadata); } } } @@ -206,7 +209,7 @@ impl rlp::Decodable for BlockDetails { fn decode(rlp: &rlp::Rlp) -> Result { let use_short_version = match rlp.item_count()? { 4 => true, - 5 => false, + 6 => false, _ => return Err(rlp::DecoderError::RlpIncorrectListLen), }; @@ -220,6 +223,11 @@ impl rlp::Decodable for BlockDetails { } else { rlp.val_at(4)? }, + metadata: if use_short_version { + None + } else { + rlp.val_at(5)? + }, }) } } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index e2a39eb16bc..e092108a6ad 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -99,9 +99,9 @@ pub trait Finalizable: LiveBlock { /// A state machine with block metadata. pub trait WithMetadata: LiveBlock { /// Get the current live block metadata. - fn metadata(&self) -> &[u8]; + fn metadata(&self) -> Option<&[u8]>; /// Set the current live block metadata. - fn set_metadata(&mut self, value: Vec); + fn set_metadata(&mut self, value: Option>); } /// Generalization of types surrounding blockchain-suitable state machines. From 5861acbcf5743a4509a10be24f622fc78338c9ea Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 01:42:46 +0800 Subject: [PATCH 34/64] [WIP] Fix current build failures --- ethcore/src/block.rs | 12 ++++- ethcore/src/blockchain/blockchain.rs | 79 +++++++++++----------------- ethcore/src/blockchain/cache.rs | 4 +- ethcore/src/client/client.rs | 14 +++-- ethcore/src/engines/mod.rs | 2 +- ethcore/src/header.rs | 11 ++-- ethcore/src/test_helpers.rs | 14 +++-- machine/src/lib.rs | 4 +- 8 files changed, 71 insertions(+), 69 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 0ac819f0c97..dab22d772e2 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -211,6 +211,10 @@ impl ::parity_machine::Transactions for ExecutedBlock { } impl ::parity_machine::Finalizable for ExecutedBlock { + fn is_finalized(&self) -> bool { + self.is_finalized + } + fn mark_finalized(&mut self) { self.is_finalized = true; } @@ -218,7 +222,7 @@ impl ::parity_machine::Finalizable for ExecutedBlock { impl ::parity_machine::WithMetadata for ExecutedBlock { fn metadata(&self) -> Option<&[u8]> { - self.metadata.as_ref() + self.metadata.as_ref().map(|v| v.as_ref()) } fn set_metadata(&mut self, value: Option>) { @@ -409,6 +413,8 @@ impl<'x> OpenBlock<'x> { let mut s = self; let unclosed_state = s.block.state.clone(); + let unclosed_metadata = s.block.metadata.clone(); + let unclosed_finalization_state = s.block.is_finalized; if let Err(e) = s.engine.on_close_block(&mut s.block) { warn!("Encountered error on closing the block: {}", e); @@ -432,6 +438,8 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes, unclosed_state, + unclosed_metadata, + unclosed_finalization_state, } } @@ -505,6 +513,8 @@ impl ClosedBlock { // revert rewards (i.e. set state back at last transaction's state). let mut block = self.block; block.state = self.unclosed_state; + block.metadata = self.unclosed_metadata; + block.is_finalized = self.unclosed_finalization_state; OpenBlock { block: block, engine: engine, diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7c5c0a2cd81..be5d778efbb 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -502,7 +502,7 @@ impl BlockChain { total_difficulty: header.difficulty(), parent: header.parent_hash(), children: vec![], - finalized: false, + is_finalized: false, metadata: None, }; @@ -657,14 +657,14 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; - is_from_route_finalized = is_from_route_finalized || from_details.finalized; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; } while to_details.number > from_details.number { to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; - is_to_route_finalized = is_to_route_finalized || to_details.finalized; + is_to_route_finalized = is_to_route_finalized || to_details.is_finalized; } assert_eq!(from_details.number, to_details.number); @@ -674,12 +674,12 @@ impl BlockChain { from_branch.push(current_from); current_from = from_details.parent.clone(); from_details = self.block_details(&from_details.parent)?; - is_from_route_finalized = is_from_route_finalized || from_details.finalized; + is_from_route_finalized = is_from_route_finalized || from_details.is_finalized; to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; - is_to_route_finalized = is_to_route_finalized || to_details.finalized; + is_to_route_finalized = is_to_route_finalized || to_details.is_finalized; } let index = from_branch.len(); @@ -735,7 +735,7 @@ impl BlockChain { self.prepare_update(batch, ExtrasUpdate { block_hashes: self.prepare_block_hashes_update(bytes, &info), - block_details: self.prepare_block_details_update(bytes, &info), + block_details: self.prepare_block_details_update(bytes, &info, false, None), block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), @@ -771,13 +771,14 @@ impl BlockChain { location: BlockLocation::CanonChain, }; + // TODO [sorpaas] support wrap sync insertion of finalization and metadata. let block_details = BlockDetails { number: header.number(), total_difficulty: info.total_difficulty, parent: header.parent_hash(), children: Vec::new(), - finalized: false, - metadata: HashMap::new(), + is_finalized: false, + metadata: None, }; let mut update = HashMap::new(); @@ -899,30 +900,6 @@ impl BlockChain { self.cache_man.lock().note_used(CacheId::BlockDetails(block_hash)); } - /// Read the metadata from the database. If the parameter is provided, read from the block's metadata. Otherwise, - /// read the global metadata. - pub fn metadata(&self, hash: &Option) -> Option { - // Check cache first - { - let read = self.metadata.read(); - if let Some(v) = read.get(hash) { - return Some(v.clone()); - } - } - - // Read from DB and populate cache - let b = self.db.get(db::COL_METADATA, match hash { - Some(hash) => hash.as_ref(), - None => &[0], - }).expect("Low level database error. Some issue with disk?"); - - let mut write = self.metadata.write(); - write.insert(hash, b.clone()); - - self.cache_man.lock().note_used(CacheId::Metadata(hash)); - Some(b) - } - /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. @@ -962,7 +939,6 @@ impl BlockChain { block_receipts: self.prepare_block_receipts_update(receipts, &info), blocks_blooms: self.prepare_block_blooms_update(bytes, &info), transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info), - metadata: self.prepare_metadata_update(hash, extras.global_metadata, extras.local_metadata), info: info.clone(), block: bytes, }, true); @@ -1013,6 +989,25 @@ impl BlockChain { } } + /// Mark a block to be considered finalized. Panic if the block hash is not found. + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) { + let mut block_details = self.block_details(&block_hash) + .unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + block_details.is_finalized = true; + + self.update_block_details(batch, block_hash, block_details); + } + + /// Prepares extras block detail update. + fn update_block_details(&self, batch: &mut DBTransaction, block_hash: H256, block_details: BlockDetails) { + let mut details_map = HashMap::new(); + details_map.insert(block_hash, block_details); + + // We're only updating one existing value. So it shouldn't suffer from cache decoherence problem. + let mut write_details = self.pending_block_details.write(); + batch.extend_with_cache(db::COL_EXTRA, &mut *write_details, details_map, CacheUpdatePolicy::Overwrite); + } + /// Prepares extras update. fn prepare_update(&self, batch: &mut DBTransaction, update: ExtrasUpdate, is_best: bool) { @@ -1198,7 +1193,7 @@ impl BlockChain { /// This function returns modified block details. /// Uses the given parent details or attempts to load them from the database. - fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool) -> HashMap { + fn prepare_block_details_update(&self, block_bytes: &[u8], info: &BlockInfo, is_finalized: bool, metadata: Option>) -> HashMap { let block = view!(BlockView, block_bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); @@ -1214,6 +1209,7 @@ impl BlockChain { parent: parent_hash, children: vec![], is_finalized: is_finalized, + metadata: metadata, }; // write to batch @@ -1230,14 +1226,6 @@ impl BlockChain { block_receipts } - /// This function returns modified metadata. - fn prepare_metadata_update(&self, hash: H256, global_metadata: Vec, local_metadata: Vec) -> HashMap, Vec> { - let mut metadata = HashMap::new(); - metadata.insert(None, global_metadata); - metadata.insert(Some(hash), local_metadata); - metadata - } - /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap> { let block = view!(BlockView, block_bytes); @@ -1377,7 +1365,6 @@ impl BlockChain { transaction_addresses: self.transaction_addresses.read().heap_size_of_children(), blocks_blooms: self.blocks_blooms.read().heap_size_of_children(), block_receipts: self.block_receipts.read().heap_size_of_children(), - metadata: self.metadata.read().heap_size_of_children(), } } @@ -1392,7 +1379,6 @@ impl BlockChain { let mut transaction_addresses = self.transaction_addresses.write(); let mut blocks_blooms = self.blocks_blooms.write(); let mut block_receipts = self.block_receipts.write(); - let mut metadata = self.metadata.write(); let mut cache_man = self.cache_man.lock(); cache_man.collect_garbage(current_size, | ids | { @@ -1405,7 +1391,6 @@ impl BlockChain { CacheId::TransactionAddresses(ref h) => { transaction_addresses.remove(h); } CacheId::BlocksBlooms(ref h) => { blocks_blooms.remove(h); } CacheId::BlockReceipts(ref h) => { block_receipts.remove(h); } - CacheId::Metadata(ref h) => { metadata.remove(h); } } } @@ -1416,7 +1401,6 @@ impl BlockChain { transaction_addresses.shrink_to_fit(); blocks_blooms.shrink_to_fit(); block_receipts.shrink_to_fit(); - metadata.shrink_to_fit(); block_headers.heap_size_of_children() + block_bodies.heap_size_of_children() + @@ -1424,8 +1408,7 @@ impl BlockChain { block_hashes.heap_size_of_children() + transaction_addresses.heap_size_of_children() + blocks_blooms.heap_size_of_children() + - block_receipts.heap_size_of_children() + - metadata.heap_size_of_children() + block_receipts.heap_size_of_children() }); } diff --git a/ethcore/src/blockchain/cache.rs b/ethcore/src/blockchain/cache.rs index a30daa33b53..999be423df7 100644 --- a/ethcore/src/blockchain/cache.rs +++ b/ethcore/src/blockchain/cache.rs @@ -27,13 +27,11 @@ pub struct CacheSize { pub blocks_blooms: usize, /// Block receipts size. pub block_receipts: usize, - /// Metadata size. - pub metadata: usize, } impl CacheSize { /// Total amount used by the cache. pub fn total(&self) -> usize { - self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts + self.metadata + self.blocks + self.block_details + self.transaction_addresses + self.blocks_blooms + self.block_receipts } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3e2fbaa33be..c6c4e195a00 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -76,6 +76,7 @@ use verification; use verification::{PreverifiedBlock, Verifier}; use verification::queue::BlockQueue; use views::BlockView; +use parity_machine::{Finalizable, WithMetadata}; // re-export pub use types::blockchain_info::BlockChainInfo; @@ -505,8 +506,6 @@ impl Importer { // // The header passed is from the original block data and is sealed. fn commit_block(&self, block: B, header: &Header, block_data: &[u8], client: &Client) -> ImportRoute where B: IsBlock + Drain { - use std::ops::Deref; - let hash = &header.hash(); let number = header.number(); let parent = header.parent_hash(); @@ -522,6 +521,10 @@ impl Importer { let mut batch = DBTransaction::new(); + let metadata = block.block().metadata().map(Into::into); + let is_finalized = block.block().is_finalized(); + let is_new_best = true; + // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. // TODO: Prove it with a test. @@ -540,15 +543,10 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); - let global_metadata: Option = block.block().global_metadata(); - let local_metadata: Option = block.block().local_metadata(); - let is_finalized = block.block().is_finalized(); - let is_new_best = true; let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { is_new_best: is_new_best, is_finalized: is_finalized, - global_metadata: global_metadata, - local_metadata: local_metadata + metadata: metadata, }); client.tracedb.read().import(&mut batch, TraceImportRequest { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index ceb0ce473bf..7e7403a9780 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -344,7 +344,7 @@ pub trait Engine: Sync + Send { /// Generate metadata for a new block based on the default total difficulty rule. pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider) -> U256 { - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 3b35a2c6ce4..787bcf96d79 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -37,9 +37,12 @@ enum Seal { /// Extended block header, wrapping `Header` with finalized and total difficulty information. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExtendedHeader { + /// The actual header. pub header: Header, + /// Whether the block underlying this header is considered finalized. pub is_finalized: bool, - pub total_difficulty: U256, + /// The parent block difficulty. + pub parent_difficulty: U256, } /// A block header. @@ -401,17 +404,17 @@ impl ::parity_machine::ScoredHeader for ExtendedHeader { type Value = U256; fn score(&self) -> &U256 { self.header.difficulty() } - fn set_score(&mut self, score: U256) { self.set_difficulty(score) } + fn set_score(&mut self, score: U256) { self.header.set_difficulty(score) } } impl ::parity_machine::TotalScoredHeader for ExtendedHeader { type Value = U256; - fn total_score(&self) -> &U256 { &self.total_difficulty } + fn total_score(&self) -> U256 { self.parent_difficulty + *self.header.difficulty() } } impl ::parity_machine::FinalizedHeader for ExtendedHeader { - fn is_finalized(&self) -> bool { self.finalized } + fn is_finalized(&self) -> bool { self.is_finalized } } #[cfg(test)] diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index ca6cfc72ff8..1036864f526 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -19,7 +19,7 @@ use account_provider::AccountProvider; use ethereum_types::{H256, U256, Address}; use block::{OpenBlock, Drain}; -use blockchain::{BlockChain, Config as BlockChainConfig}; +use blockchain::{BlockChain, Config as BlockChainConfig, ExtrasInsert}; use bytes::Bytes; use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify, ChainMessageType, PrepareOpenBlock}; use ethkey::KeyPair; @@ -266,7 +266,11 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], U256::zero(), true); + bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { + is_new_best: true, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); @@ -282,7 +286,11 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { let mut batch = db.transaction(); for block_order in 1..block_number { // Total difficulty is always 0 here. - bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], U256::zero(), true); + bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { + is_new_best: true, + is_finalized: false, + metadata: None, + }); bc.commit(); } db.write(batch).unwrap(); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index e092108a6ad..f68d3c94614 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -57,7 +57,7 @@ pub trait TotalScoredHeader: Header { type Value; /// Get the total score of this header. - fn total_score(&self) -> &Self::Value; + fn total_score(&self) -> Self::Value; } /// A header with finalized information. @@ -92,6 +92,8 @@ pub trait Transactions: LiveBlock { /// Trait for blocks which have finalized information. pub trait Finalizable: LiveBlock { + /// Get whether the block is finalized. + fn is_finalized(&self) -> bool; /// Mark the block as finalized. fn mark_finalized(&mut self); } From 6d68222f920389e84fb5fcd89425669452fe5828 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 01:45:17 +0800 Subject: [PATCH 35/64] [WIP] Remove unused blockmetadata struct --- ethcore/src/blockchain/extras.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 7a405942ae0..a60d7ef1935 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -238,15 +238,6 @@ impl HeapSizeOf for BlockDetails { } } -/// Metadata key and value -#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] -struct BlockMetadata { - /// Key of the metadata - pub key: Bytes, - /// Value of the metadata - pub value: Bytes, -} - /// Represents address of certain transaction within block #[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] pub struct TransactionAddress { From a4928302f5d940bab1372e1eb0df86d538687265 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 01:46:46 +0800 Subject: [PATCH 36/64] Remove DB migration info --- ethcore/src/db.rs | 4 +--- parity/db/rocksdb/migration.rs | 9 --------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/ethcore/src/db.rs b/ethcore/src/db.rs index b9dad603322..d11adc7710d 100644 --- a/ethcore/src/db.rs +++ b/ethcore/src/db.rs @@ -41,10 +41,8 @@ pub const COL_ACCOUNT_BLOOM: Option = Some(5); pub const COL_NODE_INFO: Option = Some(6); /// Column for the light client chain. pub const COL_LIGHT_CHAIN: Option = Some(7); -/// Column for engine metadata. -pub const COL_METADATA: Option = Some(8); /// Number of columns in DB -pub const NUM_COLUMNS: Option = Some(9); +pub const NUM_COLUMNS: Option = Some(8); /// Modes for updating caches. #[derive(Clone, Copy)] diff --git a/parity/db/rocksdb/migration.rs b/parity/db/rocksdb/migration.rs index 16309e42806..9019c056707 100644 --- a/parity/db/rocksdb/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -40,14 +40,6 @@ pub const TO_V12: ChangeColumns = ChangeColumns { version: 12, }; -/// The migration from v12 to v13. -/// Adds a column for metadata storage. -pub const TO_V13: ChangeColumns = ChangeColumns { - pre_columns: Some(8), - post_columns: Some(9), - version: 13, -}; - /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; /// Current version of database models. @@ -162,7 +154,6 @@ fn consolidated_database_migrations(compaction_profile: &CompactionProfile) -> R let mut manager = MigrationManager::new(default_migration_settings(compaction_profile)); manager.add_migration(TO_V11).map_err(|_| Error::MigrationImpossible)?; manager.add_migration(TO_V12).map_err(|_| Error::MigrationImpossible)?; - manager.add_migration(TO_V13).map_err(|_| Error::MigrationImpossible)?; Ok(manager) } From 8a06c4ef0e60c8f6cff8c2274ac45a1de11d8279 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 01:47:58 +0800 Subject: [PATCH 37/64] [WIP] Typo --- parity/db/rocksdb/migration.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/parity/db/rocksdb/migration.rs b/parity/db/rocksdb/migration.rs index 9019c056707..df6a4b5dc9c 100644 --- a/parity/db/rocksdb/migration.rs +++ b/parity/db/rocksdb/migration.rs @@ -40,6 +40,7 @@ pub const TO_V12: ChangeColumns = ChangeColumns { version: 12, }; + /// Database is assumed to be at default version, when no version file is found. const DEFAULT_VERSION: u32 = 5; /// Current version of database models. From e673a9836ff0083e652faa2bce82d007ad2b383e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 02:33:10 +0800 Subject: [PATCH 38/64] Use ExtendedHeader to implement fork choice check --- ethcore/src/blockchain/extras.rs | 1 - ethcore/src/engines/authority_round/mod.rs | 6 +++++- ethcore/src/engines/basic_authority.rs | 6 +++++- ethcore/src/engines/instant_seal.rs | 10 ++++++++-- ethcore/src/engines/mod.rs | 12 +++++++++--- ethcore/src/engines/null_engine.rs | 11 +++++++++-- ethcore/src/engines/tendermint/mod.rs | 6 +++++- ethcore/src/ethereum/ethash.rs | 6 +++++- ethcore/src/header.rs | 2 +- ethcore/src/machine.rs | 3 ++- machine/src/lib.rs | 10 +++++++++- 11 files changed, 58 insertions(+), 15 deletions(-) diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index a60d7ef1935..24d03be15de 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -24,7 +24,6 @@ use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; use rlp; -use bytes::Bytes; use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 013445ba35f..c3c8364fe57 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -31,7 +31,7 @@ use error::{Error, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; use hash::keccak; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; @@ -1319,6 +1319,10 @@ impl Engine for AuthorityRound { Some(Box::new(::snapshot::PoaSnapshot)) } } + + fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + super::total_difficulty_is_new_best(new, current) + } } #[cfg(test)] diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index bbefddccb74..b14220a14d5 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -25,7 +25,7 @@ use block::*; use engines::{Engine, Seal, ConstructedVerifier, EngineError}; use error::{BlockError, Error}; use ethjson; -use header::Header; +use header::{Header, ExtendedHeader}; use client::EngineClient; use machine::{AuxiliaryData, Call, EthereumMachine}; use super::signer::EngineSigner; @@ -191,6 +191,10 @@ impl Engine for BasicAuthority { fn snapshot_components(&self) -> Option> { None } + + fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + super::total_difficulty_is_new_best(new, current) + } } #[cfg(test)] diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 40a96e2b713..8805066495f 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use engines::{Engine, Seal}; -use parity_machine::{Machine, Transactions}; +use parity_machine::{Machine, Transactions, TotalScoredHeader}; /// An engine which does not provide any consensus mechanism, just seals blocks internally. /// Only seals blocks which have transactions. @@ -33,7 +33,9 @@ impl InstantSeal { } impl Engine for InstantSeal - where M::LiveBlock: Transactions + where M::LiveBlock: Transactions, + M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord { fn name(&self) -> &str { "InstantSeal" @@ -61,6 +63,10 @@ impl Engine for InstantSeal fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp >= parent_timestamp } + + fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool { + super::total_difficulty_is_new_best(new, current) + } } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 7e7403a9780..ee8f298f00b 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -53,7 +53,7 @@ use views::BlockView; use blockchain::BlockProvider; use ethkey::Signature; -use parity_machine::{Machine, LocalizedMachine as Localized}; +use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; @@ -340,6 +340,9 @@ pub trait Engine: Sync + Send { fn is_timestamp_valid(&self, header_timestamp: u64, parent_timestamp: u64) -> bool { header_timestamp > parent_timestamp } + + /// Check whether the given new block is the best block. + fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool; } /// Generate metadata for a new block based on the default total difficulty rule. @@ -353,8 +356,11 @@ pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider } /// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_is_new_best(_bytes: &[u8], block_total_difficulty: U256, best_block_total_difficulty: U256, _provider: &BlockProvider) -> bool { - block_total_difficulty > best_block_total_difficulty +pub fn total_difficulty_is_new_best(new: &T, mut current: Box>) -> bool where ::Value: Ord { + match current.next() { + None => true, + Some(current) => new.total_score() < current.total_score(), + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index f20a9cdfd9d..eabff53437b 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -17,7 +17,7 @@ use ethereum_types::U256; use engines::Engine; use header::BlockNumber; -use parity_machine::{Header, LiveBlock, WithBalances}; +use parity_machine::{Header, LiveBlock, WithBalances, TotalScoredHeader}; /// Params for a null engine. #[derive(Clone, Default)] @@ -56,7 +56,10 @@ impl Default for NullEngine { } } -impl Engine for NullEngine { +impl Engine for NullEngine + where M::ExtendedHeader: TotalScoredHeader, + ::Value: Ord +{ fn name(&self) -> &str { "NullEngine" } @@ -105,4 +108,8 @@ impl Engine for NullEngine { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } + + fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool { + super::total_difficulty_is_new_best(new, current) + } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 5021ef9865a..6af3fc47055 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -35,7 +35,7 @@ use unexpected::{OutOfBounds, Mismatch}; use client::EngineClient; use bytes::Bytes; use error::{Error, BlockError}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use rlp::Rlp; use ethkey::{self, Message, Signature}; use account_provider::AccountProvider; @@ -759,6 +759,10 @@ impl Engine for Tendermint { *self.client.write() = Some(client.clone()); self.validators.register_client(client); } + + fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + super::total_difficulty_is_new_best(new, current) + } } #[cfg(test)] diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 7d43395286f..4689b921220 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -24,7 +24,7 @@ use ethereum_types::{H256, H64, U256, Address}; use unexpected::{OutOfBounds, Mismatch}; use block::*; use error::{BlockError, Error}; -use header::{Header, BlockNumber}; +use header::{Header, BlockNumber, ExtendedHeader}; use engines::{self, Engine}; use ethjson; use rlp::Rlp; @@ -365,6 +365,10 @@ impl Engine for Arc { fn snapshot_components(&self) -> Option> { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } + + fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + engines::total_difficulty_is_new_best(new, current) + } } impl Ethash { diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 787bcf96d79..9c24d2c19b9 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -413,7 +413,7 @@ impl ::parity_machine::TotalScoredHeader for ExtendedHeader { fn total_score(&self) -> U256 { self.parent_difficulty + *self.header.difficulty() } } -impl ::parity_machine::FinalizedHeader for ExtendedHeader { +impl ::parity_machine::FinalizableHeader for ExtendedHeader { fn is_finalized(&self) -> bool { self.is_finalized } } diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 7d488e0d0c9..c1be80588d4 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -25,7 +25,7 @@ use builtin::Builtin; use client::{BlockInfo, CallContract}; use error::Error; use executive::Executive; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use spec::CommonParams; use state::{CleanupMode, Substate}; use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType, Tracing}; @@ -405,6 +405,7 @@ pub enum AuxiliaryRequest { impl ::parity_machine::Machine for EthereumMachine { type Header = Header; + type ExtendedHeader = ExtendedHeader; type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f68d3c94614..2f0de4a545a 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -61,11 +61,17 @@ pub trait TotalScoredHeader: Header { } /// A header with finalized information. -pub trait FinalizedHeader: Header { +pub trait FinalizableHeader: Header { /// Get whether this header is considered finalized, so that it will never be replaced in reorganization. fn is_finalized(&self) -> bool; } +/// A header with metadata information. +pub trait WithMetadataHeader: Header { + /// Get the current header metadata. + fn metadata(&self) -> Option<&[u8]>; +} + /// A "live" block is one which is in the process of the transition. /// The state of this block can be mutated by arbitrary rules of the /// state transition function. @@ -112,6 +118,8 @@ pub trait Machine: for<'a> LocalizedMachine<'a> { type Header: Header; /// The live block type. type LiveBlock: LiveBlock; + /// Block header with metadata information. + type ExtendedHeader: Header; /// A handle to a blockchain client for this machine. type EngineClient: ?Sized; /// A description of needed auxiliary data. From 700779e27686b889ef44100703e1bee4c8e6beb6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 02:56:50 +0800 Subject: [PATCH 39/64] Implement is_new_best using Ancestry iterator --- ethcore/src/client/client.rs | 26 +++++++++++++++++++--- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 4 ++-- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/header.rs | 10 +++++++-- 9 files changed, 39 insertions(+), 13 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c6c4e195a00..76ea909cfd2 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -54,7 +54,7 @@ use vm::{EnvInfo, LastHashes}; use evm::Schedule; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::{Factories, VmFactory}; -use header::{BlockNumber, Header}; +use header::{BlockNumber, Header, ExtendedHeader}; use io::IoChannel; use log_entry::LocalizedLogEntry; use miner::{Miner, MinerService}; @@ -523,7 +523,27 @@ impl Importer { let metadata = block.block().metadata().map(Into::into); let is_finalized = block.block().is_finalized(); - let is_new_best = true; + + let new = ExtendedHeader { + header: header.clone(), + is_finalized: is_finalized, + metadata: metadata, + parent_total_difficulty: chain.block_details(&parent).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent)).total_difficulty + }; + let current = chain.ancestry_iter(chain.best_block_hash()).unwrap_or_else(|| panic!("Best block hash must be in the database.")).map(|hash| { + let header = chain.block_header_data(&hash).expect("Ancestry must be in the database.").decode(); + let details = chain.block_details(&hash).expect("Ancestry must be in the database."); + + let parent_total_difficulty = details.total_difficulty - *header.difficulty(); + let is_finalized = details.is_finalized; + let metadata = details.metadata; + + ExtendedHeader { + header, parent_total_difficulty, is_finalized, metadata + } + }); + + let is_new_best = self.engine.is_new_best(&new, Box::new(current)); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. @@ -546,7 +566,7 @@ impl Importer { let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { is_new_best: is_new_best, is_finalized: is_finalized, - metadata: metadata, + metadata: new.metadata, }); client.tracedb.read().import(&mut batch, TraceImportRequest { diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index c3c8364fe57..42f2514fbcc 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1320,7 +1320,7 @@ impl Engine for AuthorityRound { } } - fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index b14220a14d5..02541de3479 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 8805066495f..b1bf7ae1517 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index ee8f298f00b..c58d2176472 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -342,7 +342,7 @@ pub trait Engine: Sync + Send { } /// Check whether the given new block is the best block. - fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool; + fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool; } /// Generate metadata for a new block based on the default total difficulty rule. @@ -356,7 +356,7 @@ pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider } /// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_is_new_best(new: &T, mut current: Box>) -> bool where ::Value: Ord { +pub fn total_difficulty_is_new_best<'a, T: TotalScoredHeader>(new: &'a T, mut current: Box + 'a>) -> bool where ::Value: Ord { match current.next() { None => true, Some(current) => new.total_score() < current.total_score(), diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index eabff53437b..63347a9a9a1 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn is_new_best(&self, new: &M::ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 6af3fc47055..666249b6be6 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -760,7 +760,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 4689b921220..c081575f4fd 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -366,7 +366,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn is_new_best(&self, new: &ExtendedHeader, current: Box>) -> bool { + fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { engines::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 9c24d2c19b9..73c81b7ab94 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -42,7 +42,9 @@ pub struct ExtendedHeader { /// Whether the block underlying this header is considered finalized. pub is_finalized: bool, /// The parent block difficulty. - pub parent_difficulty: U256, + pub parent_total_difficulty: U256, + /// The block metadata information. + pub metadata: Option>, } /// A block header. @@ -410,13 +412,17 @@ impl ::parity_machine::ScoredHeader for ExtendedHeader { impl ::parity_machine::TotalScoredHeader for ExtendedHeader { type Value = U256; - fn total_score(&self) -> U256 { self.parent_difficulty + *self.header.difficulty() } + fn total_score(&self) -> U256 { self.parent_total_difficulty + *self.header.difficulty() } } impl ::parity_machine::FinalizableHeader for ExtendedHeader { fn is_finalized(&self) -> bool { self.is_finalized } } +impl ::parity_machine::WithMetadataHeader for ExtendedHeader { + fn metadata(&self) -> Option<&[u8]> { self.metadata.as_ref().map(|v| v.as_ref()) } +} + #[cfg(test)] mod tests { use rustc_hex::FromHex; From 143277f858bf853a2fcf06e2ff2bac8451212fd6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 03:56:03 +0800 Subject: [PATCH 40/64] Use expect instead of panic --- ethcore/src/blockchain/blockchain.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index be5d778efbb..ebff33143e2 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -991,8 +991,7 @@ impl BlockChain { /// Mark a block to be considered finalized. Panic if the block hash is not found. pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) { - let mut block_details = self.block_details(&block_hash) - .unwrap_or_else(|| panic!("Invalid block hash: {:?}", block_hash)); + let mut block_details = self.block_details(&block_hash).expect("Block hash should exist from caller."); block_details.is_finalized = true; self.update_block_details(batch, block_hash, block_details); From 1dd2ea15bf639943776401f8dcfb498d39d8875a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 16:45:55 +0800 Subject: [PATCH 41/64] [WIP] Add ancestry Engine support via on_new_block --- ethcore/src/block.rs | 15 ++++++---- ethcore/src/blockchain/blockchain.rs | 35 ++++++++++++++++++++++ ethcore/src/client/client.rs | 24 +++++++++------ ethcore/src/client/test_client.rs | 1 + ethcore/src/engines/authority_round/mod.rs | 5 ++-- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 12 ++++---- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 4 +-- ethcore/src/ethereum/ethash.rs | 10 +------ ethcore/src/test_helpers.rs | 1 + 12 files changed, 76 insertions(+), 37 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index dab22d772e2..5218f8c2b6a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes}; use engines::EthEngine; use error::{Error, BlockError}; use factory::Factories; -use header::Header; +use header::{Header, ExtendedHeader}; use receipt::{Receipt, TransactionOutcome}; use state::State; use state_db::StateDB; @@ -271,7 +271,7 @@ pub struct SealedBlock { impl<'x> OpenBlock<'x> { /// Create a new `OpenBlock` ready for transaction pushing. - pub fn new( + pub fn new<'a>( engine: &'x EthEngine, factories: Factories, tracing: bool, @@ -282,6 +282,7 @@ impl<'x> OpenBlock<'x> { gas_range_target: (U256, U256), extra_data: Bytes, is_epoch_begin: bool, + ancestry: Box + 'a>, ) -> Result { let number = parent.number() + 1; let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?; @@ -303,7 +304,7 @@ impl<'x> OpenBlock<'x> { engine.populate_from_parent(&mut r.block.header, parent); engine.machine().on_new_block(&mut r.block)?; - engine.on_new_block(&mut r.block, is_epoch_begin)?; + engine.on_new_block(&mut r.block, is_epoch_begin, ancestry)?; Ok(r) } @@ -591,7 +592,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -fn enact( +fn enact<'a>( header: Header, transactions: Vec, uncles: Vec
, @@ -603,6 +604,7 @@ fn enact( factories: Factories, is_epoch_begin: bool, strip_receipts: bool, + ancestry: Box + 'a>, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -623,6 +625,7 @@ fn enact( (3141562.into(), 31415620.into()), vec![], is_epoch_begin, + ancestry, )?; b.populate_from(&header); @@ -642,7 +645,7 @@ fn enact( } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified( +pub fn enact_verified<'a>( block: PreverifiedBlock, engine: &EthEngine, tracing: bool, @@ -653,6 +656,7 @@ pub fn enact_verified( is_epoch_begin: bool, // Remove state root from transaction receipts to make them EIP-98 compatible. strip_receipts: bool, + ancestry: Box + 'a>, ) -> Result { let view = view!(BlockView, &block.bytes); @@ -668,6 +672,7 @@ pub fn enact_verified( factories, is_epoch_begin, strip_receipts, + ancestry, ) } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index ebff33143e2..7853fae5799 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -409,6 +409,27 @@ impl<'a> Iterator for AncestryIter<'a> { } } +impl<'a> AncestryIter<'a> { + pub fn to_header_iter(self) -> Box + 'a> { + let chain = self.chain; + + Box::new(self.map(move |hash| { + let header = chain.block_header_data(&hash) + .expect("Ancestry must be in the database.").decode(); + let details = chain.block_details(&hash) + .expect("Ancestry must be in the database."); + + ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + } + })) + } +} + /// An iterator which walks all epoch transitions. /// Returns epoch transitions. pub struct EpochTransitionIter<'a> { @@ -1127,6 +1148,20 @@ impl BlockChain { } } + /// Iterator that lists `first` and then all of `first`'s ancestors, by extended header. + pub fn ancestry_header_iter<'a>(&'a self, first: H256) -> Box + 'a> { + let hash_iter = AncestryIter { + current: if self.is_known(&first) { + first + } else { + H256::default() // zero hash + }, + chain: self + }; + + hash_iter.to_header_iter() + } + /// Given a block's `parent`, find every block header which represents a valid possible uncle. pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option> { self.find_uncle_hashes(parent, uncle_generations) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 76ea909cfd2..a3ef3004c1a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -427,6 +427,7 @@ impl Importer { client.factories.clone(), is_epoch_begin, strip_receipts, + chain.ancestry_header_iter(*header.parent_hash()), ); let locked_block = enact_result.map_err(|e| { @@ -530,20 +531,24 @@ impl Importer { metadata: metadata, parent_total_difficulty: chain.block_details(&parent).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent)).total_difficulty }; - let current = chain.ancestry_iter(chain.best_block_hash()).unwrap_or_else(|| panic!("Best block hash must be in the database.")).map(|hash| { - let header = chain.block_header_data(&hash).expect("Ancestry must be in the database.").decode(); - let details = chain.block_details(&hash).expect("Ancestry must be in the database."); - let parent_total_difficulty = details.total_difficulty - *header.difficulty(); - let is_finalized = details.is_finalized; - let metadata = details.metadata; + let best = { + let hash = chain.best_block_hash(); + let header = chain.block_header_data(&hash) + .expect("Best block must be in the database.").decode(); + let details = chain.block_details(&hash) + .expect("Best block must be in the database."); ExtendedHeader { - header, parent_total_difficulty, is_finalized, metadata + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, } - }); + }; - let is_new_best = self.engine.is_new_best(&new, Box::new(current)); + let is_new_best = self.engine.is_new_best(&new, &best); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. @@ -2063,6 +2068,7 @@ impl PrepareOpenBlock for Client { gas_range_target, extra_data, is_epoch_begin, + chain.ancestry_header_iter(best_header.hash()), ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index f274c09345a..6b6d408d504 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -392,6 +392,7 @@ impl PrepareOpenBlock for TestBlockChainClient { gas_range_target, extra_data, false, + Box::new(Vec::new().into_iter()), ).expect("Opening block for tests will not fail."); // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 42f2514fbcc..a72ed4854ef 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -941,10 +941,11 @@ impl Engine for AuthorityRound { Ok(()) } - fn on_new_block( + fn on_new_block<'a>( &self, block: &mut ExecutedBlock, epoch_begin: bool, + _ancestry: Box + 'a>, ) -> Result<(), Error> { // with immediate transitions, we don't use the epoch mechanism anyway. // the genesis is always considered an epoch, but we ignore it intentionally. @@ -1320,7 +1321,7 @@ impl Engine for AuthorityRound { } } - fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 02541de3479..de3c9c50f89 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index b1bf7ae1517..f17f7c5fe00 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index c58d2176472..bcd4efd9e03 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -196,10 +196,11 @@ pub trait Engine: Sync + Send { /// Block transformation functions, before the transactions. /// `epoch_begin` set to true if this block kicks off an epoch. - fn on_new_block( + fn on_new_block<'a>( &self, _block: &mut M::LiveBlock, _epoch_begin: bool, + _ancestry: Box + 'a>, ) -> Result<(), M::Error> { Ok(()) } @@ -342,7 +343,7 @@ pub trait Engine: Sync + Send { } /// Check whether the given new block is the best block. - fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool; + fn is_new_best(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> bool; } /// Generate metadata for a new block based on the default total difficulty rule. @@ -356,11 +357,8 @@ pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider } /// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_is_new_best<'a, T: TotalScoredHeader>(new: &'a T, mut current: Box + 'a>) -> bool where ::Value: Ord { - match current.next() { - None => true, - Some(current) => new.total_score() < current.total_score(), - } +pub fn total_difficulty_is_new_best(new: &T, best: &T) -> bool where ::Value: Ord { + new.total_score() > best.total_score() } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 63347a9a9a1..ba3666c5b4e 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn is_new_best<'a>(&'a self, new: &'a M::ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 666249b6be6..ec9c4d6587d 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -527,7 +527,7 @@ impl Engine for Tendermint { Ok(()) } - fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool) -> Result<(), Error> { + fn on_new_block<'a>(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: Box + 'a>) -> Result<(), Error> { if !epoch_begin { return Ok(()) } // genesis is never a new block, but might as well check. @@ -760,7 +760,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { super::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index c081575f4fd..95f000195cd 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -221,14 +221,6 @@ impl Engine for Arc { header.set_difficulty(difficulty); } - fn on_new_block( - &self, - _block: &mut ExecutedBlock, - _begins_epoch: bool, - ) -> Result<(), Error> { - Ok(()) - } - /// Apply the block reward on finalisation of the block. /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { @@ -366,7 +358,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn is_new_best<'a>(&'a self, new: &'a ExtendedHeader, current: Box + 'a>) -> bool { + fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { engines::total_difficulty_is_new_best(new, current) } } diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 1036864f526..06f9f489732 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -148,6 +148,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun (3141562.into(), 31415620.into()), vec![], false, + Box::new(Vec::new().into_iter()), ).unwrap(); rolling_timestamp += 10; b.set_timestamp(rolling_timestamp); From 5d4bd672d3528c3c33635b44f281c79e35a87509 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 18:01:43 +0800 Subject: [PATCH 42/64] Fix tests --- ethcore/src/block.rs | 7 +++--- ethcore/src/blockchain/blockchain.rs | 9 ++++++-- ethcore/src/client/client.rs | 8 +++++-- ethcore/src/engines/authority_round/mod.rs | 24 ++++++++++----------- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 6 +++--- ethcore/src/snapshot/tests/proof_of_work.rs | 10 +++++---- ethcore/src/tests/trace.rs | 5 ++++- ethcore/src/verification/verification.rs | 4 ++-- 11 files changed, 47 insertions(+), 32 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 5218f8c2b6a..3ba765306a2 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -730,6 +730,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + Box::new(Vec::new().into_iter()), )?; b.populate_from(&header); @@ -763,7 +764,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close_and_lock(); let _ = b.seal(&*spec.engine, vec![]); } @@ -777,7 +778,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap() + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -801,7 +802,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.set_extra_data(b"uncle1".to_vec()); let mut uncle2_header = Header::new(); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7853fae5799..905edba9892 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1520,15 +1520,20 @@ mod tests { fn insert_block_batch(batch: &mut DBTransaction, bc: &BlockChain, bytes: &[u8], receipts: Vec) -> ImportRoute { use views::BlockView; + use blockchain::ExtrasInsert; - let block = BlockView::new(bytes); + let block = view!(BlockView, bytes); let header = block.header_view(); let parent_hash = header.parent_hash(); let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); let is_new_best = block_total_difficulty > bc.best_block_total_difficulty(); - bc.insert_block(batch, bytes, receipts, block_total_difficulty, is_new_best) + bc.insert_block(batch, bytes, receipts, ExtrasInsert { + is_new_best: is_new_best, + is_finalized: false, + metadata: None + }) } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index a3ef3004c1a..b684917dedf 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2288,7 +2288,7 @@ mod tests { use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use kvdb::DBTransaction; - use ethereum_types::U256; + use blockchain::ExtrasInsert; let client = generate_dummy_client(0); let genesis = client.chain_info().best_block_hash; @@ -2301,7 +2301,11 @@ mod tests { let another_client = client.clone(); thread::spawn(move || { let mut batch = DBTransaction::new(); - another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), U256::zero(), true); + another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { + is_new_best: true, + is_finalized: false, + metadata: None, + }); go_thread.store(true, Ordering::SeqCst); }); go diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index a72ed4854ef..e6a9efb47fc 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1383,9 +1383,9 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1417,9 +1417,9 @@ mod tests { let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1666,7 +1666,7 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); let client = generate_dummy_client(0); @@ -1701,7 +1701,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1710,7 +1710,7 @@ mod tests { engine.step(); // step 3 - let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); b2.push_transaction(Transaction { action: Action::Create, nonce: U256::from(0), @@ -1749,7 +1749,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1758,7 +1758,7 @@ mod tests { engine.step(); // step 3 - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr2, "0".into()); assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None); @@ -1766,7 +1766,7 @@ mod tests { // step 4 // the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages - let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b3 = b3.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1799,7 +1799,7 @@ mod tests { engine.register_client(Arc::downgrade(&client) as _); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1809,7 +1809,7 @@ mod tests { // step 3 // the signer of the accumulated empty step message should be rewarded - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); // after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index de3c9c50f89..f933e5b20f2 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -251,7 +251,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index f17f7c5fe00..d2c44ff998b 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -86,7 +86,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index ec9c4d6587d..681bed2d0e6 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -798,7 +798,7 @@ mod tests { let db = spec.ensure_db_good(db, &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close(); if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 95f000195cd..542804ef282 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -535,7 +535,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap()); } @@ -584,7 +584,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let mut uncle = Header::new(); let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into(); uncle.set_author(uncle_author); @@ -602,7 +602,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); let b = b.close(); let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into(); diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 8a9216a245f..d9885875e79 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -22,7 +22,7 @@ use tempdir::TempDir; use error::Error; use blockchain::generator::{BlockGenerator, BlockBuilder}; -use blockchain::BlockChain; +use blockchain::{BlockChain, ExtrasInsert}; use snapshot::{chunk_secondary, Error as SnapshotError, Progress, SnapshotComponents}; use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter}; @@ -48,10 +48,12 @@ fn chunk_and_restore(amount: u64) { // build the blockchain. let mut batch = DBTransaction::new(); - let mut total_difficulty = *genesis.header.difficulty(); for block in generator { - total_difficulty = total_difficulty + *block.header.difficulty(); - bc.insert_block(&mut batch, &block.encoded(), vec![], total_difficulty, true); + bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { + is_new_best: true, + is_finalized: false, + metadata: None, + }); bc.commit(); } diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index 72d0d473716..a5005436052 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -87,6 +87,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + Box::new(Vec::new().into_iter()), ).unwrap(); rolling_timestamp += 10; root_block.set_timestamp(rolling_timestamp); @@ -115,6 +116,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, + Box::new(Vec::new().into_iter()), ).unwrap(); rolling_timestamp += 10; parent_block.set_timestamp(rolling_timestamp); @@ -141,7 +143,8 @@ fn can_trace_block_and_uncle_reward() { author.clone(), (3141562.into(), 31415620.into()), vec![], - false + false, + Box::new(Vec::new().into_iter()), ).unwrap(); rolling_timestamp += 10; block.set_timestamp(rolling_timestamp); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 5250434311a..86e1ec3ddbd 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -454,8 +454,8 @@ mod tests { total_difficulty: header.difficulty().clone(), parent: header.parent_hash().clone(), children: Vec::new(), - finalized: false, - metadata: Default::default(), + is_finalized: false, + metadata: None, } }) } From 704e697ea9708dfaaa0997198135cbc3da34e0de Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 18:25:57 +0800 Subject: [PATCH 43/64] Emission of ancestry actions --- ethcore/src/client/client.rs | 9 +++++++++ ethcore/src/engines/mod.rs | 7 +++++++ ethcore/src/machine.rs | 1 + ethcore/types/src/ancestry_action.rs | 27 +++++++++++++++++++++++++++ ethcore/types/src/lib.rs | 1 + machine/src/lib.rs | 2 ++ 6 files changed, 47 insertions(+) create mode 100644 ethcore/types/src/ancestry_action.rs diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b684917dedf..201ca83b78a 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -72,6 +72,7 @@ use trace::{TraceDB, ImportRequest as TraceImportRequest, LocalizedTrace, Databa use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTransaction, Transaction, Action}; use types::filter::Filter; use types::mode::Mode as IpcMode; +use types::ancestry_action::AncestryAction; use verification; use verification::{PreverifiedBlock, Verifier}; use verification::queue::BlockQueue; @@ -522,6 +523,8 @@ impl Importer { let mut batch = DBTransaction::new(); + let ancestry_actions = self.engine.ancestry_actions(block.block(), chain.ancestry_header_iter(*parent)); + let metadata = block.block().metadata().map(Into::into); let is_finalized = block.block().is_finalized(); @@ -568,6 +571,12 @@ impl Importer { ); state.journal_under(&mut batch, number, hash).expect("DB commit failed"); + + for ancestry_action in ancestry_actions { + let AncestryAction::MarkFinalized(ancestry) = ancestry_action; + chain.mark_finalized(&mut batch, ancestry); + } + let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { is_new_best: is_new_best, is_finalized: is_finalized, diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index bcd4efd9e03..5b477e394aa 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -57,6 +57,7 @@ use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; use ethereum_types::{H256, U256, Address}; use unexpected::{Mismatch, OutOfBounds}; use bytes::Bytes; +use types::ancestry_action::AncestryAction; /// Default EIP-210 contrat code. /// As defined in https://github.com/ethereum/EIPs/pull/210 @@ -342,6 +343,12 @@ pub trait Engine: Sync + Send { header_timestamp > parent_timestamp } + /// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that + /// the ancestry exists. + fn ancestry_actions<'a>(&self, _block: &M::LiveBlock, _ancestry: Box + 'a>) -> Vec { + Vec::new() + } + /// Check whether the given new block is the best block. fn is_new_best(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> bool; } diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index c1be80588d4..f897b50eeee 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -410,6 +410,7 @@ impl ::parity_machine::Machine for EthereumMachine { type LiveBlock = ExecutedBlock; type EngineClient = ::client::EngineClient; type AuxiliaryRequest = AuxiliaryRequest; + type AncestryAction = ::types::ancestry_action::AncestryAction; type Error = Error; } diff --git a/ethcore/types/src/ancestry_action.rs b/ethcore/types/src/ancestry_action.rs new file mode 100644 index 00000000000..d9915cfee42 --- /dev/null +++ b/ethcore/types/src/ancestry_action.rs @@ -0,0 +1,27 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Actions on ancestry blocks when working on a new block. + +use ethereum_types::H256; + +#[derive(Debug, PartialEq, Eq, Clone)] +/// Actions on a live block's parent block. Only committed when the live block is committed. Those actions here must +/// respect the normal blockchain reorganization rules. +pub enum AncestryAction { + /// Mark an ancestry block as finalized. + MarkFinalized(H256), +} diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 83a1cc65579..18e0dde86ad 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -46,6 +46,7 @@ pub mod state_diff; pub mod trace_filter; pub mod tree_route; pub mod verification_queue_info; +pub mod ancestry_action; /// Type for block number. pub type BlockNumber = u64; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 2f0de4a545a..5a098334e7f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -124,6 +124,8 @@ pub trait Machine: for<'a> LocalizedMachine<'a> { type EngineClient: ?Sized; /// A description of needed auxiliary data. type AuxiliaryRequest; + /// Actions taken on ancestry blocks when commiting a new block. + type AncestryAction; /// Errors which can occur when querying or interacting with the machine. type Error; From fdadd4293fe66aeb9ea4507f77b0bd5ba3e1bd6f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 20:07:42 +0800 Subject: [PATCH 44/64] use_short_version should take account of metadata --- ethcore/src/blockchain/extras.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 24d03be15de..3fb25e7b1b1 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -186,7 +186,7 @@ pub struct BlockDetails { impl rlp::Encodable for BlockDetails { fn rlp_append(&self, stream: &mut rlp::RlpStream) { - let use_short_version = !self.is_finalized; + let use_short_version = self.metadata.is_none() && !self.is_finalized; match use_short_version { true => { stream.begin_list(4); }, From 60a7a17628e8353327d9f71dbf1ad89d16a32733 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 20:25:55 +0800 Subject: [PATCH 45/64] Engine::is_new_best -> Engine::fork_choice --- ethcore/src/client/client.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 4 ++-- ethcore/src/engines/basic_authority.rs | 4 ++-- ethcore/src/engines/instant_seal.rs | 4 ++-- ethcore/src/engines/mod.rs | 16 ++-------------- ethcore/src/engines/null_engine.rs | 4 ++-- ethcore/src/engines/tendermint/mod.rs | 4 ++-- ethcore/src/ethereum/ethash.rs | 4 ++-- 8 files changed, 15 insertions(+), 27 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 201ca83b78a..e8509efb135 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -551,7 +551,7 @@ impl Importer { } }; - let is_new_best = self.engine.is_new_best(&new, &best); + let is_new_best = self.engine.fork_choice(&new, &best); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index e6a9efb47fc..9ef72d904da 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1321,8 +1321,8 @@ impl Engine for AuthorityRound { } } - fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { - super::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index f933e5b20f2..f79528157e1 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,8 +192,8 @@ impl Engine for BasicAuthority { None } - fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { - super::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index d2c44ff998b..5a94544f252 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,8 +64,8 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn is_new_best(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { - super::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { + super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 5b477e394aa..aef8b6582f4 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -49,8 +49,6 @@ use header::{Header, BlockNumber}; use snapshot::SnapshotComponents; use spec::CommonParams; use transaction::{self, UnverifiedTransaction, SignedTransaction}; -use views::BlockView; -use blockchain::BlockProvider; use ethkey::Signature; use parity_machine::{Machine, LocalizedMachine as Localized, TotalScoredHeader}; @@ -350,21 +348,11 @@ pub trait Engine: Sync + Send { } /// Check whether the given new block is the best block. - fn is_new_best(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> bool; -} - -/// Generate metadata for a new block based on the default total difficulty rule. -pub fn total_difficulty_generate_metadata(bytes: &[u8], provider: &BlockProvider) -> U256 { - let block = view!(BlockView, bytes); - let header = block.header_view(); - let parent_hash = header.parent_hash(); - let parent_details = provider.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - - parent_details.total_difficulty + header.difficulty() + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> bool; } /// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_is_new_best(new: &T, best: &T) -> bool where ::Value: Ord { +pub fn total_difficulty_fork_choice(new: &T, best: &T) -> bool where ::Value: Ord { new.total_score() > best.total_score() } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index ba3666c5b4e..e74eb10a06c 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn is_new_best(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { - super::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { + super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 681bed2d0e6..7ec82a33162 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -760,8 +760,8 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { - super::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 542804ef282..232b46970a1 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -358,8 +358,8 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn is_new_best(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { - engines::total_difficulty_is_new_best(new, current) + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + engines::total_difficulty_fork_choice(new, current) } } From 78569a0467f1a8be5b63762b818c735ac8e44531 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 20:31:37 +0800 Subject: [PATCH 46/64] Use proper expect format as defined in #1026 --- ethcore/src/blockchain/blockchain.rs | 9 +++++---- ethcore/src/client/client.rs | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 905edba9892..638bd54e5ff 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -415,9 +415,9 @@ impl<'a> AncestryIter<'a> { Box::new(self.map(move |hash| { let header = chain.block_header_data(&hash) - .expect("Ancestry must be in the database.").decode(); + .expect("Initial hash is checked by iterator constructor; parent block is in the database; qed").decode(); let details = chain.block_details(&hash) - .expect("Ancestry must be in the database."); + .expect("Initial hash is checked by iterator constructor; parent block is in the database; qed"); ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), @@ -1011,11 +1011,12 @@ impl BlockChain { } /// Mark a block to be considered finalized. Panic if the block hash is not found. - pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) { - let mut block_details = self.block_details(&block_hash).expect("Block hash should exist from caller."); + pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Option<()> { + let mut block_details = self.block_details(&block_hash)?; block_details.is_finalized = true; self.update_block_details(batch, block_hash, block_details); + Some(()) } /// Prepares extras block detail update. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e8509efb135..76d11098ba9 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -538,9 +538,9 @@ impl Importer { let best = { let hash = chain.best_block_hash(); let header = chain.block_header_data(&hash) - .expect("Best block must be in the database.").decode(); + .expect("Best block is in the database; qed").decode(); let details = chain.block_details(&hash) - .expect("Best block must be in the database."); + .expect("Best block is in the database; qed"); ExtendedHeader { parent_total_difficulty: details.total_difficulty - *header.difficulty(), @@ -574,7 +574,7 @@ impl Importer { for ancestry_action in ancestry_actions { let AncestryAction::MarkFinalized(ancestry) = ancestry_action; - chain.mark_finalized(&mut batch, ancestry); + chain.mark_finalized(&mut batch, ancestry).expect("Engine's ancestry action must be known blocks; qed"); } let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { From 8d6629b3b733ce0e7e72fa60e8e49919fe6d5b2c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 20:34:43 +0800 Subject: [PATCH 47/64] panic -> expect --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 76d11098ba9..ee8aa9a4cd3 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -532,7 +532,7 @@ impl Importer { header: header.clone(), is_finalized: is_finalized, metadata: metadata, - parent_total_difficulty: chain.block_details(&parent).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent)).total_difficulty + parent_total_difficulty: chain.block_details(&parent).expect("Parent block is in the database; qed").total_difficulty }; let best = { From fda5e7523419df027e25fb1855a40bd158980bc6 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 20:39:36 +0800 Subject: [PATCH 48/64] ancestry_header -> ancestry_with_metadata --- ethcore/src/blockchain/blockchain.rs | 6 +++--- ethcore/src/client/client.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 638bd54e5ff..4f2837bdc07 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -410,7 +410,7 @@ impl<'a> Iterator for AncestryIter<'a> { } impl<'a> AncestryIter<'a> { - pub fn to_header_iter(self) -> Box + 'a> { + pub fn to_with_metadata_iter(self) -> Box + 'a> { let chain = self.chain; Box::new(self.map(move |hash| { @@ -1150,7 +1150,7 @@ impl BlockChain { } /// Iterator that lists `first` and then all of `first`'s ancestors, by extended header. - pub fn ancestry_header_iter<'a>(&'a self, first: H256) -> Box + 'a> { + pub fn ancestry_with_metadata_iter<'a>(&'a self, first: H256) -> Box + 'a> { let hash_iter = AncestryIter { current: if self.is_known(&first) { first @@ -1160,7 +1160,7 @@ impl BlockChain { chain: self }; - hash_iter.to_header_iter() + hash_iter.to_with_metadata_iter() } /// Given a block's `parent`, find every block header which represents a valid possible uncle. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ee8aa9a4cd3..050d3c7d60f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -428,7 +428,7 @@ impl Importer { client.factories.clone(), is_epoch_begin, strip_receipts, - chain.ancestry_header_iter(*header.parent_hash()), + chain.ancestry_with_metadata_iter(*header.parent_hash()), ); let locked_block = enact_result.map_err(|e| { @@ -523,7 +523,7 @@ impl Importer { let mut batch = DBTransaction::new(); - let ancestry_actions = self.engine.ancestry_actions(block.block(), chain.ancestry_header_iter(*parent)); + let ancestry_actions = self.engine.ancestry_actions(block.block(), chain.ancestry_with_metadata_iter(*parent)); let metadata = block.block().metadata().map(Into::into); let is_finalized = block.block().is_finalized(); @@ -2077,7 +2077,7 @@ impl PrepareOpenBlock for Client { gas_range_target, extra_data, is_epoch_begin, - chain.ancestry_header_iter(best_header.hash()), + chain.ancestry_with_metadata_iter(best_header.hash()), ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles From 45f144d330067b8b56dd50045fe121e50dd80378 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 21:01:05 +0800 Subject: [PATCH 49/64] Boxed iterator -> &mut iterator --- ethcore/src/block.rs | 10 ++-- ethcore/src/blockchain/blockchain.rs | 56 +++++++++++++--------- ethcore/src/client/client.rs | 6 +-- ethcore/src/client/test_client.rs | 2 +- ethcore/src/engines/authority_round/mod.rs | 4 +- ethcore/src/engines/mod.rs | 6 +-- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/test_helpers.rs | 2 +- 8 files changed, 50 insertions(+), 38 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 3ba765306a2..46cf225dc9a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -282,7 +282,7 @@ impl<'x> OpenBlock<'x> { gas_range_target: (U256, U256), extra_data: Bytes, is_epoch_begin: bool, - ancestry: Box + 'a>, + ancestry: &mut Iterator, ) -> Result { let number = parent.number() + 1; let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?; @@ -592,7 +592,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -fn enact<'a>( +fn enact( header: Header, transactions: Vec, uncles: Vec
, @@ -604,7 +604,7 @@ fn enact<'a>( factories: Factories, is_epoch_begin: bool, strip_receipts: bool, - ancestry: Box + 'a>, + ancestry: &mut Iterator, ) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { @@ -645,7 +645,7 @@ fn enact<'a>( } /// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header -pub fn enact_verified<'a>( +pub fn enact_verified( block: PreverifiedBlock, engine: &EthEngine, tracing: bool, @@ -656,7 +656,7 @@ pub fn enact_verified<'a>( is_epoch_begin: bool, // Remove state root from transaction receipts to make them EIP-98 compatible. strip_receipts: bool, - ancestry: Box + 'a>, + ancestry: &mut Iterator, ) -> Result { let view = view!(BlockView, &block.bytes); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 4f2837bdc07..d2967809310 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -409,24 +409,38 @@ impl<'a> Iterator for AncestryIter<'a> { } } -impl<'a> AncestryIter<'a> { - pub fn to_with_metadata_iter(self) -> Box + 'a> { - let chain = self.chain; - - Box::new(self.map(move |hash| { - let header = chain.block_header_data(&hash) - .expect("Initial hash is checked by iterator constructor; parent block is in the database; qed").decode(); - let details = chain.block_details(&hash) - .expect("Initial hash is checked by iterator constructor; parent block is in the database; qed"); - - ExtendedHeader { - parent_total_difficulty: details.total_difficulty - *header.difficulty(), - is_finalized: details.is_finalized, - metadata: details.metadata, - - header: header, +/// An iterator which walks the blockchain towards the genesis, with metadata information. +pub struct AncestryWithMetadataIter<'a> { + current: H256, + chain: &'a BlockChain, +} + +impl<'a> Iterator for AncestryWithMetadataIter<'a> { + type Item = ExtendedHeader; + fn next(&mut self) -> Option { + if self.current.is_zero() { + None + } else { + let details = self.chain.block_details(&self.current); + let header = self.chain.block_header_data(&self.current).map(|h| h.decode()); + + match (details, header) { + (Some(details), Some(header)) => { + self.current = details.parent; + Some(ExtendedHeader { + parent_total_difficulty: details.total_difficulty - *header.difficulty(), + is_finalized: details.is_finalized, + metadata: details.metadata, + + header: header, + }) + }, + _ => { + self.current = H256::default(); + None + }, } - })) + } } } @@ -1150,17 +1164,15 @@ impl BlockChain { } /// Iterator that lists `first` and then all of `first`'s ancestors, by extended header. - pub fn ancestry_with_metadata_iter<'a>(&'a self, first: H256) -> Box + 'a> { - let hash_iter = AncestryIter { + pub fn ancestry_with_metadata_iter<'a>(&'a self, first: H256) -> AncestryWithMetadataIter { + AncestryWithMetadataIter { current: if self.is_known(&first) { first } else { H256::default() // zero hash }, chain: self - }; - - hash_iter.to_with_metadata_iter() + } } /// Given a block's `parent`, find every block header which represents a valid possible uncle. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 050d3c7d60f..9a22d303c9b 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -428,7 +428,7 @@ impl Importer { client.factories.clone(), is_epoch_begin, strip_receipts, - chain.ancestry_with_metadata_iter(*header.parent_hash()), + &mut chain.ancestry_with_metadata_iter(*header.parent_hash()), ); let locked_block = enact_result.map_err(|e| { @@ -523,7 +523,7 @@ impl Importer { let mut batch = DBTransaction::new(); - let ancestry_actions = self.engine.ancestry_actions(block.block(), chain.ancestry_with_metadata_iter(*parent)); + let ancestry_actions = self.engine.ancestry_actions(block.block(), &mut chain.ancestry_with_metadata_iter(*parent)); let metadata = block.block().metadata().map(Into::into); let is_finalized = block.block().is_finalized(); @@ -2077,7 +2077,7 @@ impl PrepareOpenBlock for Client { gas_range_target, extra_data, is_epoch_begin, - chain.ancestry_with_metadata_iter(best_header.hash()), + &mut chain.ancestry_with_metadata_iter(best_header.hash()), ).expect("OpenBlock::new only fails if parent state root invalid; state root of best block's header is never invalid; qed"); // Add uncles diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 6b6d408d504..b89682520de 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -392,7 +392,7 @@ impl PrepareOpenBlock for TestBlockChainClient { gas_range_target, extra_data, false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), ).expect("Opening block for tests will not fail."); // TODO [todr] Override timestamp for predictability open_block.set_timestamp(*self.latest_block_timestamp.read()); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 9ef72d904da..a5f8b6261ed 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -941,11 +941,11 @@ impl Engine for AuthorityRound { Ok(()) } - fn on_new_block<'a>( + fn on_new_block( &self, block: &mut ExecutedBlock, epoch_begin: bool, - _ancestry: Box + 'a>, + _ancestry: &mut Iterator, ) -> Result<(), Error> { // with immediate transitions, we don't use the epoch mechanism anyway. // the genesis is always considered an epoch, but we ignore it intentionally. diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index aef8b6582f4..1416a7d2532 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -195,11 +195,11 @@ pub trait Engine: Sync + Send { /// Block transformation functions, before the transactions. /// `epoch_begin` set to true if this block kicks off an epoch. - fn on_new_block<'a>( + fn on_new_block( &self, _block: &mut M::LiveBlock, _epoch_begin: bool, - _ancestry: Box + 'a>, + _ancestry: &mut Iterator, ) -> Result<(), M::Error> { Ok(()) } @@ -343,7 +343,7 @@ pub trait Engine: Sync + Send { /// Gather all ancestry actions. Called at the last stage when a block is committed. The Engine must guarantee that /// the ancestry exists. - fn ancestry_actions<'a>(&self, _block: &M::LiveBlock, _ancestry: Box + 'a>) -> Vec { + fn ancestry_actions(&self, _block: &M::LiveBlock, _ancestry: &mut Iterator) -> Vec { Vec::new() } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 7ec82a33162..8382312128b 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -527,7 +527,7 @@ impl Engine for Tendermint { Ok(()) } - fn on_new_block<'a>(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: Box + 'a>) -> Result<(), Error> { + fn on_new_block<'a>(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: &mut Iterator) -> Result<(), Error> { if !epoch_begin { return Ok(()) } // genesis is never a new block, but might as well check. diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 06f9f489732..4d79b2bf735 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -148,7 +148,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(test_spec: F, accoun (3141562.into(), 31415620.into()), vec![], false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; b.set_timestamp(rolling_timestamp); From 86d1ef2ba0d3a7ba42339b1d7311929fd7a3aca2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 21:04:23 +0800 Subject: [PATCH 50/64] Fix tests --- ethcore/src/block.rs | 8 ++++---- ethcore/src/engines/authority_round/mod.rs | 24 +++++++++++----------- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 6 +++--- ethcore/src/tests/trace.rs | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 46cf225dc9a..34dd8c24da3 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -730,7 +730,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), )?; b.populate_from(&header); @@ -764,7 +764,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); let _ = b.seal(&*spec.engine, vec![]); } @@ -778,7 +778,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap() + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap() .close_and_lock().seal(engine, vec![]).unwrap(); let orig_bytes = b.rlp_bytes(); let orig_db = b.drain(); @@ -802,7 +802,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle1_header = Header::new(); uncle1_header.set_extra_data(b"uncle1".to_vec()); let mut uncle2_header = Header::new(); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index a5f8b6261ed..b586e18accd 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1383,9 +1383,9 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1417,9 +1417,9 @@ mod tests { let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1666,7 +1666,7 @@ mod tests { let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); let client = generate_dummy_client(0); @@ -1701,7 +1701,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1710,7 +1710,7 @@ mod tests { engine.step(); // step 3 - let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); b2.push_transaction(Transaction { action: Action::Create, nonce: U256::from(0), @@ -1749,7 +1749,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1758,7 +1758,7 @@ mod tests { engine.step(); // step 3 - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr2, "0".into()); assert_eq!(engine.generate_seal(b2.block(), &genesis_header), Seal::None); @@ -1766,7 +1766,7 @@ mod tests { // step 4 // the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages - let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b3 = b3.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); @@ -1799,7 +1799,7 @@ mod tests { engine.register_client(Arc::downgrade(&client) as _); // step 2 - let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b1 = b1.close_and_lock(); // since the block is empty it isn't sealed and we generate empty steps @@ -1809,7 +1809,7 @@ mod tests { // step 3 // the signer of the accumulated empty step message should be rewarded - let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); // after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index f79528157e1..533830a7570 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -251,7 +251,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 5a94544f252..726f7b3f6a3 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -86,7 +86,7 @@ mod tests { let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 8382312128b..006bd6b740e 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -798,7 +798,7 @@ mod tests { let db = spec.ensure_db_good(db, &Default::default()).unwrap(); let genesis_header = spec.genesis_header(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 232b46970a1..dea0d907bff 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -535,7 +535,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); assert_eq!(b.state().balance(&Address::zero()).unwrap(), U256::from_str("4563918244f40000").unwrap()); } @@ -584,7 +584,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let mut uncle = Header::new(); let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into(); uncle.set_author(uncle_author); @@ -602,7 +602,7 @@ mod tests { let genesis_header = spec.genesis_header(); let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, Box::new(Vec::new().into_iter())).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![], false, &mut Vec::new().into_iter()).unwrap(); let b = b.close(); let ubi_contract: Address = "00efdd5883ec628983e9063c7d969fe268bbf310".into(); diff --git a/ethcore/src/tests/trace.rs b/ethcore/src/tests/trace.rs index a5005436052..a98667b1423 100644 --- a/ethcore/src/tests/trace.rs +++ b/ethcore/src/tests/trace.rs @@ -87,7 +87,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; root_block.set_timestamp(rolling_timestamp); @@ -116,7 +116,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; parent_block.set_timestamp(rolling_timestamp); @@ -144,7 +144,7 @@ fn can_trace_block_and_uncle_reward() { (3141562.into(), 31415620.into()), vec![], false, - Box::new(Vec::new().into_iter()), + &mut Vec::new().into_iter(), ).unwrap(); rolling_timestamp += 10; block.set_timestamp(rolling_timestamp); From 728172668e4109cae8fe4a2798df4b9cd2aadbf4 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 18 Apr 2018 23:25:09 +0800 Subject: [PATCH 51/64] is_new_best -> primitive_fork_choice --- ethcore/src/blockchain/blockchain.rs | 17 +++++++++++++---- ethcore/src/blockchain/update.rs | 4 ++-- ethcore/src/client/client.rs | 6 +++--- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 19 ++++++++++++++++--- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/snapshot/tests/proof_of_work.rs | 2 +- ethcore/src/test_helpers.rs | 4 ++-- 12 files changed, 43 insertions(+), 21 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index d2967809310..ade9f782db3 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -43,6 +43,7 @@ use blockchain::{CacheSize, ImportRoute, Config}; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; use encoded; +use engines::ForkChoice; use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition}; use rayon::prelude::*; use ansi_term::Colour; @@ -992,8 +993,12 @@ impl BlockChain { hash: hash, number: number, total_difficulty: parent_details.total_difficulty + header.difficulty(), - location: if extras.is_new_best { - // on new best block we need to make sure that all ancestors + location: if extras.primitive_fork_choice == ForkChoice::New { + // The primitive fork choice does not mean we accept it as + // the new best block. It still needs to be checked by + // finalization rules. + // + // On new best block we need to make sure that all ancestors // are moved to "canon chain" // find the route between old best block and the new one let best_hash = self.best_block_hash(); @@ -1540,10 +1545,14 @@ mod tests { let parent_hash = header.parent_hash(); let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); - let is_new_best = block_total_difficulty > bc.best_block_total_difficulty(); + let primitive_fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { + ::engines::ForkChoice::New + } else { + ::engines::ForkChoice::Old + }; bc.insert_block(batch, bytes, receipts, ExtrasInsert { - is_new_best: is_new_best, + primitive_fork_choice: primitive_fork_choice, is_finalized: false, metadata: None }) diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index f4e4a6d346a..7cf0bf3db1f 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -25,8 +25,8 @@ pub struct ExtrasUpdate<'a> { /// Extra information in block insertion. pub struct ExtrasInsert { - /// Is the inserted block considered the best block. - pub is_new_best: bool, + /// The primitive fork choice before applying finalization rules. + pub primitive_fork_choice: ::engines::ForkChoice, /// Is the inserted block considered finalized. pub is_finalized: bool, /// New block local metadata. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9a22d303c9b..e1aaa93b893 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -551,7 +551,7 @@ impl Importer { } }; - let is_new_best = self.engine.fork_choice(&new, &best); + let fork_choice = self.engine.fork_choice(&new, &best); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. @@ -578,7 +578,7 @@ impl Importer { } let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { - is_new_best: is_new_best, + primitive_fork_choice: fork_choice, is_finalized: is_finalized, metadata: new.metadata, }); @@ -2311,7 +2311,7 @@ mod tests { thread::spawn(move || { let mut batch = DBTransaction::new(); another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { - is_new_best: true, + primitive_fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index b586e18accd..e10fb36b879 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1321,7 +1321,7 @@ impl Engine for AuthorityRound { } } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 533830a7570..e99fd88dcbc 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 726f7b3f6a3..c16203f1053 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 1416a7d2532..a4c294ba6d8 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -61,6 +61,15 @@ use types::ancestry_action::AncestryAction; /// As defined in https://github.com/ethereum/EIPs/pull/210 pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b"; +/// Fork choice. +#[derive(Debug, PartialEq, Eq)] +pub enum ForkChoice { + /// Choose the new block. + New, + /// Choose the current best block. + Old, +} + /// Voting errors. #[derive(Debug)] pub enum EngineError { @@ -348,12 +357,16 @@ pub trait Engine: Sync + Send { } /// Check whether the given new block is the best block. - fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> bool; + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; } /// Check whether a given block is the best block based on the default total difficulty rule. -pub fn total_difficulty_fork_choice(new: &T, best: &T) -> bool where ::Value: Ord { - new.total_score() > best.total_score() +pub fn total_difficulty_fork_choice(new: &T, best: &T) -> ForkChoice where ::Value: Ord { + if new.total_score() > best.total_score() { + ForkChoice::New + } else { + ForkChoice::Old + } } /// Common type alias for an engine coupled with an Ethereum-like state machine. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index e74eb10a06c..33cf9228e1c 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> bool { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 006bd6b740e..4942c4a807c 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -760,7 +760,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index dea0d907bff..cb373b15e8b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -358,7 +358,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> bool { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { engines::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index d9885875e79..785c2e82244 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -50,7 +50,7 @@ fn chunk_and_restore(amount: u64) { let mut batch = DBTransaction::new(); for block in generator { bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { - is_new_best: true, + primitive_fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 4d79b2bf735..39fbe3f7913 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -268,7 +268,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { for block_order in 1..block_number { // Total difficulty is always 0 here. bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { - is_new_best: true, + primitive_fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); @@ -288,7 +288,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { for block_order in 1..block_number { // Total difficulty is always 0 here. bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { - is_new_best: true, + primitive_fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); From d86a0563a71e1a906af48f467fda416d83ddc349 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 19 Apr 2018 00:38:32 +0800 Subject: [PATCH 52/64] Document how fork_choice works --- ethcore/src/engines/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index a4c294ba6d8..74f11b7bf91 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -356,7 +356,9 @@ pub trait Engine: Sync + Send { Vec::new() } - /// Check whether the given new block is the best block. + /// Check whether the given new block is the best block. The client will first use this function to determine the + /// primitive fork choice rules, and then check on the finalization rules, which might overwrite the primitive fork + /// choice. Note this may not work in some edge cases. fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; } From e7a83f42abe4904dfac53d8706826f035349318f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 19 Apr 2018 03:49:02 +0800 Subject: [PATCH 53/64] Engine::fork_choice -> Engine::primitive_fork_choice --- ethcore/src/client/client.rs | 4 ++-- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 4 +++- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 4 ++-- ethcore/src/ethereum/ethash.rs | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e1aaa93b893..96d3196e12d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -551,7 +551,7 @@ impl Importer { } }; - let fork_choice = self.engine.fork_choice(&new, &best); + let primitive_fork_choice = self.engine.primitive_fork_choice(&new, &best); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. @@ -578,7 +578,7 @@ impl Importer { } let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { - primitive_fork_choice: fork_choice, + primitive_fork_choice: primitive_fork_choice, is_finalized: is_finalized, metadata: new.metadata, }); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index e10fb36b879..b3189017d1d 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1321,7 +1321,7 @@ impl Engine for AuthorityRound { } } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index e99fd88dcbc..6f3e75e2cd4 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index c16203f1053..fadb6a0217d 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + fn primitive_fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 74f11b7bf91..ca90f82bdeb 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -359,7 +359,9 @@ pub trait Engine: Sync + Send { /// Check whether the given new block is the best block. The client will first use this function to determine the /// primitive fork choice rules, and then check on the finalization rules, which might overwrite the primitive fork /// choice. Note this may not work in some edge cases. - fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; + /// + /// If finalization rules do not exist. Primitive fork choice is the final fork choice. + fn primitive_fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; } /// Check whether a given block is the best block based on the default total difficulty rule. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 33cf9228e1c..bac43724658 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + fn primitive_fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 4942c4a807c..75622eb00c8 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -527,7 +527,7 @@ impl Engine for Tendermint { Ok(()) } - fn on_new_block<'a>(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: &mut Iterator) -> Result<(), Error> { + fn on_new_block(&self, block: &mut ExecutedBlock, epoch_begin: bool, _ancestry: &mut Iterator) -> Result<(), Error> { if !epoch_begin { return Ok(()) } // genesis is never a new block, but might as well check. @@ -760,7 +760,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index cb373b15e8b..7318828c87e 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -358,7 +358,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { + fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { engines::total_difficulty_fork_choice(new, current) } } From 6b6b042bc92fbfe3f0bc3713250220ada61856da Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 19 Apr 2018 15:25:11 +0800 Subject: [PATCH 54/64] comment: clarify types of finalization where Engine::primitive_fork_choice works --- ethcore/src/engines/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index ca90f82bdeb..7bc3b981ade 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -358,7 +358,8 @@ pub trait Engine: Sync + Send { /// Check whether the given new block is the best block. The client will first use this function to determine the /// primitive fork choice rules, and then check on the finalization rules, which might overwrite the primitive fork - /// choice. Note this may not work in some edge cases. + /// choice. This function works for Casper-like finality check, but may not work well for some types of instant + /// finality. /// /// If finalization rules do not exist. Primitive fork choice is the final fork choice. fn primitive_fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; From c593e1784f7ab9ffaa6488d9ce5e2a46ed7035b7 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 21 Apr 2018 11:11:47 +0800 Subject: [PATCH 55/64] Expose FinalizationInfo to Engine --- ethcore/src/blockchain/blockchain.rs | 52 +++++++++++---------- ethcore/src/blockchain/update.rs | 2 +- ethcore/src/client/client.rs | 15 ++++-- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 18 ++++--- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/snapshot/tests/proof_of_work.rs | 2 +- ethcore/src/test_helpers.rs | 4 +- 12 files changed, 58 insertions(+), 47 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index ade9f782db3..1d80ee29622 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -939,7 +939,22 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras:ExtrasInsert) -> ImportRoute { + let block = view!(BlockView, bytes); + let header = block.header_view(); + + let parent_hash = header.parent_hash(); + let best_hash = self.best_block_hash(); + + let route = self.tree_route(best_hash, parent_hash).expect("blocks being imported always within recent history; qed"); + + self.insert_block_with_route(batch, bytes, receipts, route, extras) + } + + /// Inserts the block into backing cache database with already generated route information. + /// Expects the block to be valid and already verified and route is tree route information from current best block to new block's parent. + /// If the block is already known, does nothing. + pub fn insert_block_with_route(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, route: TreeRoute, extras: ExtrasInsert) -> ImportRoute { // create views onto rlp let block = view!(BlockView, bytes); let header = block.header_view(); @@ -958,7 +973,7 @@ impl BlockChain { batch.put(db::COL_HEADERS, &hash, &compressed_header); batch.put(db::COL_BODIES, &hash, &compressed_body); - let info = self.block_info(&header, &extras); + let info = self.block_info(&header, route, &extras); if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", @@ -983,7 +998,7 @@ impl BlockChain { } /// Get inserted block info which is critical to prepare extras updates. - fn block_info(&self, header: &HeaderView, extras: &ExtrasInsert) -> BlockInfo { + fn block_info(&self, header: &HeaderView, route: TreeRoute, extras: &ExtrasInsert) -> BlockInfo { let hash = header.hash(); let number = header.number(); let parent_hash = header.parent_hash(); @@ -993,23 +1008,11 @@ impl BlockChain { hash: hash, number: number, total_difficulty: parent_details.total_difficulty + header.difficulty(), - location: if extras.primitive_fork_choice == ForkChoice::New { - // The primitive fork choice does not mean we accept it as - // the new best block. It still needs to be checked by - // finalization rules. - // - // On new best block we need to make sure that all ancestors - // are moved to "canon chain" - // find the route between old best block and the new one - let best_hash = self.best_block_hash(); - let route = self.tree_route(best_hash, parent_hash) - .expect("blocks being imported always within recent history; qed"); - - assert_eq!(number, parent_details.number + 1); - - if route.is_from_route_finalized { - BlockLocation::Branch - } else { + location: match extras.fork_choice { + ForkChoice::New => { + // On new best block we need to make sure that all ancestors + // are moved to "canon chain" + // find the route between old best block and the new one match route.blocks.len() { 0 => BlockLocation::CanonChain, _ => { @@ -1022,9 +1025,8 @@ impl BlockChain { }) } } - } - } else { - BlockLocation::Branch + }, + ForkChoice::Old => BlockLocation::Branch, }, } } @@ -1545,14 +1547,14 @@ mod tests { let parent_hash = header.parent_hash(); let parent_details = bc.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); let block_total_difficulty = parent_details.total_difficulty + header.difficulty(); - let primitive_fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { + let fork_choice = if block_total_difficulty > bc.best_block_total_difficulty() { ::engines::ForkChoice::New } else { ::engines::ForkChoice::Old }; bc.insert_block(batch, bytes, receipts, ExtrasInsert { - primitive_fork_choice: primitive_fork_choice, + fork_choice: fork_choice, is_finalized: false, metadata: None }) diff --git a/ethcore/src/blockchain/update.rs b/ethcore/src/blockchain/update.rs index 7cf0bf3db1f..b695b9236b0 100644 --- a/ethcore/src/blockchain/update.rs +++ b/ethcore/src/blockchain/update.rs @@ -26,7 +26,7 @@ pub struct ExtrasUpdate<'a> { /// Extra information in block insertion. pub struct ExtrasInsert { /// The primitive fork choice before applying finalization rules. - pub primitive_fork_choice: ::engines::ForkChoice, + pub fork_choice: ::engines::ForkChoice, /// Is the inserted block considered finalized. pub is_finalized: bool, /// New block local metadata. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c204bf896a5..26ac5f97cab 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -48,7 +48,7 @@ use client::{ ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; -use engines::{EthEngine, EpochTransition}; +use engines::{EthEngine, EpochTransition, FinalizationInfo}; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; @@ -532,6 +532,7 @@ impl Importer { let ancestry_actions = self.engine.ancestry_actions(block.block(), &mut chain.ancestry_with_metadata_iter(*parent)); + let best_hash = chain.best_block_hash(); let metadata = block.block().metadata().map(Into::into); let is_finalized = block.block().is_finalized(); @@ -543,7 +544,7 @@ impl Importer { }; let best = { - let hash = chain.best_block_hash(); + let hash = best_hash; let header = chain.block_header_data(&hash) .expect("Best block is in the database; qed").decode(); let details = chain.block_details(&hash) @@ -558,7 +559,11 @@ impl Importer { } }; - let primitive_fork_choice = self.engine.primitive_fork_choice(&new, &best); + let route = chain.tree_route(best_hash, *parent).expect("blocks being imported always within recent history; qed"); + let fork_choice = self.engine.fork_choice(&new, &best, FinalizationInfo { + is_old_route_finalized: route.is_from_route_finalized, + is_new_parent_route_finalized: route.is_to_route_finalized, + }); // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. @@ -585,7 +590,7 @@ impl Importer { } let route = chain.insert_block(&mut batch, block_data, receipts.clone(), ExtrasInsert { - primitive_fork_choice: primitive_fork_choice, + fork_choice: fork_choice, is_finalized: is_finalized, metadata: new.metadata, }); @@ -2318,7 +2323,7 @@ mod tests { thread::spawn(move || { let mut batch = DBTransaction::new(); another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new(), ExtrasInsert { - primitive_fork_choice: ::engines::ForkChoice::New, + fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index b3189017d1d..66668a9d885 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1321,7 +1321,7 @@ impl Engine for AuthorityRound { } } - fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 6f3e75e2cd4..6cb0e2c804c 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index fadb6a0217d..7b2b154c8ec 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn primitive_fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 7bc3b981ade..c1f6c427d09 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -70,6 +70,15 @@ pub enum ForkChoice { Old, } +/// Finalization related information. +#[derive(Debug, PartialEq, Eq)] +pub struct FinalizationInfo { + /// Whether the route from current best block to common ancestor is finalized. + pub is_old_route_finalized: bool, + /// Whether the route from new block's parent to common ancestor is finalized. + pub is_new_parent_route_finalized: bool, +} + /// Voting errors. #[derive(Debug)] pub enum EngineError { @@ -356,13 +365,8 @@ pub trait Engine: Sync + Send { Vec::new() } - /// Check whether the given new block is the best block. The client will first use this function to determine the - /// primitive fork choice rules, and then check on the finalization rules, which might overwrite the primitive fork - /// choice. This function works for Casper-like finality check, but may not work well for some types of instant - /// finality. - /// - /// If finalization rules do not exist. Primitive fork choice is the final fork choice. - fn primitive_fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; + /// Check whether the given new block is the best block. + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader, finalization: FinalizationInfo) -> ForkChoice; } /// Check whether a given block is the best block based on the default total difficulty rule. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index bac43724658..2c82d12294b 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -109,7 +109,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn primitive_fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 75622eb00c8..ea9a63d03e1 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -760,7 +760,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 7318828c87e..f18f8803a19 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -358,7 +358,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn primitive_fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: engines::FinalizationInfo) -> engines::ForkChoice { engines::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index 785c2e82244..9d39fc94c79 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -50,7 +50,7 @@ fn chunk_and_restore(amount: u64) { let mut batch = DBTransaction::new(); for block in generator { bc.insert_block(&mut batch, &block.encoded(), vec![], ExtrasInsert { - primitive_fork_choice: ::engines::ForkChoice::New, + fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); diff --git a/ethcore/src/test_helpers.rs b/ethcore/src/test_helpers.rs index 39fbe3f7913..e57d16a6549 100644 --- a/ethcore/src/test_helpers.rs +++ b/ethcore/src/test_helpers.rs @@ -268,7 +268,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> BlockChain { for block_order in 1..block_number { // Total difficulty is always 0 here. bc.insert_block(&mut batch, &create_unverifiable_block(block_order, bc.best_block_hash()), vec![], ExtrasInsert { - primitive_fork_choice: ::engines::ForkChoice::New, + fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); @@ -288,7 +288,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> BlockChain { for block_order in 1..block_number { // Total difficulty is always 0 here. bc.insert_block(&mut batch, &create_unverifiable_block_with_extra(block_order, bc.best_block_hash(), None), vec![], ExtrasInsert { - primitive_fork_choice: ::engines::ForkChoice::New, + fork_choice: ::engines::ForkChoice::New, is_finalized: false, metadata: None, }); From 0b8e55d5160f8d65e845a7f9e09984011dc43893 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Sat, 21 Apr 2018 11:24:26 +0800 Subject: [PATCH 56/64] Fix tests due to merging --- ethcore/src/engines/authority_round/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index ec20c65e2d4..7bbc90f5b5a 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1964,6 +1964,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let b1 = b1.close_and_lock(); @@ -1985,6 +1986,7 @@ mod tests { (3141562.into(), 31415620.into()), vec![], false, + &mut Vec::new().into_iter(), ).unwrap(); let addr1_balance = b2.block().state().balance(&addr1).unwrap(); From 69cc85614cc6c710171ac6165ebe240e6acd0d64 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 2 May 2018 04:00:00 +0800 Subject: [PATCH 57/64] Remove TotalDifficulty trait --- machine/src/lib.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 5a098334e7f..69fbb0cf83f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -20,7 +20,6 @@ extern crate ethereum_types; use ethereum_types::{H256, U256, Address}; -use std::ops::Add; /// A header. This contains important metadata about the block, as well as a /// "seal" that indicates validity to a consensus engine. @@ -158,10 +157,3 @@ pub trait WithBalances: Machine { _indirect: &[(Address, U256)], ) -> Result<(), Self::Error> { Ok(()) } } - -/// Metadata with total difficulty information. -pub trait TotalDifficulty { - type Value: Ord + Add; - - fn total_difficulty(&self) -> &Self::Value; -} From 60b6def9c0d6c9badb075d222ba8b7b776e295bc Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 02:57:19 +0800 Subject: [PATCH 58/64] Do not pass FinalizationInfo to Engine If there's finalized blocks in from route, choose the old branch without calling `Engine::fork_choice`. --- ethcore/src/client/client.rs | 11 ++++++----- ethcore/src/engines/authority_round/mod.rs | 2 +- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 13 ++----------- ethcore/src/engines/null_engine.rs | 2 +- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/ethereum/ethash.rs | 2 +- 8 files changed, 14 insertions(+), 22 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index f45786dd46d..47288a6d42c 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -48,7 +48,7 @@ use client::{ ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType }; use encoded; -use engines::{EthEngine, EpochTransition, FinalizationInfo}; +use engines::{EthEngine, EpochTransition, ForkChoice}; use error::{ImportErrorKind, BlockImportErrorKind, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use vm::{EnvInfo, LastHashes}; use evm::Schedule; @@ -526,10 +526,11 @@ impl Importer { }; let route = chain.tree_route(best_hash, *parent).expect("blocks being imported always within recent history; qed"); - let fork_choice = self.engine.fork_choice(&new, &best, FinalizationInfo { - is_old_route_finalized: route.is_from_route_finalized, - is_new_parent_route_finalized: route.is_to_route_finalized, - }); + let fork_choice = if route.is_from_route_finalized { + ForkChoice::Old + } else { + self.engine.fork_choice(&new, &best) + }; // CHECK! I *think* this is fine, even if the state_root is equal to another // already-imported block of the same number. diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index c3975eccbaf..575cee81d27 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -1350,7 +1350,7 @@ impl Engine for AuthorityRound { } } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 6cb0e2c804c..e99fd88dcbc 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -192,7 +192,7 @@ impl Engine for BasicAuthority { None } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 7b2b154c8ec..c16203f1053 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -64,7 +64,7 @@ impl Engine for InstantSeal header_timestamp >= parent_timestamp } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index b2fe16b733d..0878b4595f1 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -71,15 +71,6 @@ pub enum ForkChoice { Old, } -/// Finalization related information. -#[derive(Debug, PartialEq, Eq)] -pub struct FinalizationInfo { - /// Whether the route from current best block to common ancestor is finalized. - pub is_old_route_finalized: bool, - /// Whether the route from new block's parent to common ancestor is finalized. - pub is_new_parent_route_finalized: bool, -} - /// Voting errors. #[derive(Debug)] pub enum EngineError { @@ -375,8 +366,8 @@ pub trait Engine: Sync + Send { Vec::new() } - /// Check whether the given new block is the best block. - fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader, finalization: FinalizationInfo) -> ForkChoice; + /// Check whether the given new block is the best block, after finalization check. + fn fork_choice(&self, new: &M::ExtendedHeader, best: &M::ExtendedHeader) -> ForkChoice; } /// Check whether a given block is the best block based on the default total difficulty rule. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 496a513650d..c6025e62471 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -105,7 +105,7 @@ impl Engine for NullEngine Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } - fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { + fn fork_choice(&self, new: &M::ExtendedHeader, current: &M::ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index f7e331eb56d..52bf5ff67b8 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -766,7 +766,7 @@ impl Engine for Tendermint { self.validators.register_client(client); } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: super::FinalizationInfo) -> super::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> super::ForkChoice { super::total_difficulty_fork_choice(new, current) } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index aa9f748015e..9b3945e38b1 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -357,7 +357,7 @@ impl Engine for Arc { Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } - fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader, _finalization: engines::FinalizationInfo) -> engines::ForkChoice { + fn fork_choice(&self, new: &ExtendedHeader, current: &ExtendedHeader) -> engines::ForkChoice { engines::total_difficulty_fork_choice(new, current) } } From 15a967b3d6b46c7b71b291931cb76e10de90c41f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 20:45:15 +0800 Subject: [PATCH 59/64] Fix compile --- ethcore/src/blockchain/blockchain.rs | 3 ++- ethcore/src/client/client.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index c486853ea1c..f26b860b269 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -431,7 +431,8 @@ impl<'a> Iterator for AncestryWithMetadataIter<'a> { None } else { let details = self.chain.block_details(&self.current); - let header = self.chain.block_header_data(&self.current).map(|h| h.decode()); + let header = self.chain.block_header_data(&self.current) + .map(|h| h.decode().expect("Stored block header data is valid RLP; qed")); match (details, header) { (Some(details), Some(header)) => { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d6982a703fa..e57f3b7f40f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -486,7 +486,9 @@ impl Importer { let best = { let hash = best_hash; let header = chain.block_header_data(&hash) - .expect("Best block is in the database; qed").decode(); + .expect("Best block is in the database; qed") + .decode() + .expect("Stored block header is valid RLP; qed"); let details = chain.block_details(&hash) .expect("Best block is in the database; qed"); From 8d1d98b0929fd537f62d8eb858e81c7895c58047 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Wed, 9 May 2018 20:45:52 +0800 Subject: [PATCH 60/64] Fix unused import --- ethcore/sync/src/light_sync/response.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/sync/src/light_sync/response.rs b/ethcore/sync/src/light_sync/response.rs index 74665118b7f..3629613224d 100644 --- a/ethcore/sync/src/light_sync/response.rs +++ b/ethcore/sync/src/light_sync/response.rs @@ -16,7 +16,7 @@ //! Helpers for decoding and verifying responses for headers. -use ethcore::{self, encoded, header::Header}; +use ethcore::{encoded, header::Header}; use ethereum_types::H256; use light::request::{HashOrNumber, CompleteHeadersRequest as HeadersRequest}; use rlp::DecoderError; From 63a3f545e50269d6349a602292efa7c8fdbcf7b3 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 11 May 2018 23:30:36 +0800 Subject: [PATCH 61/64] Remove is_to_route_finalized When no block reorg passes a finalized block, this variable is always false. --- ethcore/src/blockchain/blockchain.rs | 4 ---- ethcore/src/client/test_client.rs | 1 - ethcore/types/src/tree_route.rs | 2 -- 3 files changed, 7 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f26b860b269..97ba3cd898f 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -690,7 +690,6 @@ impl BlockChain { let mut from_branch = vec![]; let mut is_from_route_finalized = false; let mut to_branch = vec![]; - let mut is_to_route_finalized = false; let mut from_details = self.block_details(&from)?; let mut to_details = self.block_details(&to)?; @@ -709,7 +708,6 @@ impl BlockChain { to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; - is_to_route_finalized = is_to_route_finalized || to_details.is_finalized; } assert_eq!(from_details.number, to_details.number); @@ -724,7 +722,6 @@ impl BlockChain { to_branch.push(current_to); current_to = to_details.parent.clone(); to_details = self.block_details(&to_details.parent)?; - is_to_route_finalized = is_to_route_finalized || to_details.is_finalized; } let index = from_branch.len(); @@ -736,7 +733,6 @@ impl BlockChain { ancestor: current_from, index: index, is_from_route_finalized: is_from_route_finalized, - is_to_route_finalized: is_to_route_finalized, }) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 8dbeed42646..fab32346572 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -742,7 +742,6 @@ impl BlockChainClient for TestBlockChainClient { if adding { Vec::new() } else { blocks } }, is_from_route_finalized: false, - is_to_route_finalized: false, }) } diff --git a/ethcore/types/src/tree_route.rs b/ethcore/types/src/tree_route.rs index 4df6c2a7091..5d1bddd87b3 100644 --- a/ethcore/types/src/tree_route.rs +++ b/ethcore/types/src/tree_route.rs @@ -29,6 +29,4 @@ pub struct TreeRoute { pub index: usize, /// Whether it has finalized blocks from `from` (inclusive) to `ancestor` (exclusive). pub is_from_route_finalized: bool, - /// Whether it has finalized blocks from `ancestor` (exclusive) to `to` (inclusive). - pub is_to_route_finalized: bool, } From 7b0cd66d0ecf9c9e274ccddfc4baae8da99c8013 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 11 May 2018 23:32:31 +0800 Subject: [PATCH 62/64] Address format grumbles --- ethcore/src/blockchain/blockchain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 97ba3cd898f..4813ae818b5 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -812,7 +812,7 @@ impl BlockChain { location: BlockLocation::CanonChain, }; - // TODO [sorpaas] support wrap sync insertion of finalization and metadata. + // TODO [sorpaas] support warp sync insertion of finalization and metadata. let block_details = BlockDetails { number: header.number(), total_difficulty: info.total_difficulty, @@ -944,7 +944,7 @@ impl BlockChain { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras:ExtrasInsert) -> ImportRoute { + pub fn insert_block(&self, batch: &mut DBTransaction, bytes: &[u8], receipts: Vec, extras: ExtrasInsert) -> ImportRoute { let block = view!(BlockView, bytes); let header = block.header_view(); From 2c17071e26f585fdd1fd7cfcc9e50033d90d7c5a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 11 May 2018 23:34:10 +0800 Subject: [PATCH 63/64] Fix docs: mark_finalized returns None if block hash is not found `blockchain` mod does not yet have an Error type, so we still temporarily use None here. --- ethcore/src/blockchain/blockchain.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 4813ae818b5..ee7b3fd39e6 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -1036,7 +1036,8 @@ impl BlockChain { } } - /// Mark a block to be considered finalized. Panic if the block hash is not found. + /// Mark a block to be considered finalized. Returns `Some(())` if the operation succeeds, and `None` if the block + /// hash is not found. pub fn mark_finalized(&self, batch: &mut DBTransaction, block_hash: H256) -> Option<()> { let mut block_details = self.block_details(&block_hash)?; block_details.is_finalized = true; From 819b3d8a2352c1ada5a017a3cbb4fe032d7e0593 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 11 May 2018 23:39:58 +0800 Subject: [PATCH 64/64] Fix inaccurate tree_route None expect description --- ethcore/src/blockchain/blockchain.rs | 2 +- ethcore/src/client/client.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index ee7b3fd39e6..f2621d00e1b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -951,7 +951,7 @@ impl BlockChain { let parent_hash = header.parent_hash(); let best_hash = self.best_block_hash(); - let route = self.tree_route(best_hash, parent_hash).expect("blocks being imported always within recent history; qed"); + let route = self.tree_route(best_hash, parent_hash).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); self.insert_block_with_route(batch, bytes, receipts, route, extras) } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e57f3b7f40f..993ecdda216 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -501,7 +501,7 @@ impl Importer { } }; - let route = chain.tree_route(best_hash, *parent).expect("blocks being imported always within recent history; qed"); + let route = chain.tree_route(best_hash, *parent).expect("forks are only kept when it has common ancestors; tree route from best to prospective's parent always exists; qed"); let fork_choice = if route.is_from_route_finalized { ForkChoice::Old } else {