From b7f9b304c14ab1f0590d392584d88e01e5f43e45 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 23 Jan 2017 15:27:11 +0100 Subject: [PATCH] Chain scoring (#4218) * chain scoring * use current steps --- ethcore/src/blockchain/blockchain.rs | 14 ++++-------- ethcore/src/client/client.rs | 4 ++-- ethcore/src/engines/authority_round.rs | 21 ++++-------------- ethcore/src/engines/mod.rs | 10 +-------- ethcore/src/engines/tendermint/message.rs | 3 ++- ethcore/src/engines/tendermint/mod.rs | 27 +++-------------------- ethcore/src/ethereum/ethash.rs | 11 --------- ethcore/src/snapshot/service.rs | 4 +--- ethcore/src/snapshot/tests/blocks.rs | 8 +++---- ethcore/src/tests/helpers.rs | 6 ++--- 10 files changed, 24 insertions(+), 84 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 40df0e11a..51c8ca12f 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -34,7 +34,6 @@ use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute, Config}; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; -use engines::Engine; use encoded; const LOG_BLOOMS_LEVELS: usize = 3; @@ -200,9 +199,6 @@ pub struct BlockChain { pending_block_hashes: RwLock>, pending_block_details: RwLock>, pending_transaction_addresses: RwLock>>, - - // Used for block ordering. - engine: Arc, } impl BlockProvider for BlockChain { @@ -424,8 +420,8 @@ impl<'a> Iterator for AncestryIter<'a> { } impl BlockChain { - /// Create new instance of blockchain from given Genesis and block picking rules of Engine. - pub fn new(config: Config, genesis: &[u8], db: Arc, engine: Arc) -> BlockChain { + /// Create new instance of blockchain from given Genesis. + pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { // 400 is the avarage size of the key let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); @@ -450,7 +446,6 @@ impl BlockChain { pending_block_hashes: RwLock::new(HashMap::new()), pending_block_details: RwLock::new(HashMap::new()), pending_transaction_addresses: RwLock::new(HashMap::new()), - engine: engine, }; // load best block @@ -867,7 +862,7 @@ impl BlockChain { 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 = self.engine.is_new_best_block(self.best_block_total_difficulty(), self.best_block_header().view(), &parent_details, header); + let is_new_best = parent_details.total_difficulty + header.difficulty() > self.best_block_total_difficulty(); BlockInfo { hash: hash, @@ -1328,7 +1323,6 @@ mod tests { use views::BlockView; use transaction::{Transaction, Action}; use log_entry::{LogEntry, LocalizedLogEntry}; - use spec::Spec; use ethkey::Secret; fn new_db(path: &str) -> Arc { @@ -1336,7 +1330,7 @@ mod tests { } fn new_chain(genesis: &[u8], db: Arc) -> BlockChain { - BlockChain::new(Config::default(), genesis, db, Spec::new_null().engine) + BlockChain::new(Config::default(), genesis, db) } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 8e9b2c6d2..e52dd38d0 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -192,7 +192,7 @@ impl Client { } let gb = spec.genesis_block(); - let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone())); + let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone())); let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone())); trace!("Cleanup journal: DB Earliest = {:?}, Latest = {:?}", state_db.journal_db().earliest_era(), state_db.journal_db().latest_era()); @@ -857,7 +857,7 @@ impl snapshot::DatabaseRestore for Client { let cache_size = state_db.cache_size(); *state_db = StateDB::new(journaldb::new(db.clone(), self.pruning, ::db::COL_STATE), cache_size); - *chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone(), self.engine.clone())); + *chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone())); *tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone()); Ok(()) } diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 22635425e..3f371cb24 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -21,15 +21,13 @@ use std::sync::Weak; use std::time::{UNIX_EPOCH, Duration}; use util::*; use ethkey::{verify_address, Signature}; -use rlp::{UntrustedRlp, Rlp, View, encode}; +use rlp::{UntrustedRlp, View, encode}; use account_provider::AccountProvider; use block::*; use spec::CommonParams; use engines::{Engine, Seal, EngineError}; use header::Header; use error::{Error, BlockError}; -use blockchain::extras::BlockDetails; -use views::HeaderView; use evm::Schedule; use ethjson; use io::{IoContext, IoHandler, TimerToken, IoService}; @@ -208,7 +206,9 @@ impl Engine for AuthorityRound { } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { - header.set_difficulty(parent.difficulty().clone()); + // Chain scoring: total weight is sqrt(U256::max_value())*height - step + let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load(AtomicOrdering::SeqCst).into(); + header.set_difficulty(new_difficulty); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.gas_limit_bound_divisor; @@ -309,19 +309,6 @@ impl Engine for AuthorityRound { Ok(()) } - fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - let new_number = new_header.number(); - let best_number = best_header.number(); - if new_number != best_number { - new_number > best_number - } else { - // Take the oldest step at given height. - let new_step: usize = Rlp::new(&new_header.seal()[0]).as_val(); - let best_step: usize = Rlp::new(&best_header.seal()[0]).as_val(); - new_step < best_step - } - } - fn register_client(&self, client: Weak) { *self.client.write() = Some(client.clone()); self.validators.register_call_contract(client); diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 42d5d3dca..6beb0f304 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -41,9 +41,6 @@ use spec::CommonParams; use evm::Schedule; use header::Header; use transaction::{UnverifiedTransaction, SignedTransaction}; -use ethereum::ethash; -use blockchain::extras::BlockDetails; -use views::HeaderView; use client::Client; /// Voting errors. @@ -177,7 +174,7 @@ pub trait Engine : Sync + Send { } /// Populate a header's fields based on its parent's header. - /// Takes gas floor and ceiling targets. + /// Usually implements the chain scoring rule based on weight. /// The gas floor target must not be lower than the engine's minimum gas limit. fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256, _gas_ceil_target: U256) { header.set_difficulty(parent.difficulty().clone()); @@ -203,11 +200,6 @@ pub trait Engine : Sync + Send { self.builtins().get(a).expect("attempted to execute nonexistent builtin").execute(input, output); } - /// Check if new block should be chosen as the one in chain. - fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - ethash::is_new_best_block(best_total_difficulty, parent_details, new_header) - } - /// Find out if the block is a proposal block and should not be inserted into the DB. /// Takes a header of a fully verified block. fn is_proposal(&self, _verified_header: &Header) -> bool { false } diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index 1f17ed902..ff258185d 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -53,7 +53,8 @@ impl VoteStep { } } -fn consensus_round(header: &Header) -> Result { +/// Header consensus round. +pub fn consensus_round(header: &Header) -> Result { let round_rlp = header.seal().get(0).expect("seal passed basic verification; seal has 3 fields; qed"); UntrustedRlp::new(round_rlp.as_slice()).as_val() } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index ca8e7f0c4..fb744eb9f 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -41,8 +41,6 @@ use account_provider::AccountProvider; use block::*; use spec::CommonParams; use engines::{Engine, Seal, EngineError}; -use blockchain::extras::BlockDetails; -use views::HeaderView; use evm::Schedule; use state::CleanupMode; use io::IoService; @@ -397,7 +395,9 @@ impl Engine for Tendermint { } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { - header.set_difficulty(parent.difficulty().clone()); + // Chain scoring: total weight is sqrt(U256::max_value())*height - round + let new_difficulty = U256::from(U128::max_value()) + consensus_round(parent).expect("Header has been verified; qed").into() - self.round.load(AtomicOrdering::SeqCst).into(); + header.set_difficulty(new_difficulty); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.gas_limit_bound_divisor; @@ -565,27 +565,6 @@ impl Engine for Tendermint { self.step_service.stop() } - fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - let new_number = new_header.number(); - let best_number = best_header.number(); - trace!(target: "poa", "new_header: {}, best_header: {}", new_number, best_number); - if new_number != best_number { - new_number > best_number - } else { - let new_seal = new_header.seal(); - let best_seal = best_header.seal(); - let new_signatures = new_seal.get(2).expect("Tendermint seal should have three elements.").len(); - let best_signatures = best_seal.get(2).expect("Tendermint seal should have three elements.").len(); - if new_signatures > best_signatures { - true - } else { - let new_round: Round = ::rlp::Rlp::new(&new_seal.get(0).expect("Tendermint seal should have three elements.")).as_val(); - let best_round: Round = ::rlp::Rlp::new(&best_seal.get(0).expect("Tendermint seal should have three elements.")).as_val(); - new_round > best_round - } - } - } - fn is_proposal(&self, header: &Header) -> bool { let signatures_len = header.seal()[2].len(); // Signatures have to be an empty list rlp. diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index ef8a27544..7ec2a9565 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -21,7 +21,6 @@ use builtin::Builtin; use env_info::EnvInfo; use error::{BlockError, TransactionError, Error}; use header::Header; -use views::HeaderView; use state::CleanupMode; use spec::CommonParams; use transaction::UnverifiedTransaction; @@ -29,7 +28,6 @@ use engines::Engine; use evm::Schedule; use ethjson; use rlp::{self, UntrustedRlp, View}; -use blockchain::extras::BlockDetails; /// Parity tries to round block.gas_limit to multiple of this constant pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); @@ -335,15 +333,6 @@ impl Engine for Ethash { Ok(()) } - - fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - is_new_best_block(best_total_difficulty, parent_details, new_header) - } -} - -/// Check if a new block should replace the best blockchain block. -pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty } // Try to round gas_limit a bit so that: diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 8d0d14ac7..5ef0aaffd 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -81,7 +81,6 @@ struct Restoration { struct RestorationParams<'a> { manifest: ManifestData, // manifest to base restoration on. pruning: Algorithm, // pruning algorithm for the database. - engine: Arc, // consensus engine of the chain. db_path: PathBuf, // database path db_config: &'a DatabaseConfig, // configuration for the database. writer: Option, // writer for recovered snapshot. @@ -100,7 +99,7 @@ impl Restoration { let raw_db = Arc::new(Database::open(params.db_config, &*params.db_path.to_string_lossy()) .map_err(UtilError::SimpleString)?); - let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone(), params.engine); + let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone()); let blocks = BlockRebuilder::new(chain, raw_db.clone(), &manifest)?; let root = manifest.state_root.clone(); @@ -421,7 +420,6 @@ impl Service { let params = RestorationParams { manifest: manifest, pruning: self.pruning, - engine: self.engine.clone(), db_path: self.restoration_db(), db_config: &self.db_config, writer: writer, diff --git a/ethcore/src/snapshot/tests/blocks.rs b/ethcore/src/snapshot/tests/blocks.rs index 058d311e2..cd8890d1b 100644 --- a/ethcore/src/snapshot/tests/blocks.rs +++ b/ethcore/src/snapshot/tests/blocks.rs @@ -44,7 +44,7 @@ fn chunk_and_restore(amount: u64) { snapshot_path.push("SNAP"); let old_db = Arc::new(Database::open(&db_cfg, orig_path.as_str()).unwrap()); - let bc = BlockChain::new(Default::default(), &genesis, old_db.clone(), engine.clone()); + let bc = BlockChain::new(Default::default(), &genesis, old_db.clone()); // build the blockchain. let mut batch = old_db.transaction(); @@ -74,7 +74,7 @@ fn chunk_and_restore(amount: u64) { // restore it. let new_db = Arc::new(Database::open(&db_cfg, new_path.as_str()).unwrap()); - let new_chain = BlockChain::new(Default::default(), &genesis, new_db.clone(), engine.clone()); + let new_chain = BlockChain::new(Default::default(), &genesis, new_db.clone()); let mut rebuilder = BlockRebuilder::new(new_chain, new_db.clone(), &manifest).unwrap(); let reader = PackedReader::new(&snapshot_path).unwrap().unwrap(); let flag = AtomicBool::new(true); @@ -87,7 +87,7 @@ fn chunk_and_restore(amount: u64) { rebuilder.finalize(HashMap::new()).unwrap(); // and test it. - let new_chain = BlockChain::new(Default::default(), &genesis, new_db, engine); + let new_chain = BlockChain::new(Default::default(), &genesis, new_db); assert_eq!(new_chain.best_block_hash(), best_hash); } @@ -122,7 +122,7 @@ fn checks_flag() { let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let db = Arc::new(Database::open(&db_cfg, path.as_str()).unwrap()); let engine = Arc::new(::engines::NullEngine::default()); - let chain = BlockChain::new(Default::default(), &genesis, db.clone(), engine.clone()); + let chain = BlockChain::new(Default::default(), &genesis, db.clone()); let manifest = ::snapshot::ManifestData { state_hashes: Vec::new(), diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 80419d806..2aef7bdec 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -294,7 +294,7 @@ fn new_db(path: &str) -> Arc { pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); let mut batch = db.transaction(); for block_order in 1..block_number { @@ -312,7 +312,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); let mut batch = db.transaction(); @@ -331,7 +331,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); GuardedTempResult:: { _temp: temp,