Chain scoring (#4218)

* chain scoring

* use current steps
This commit is contained in:
keorn 2017-01-23 15:27:11 +01:00 committed by Nikolay Volf
parent 2034595652
commit b7f9b304c1
10 changed files with 24 additions and 84 deletions

View File

@ -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<HashMap<BlockNumber, H256>>,
pending_block_details: RwLock<HashMap<H256, BlockDetails>>,
pending_transaction_addresses: RwLock<HashMap<H256, Option<TransactionAddress>>>,
// Used for block ordering.
engine: Arc<Engine>,
}
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<Database>, engine: Arc<Engine>) -> BlockChain {
/// Create new instance of blockchain from given Genesis.
pub fn new(config: Config, genesis: &[u8], db: Arc<Database>) -> 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<Database> {
@ -1336,7 +1330,7 @@ mod tests {
}
fn new_chain(genesis: &[u8], db: Arc<Database>) -> BlockChain {
BlockChain::new(Config::default(), genesis, db, Spec::new_null().engine)
BlockChain::new(Config::default(), genesis, db)
}
#[test]

View File

@ -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(())
}

View File

@ -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<Client>) {
*self.client.write() = Some(client.clone());
self.validators.register_call_contract(client);

View File

@ -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 }

View File

@ -53,7 +53,8 @@ impl VoteStep {
}
}
fn consensus_round(header: &Header) -> Result<Round, ::rlp::DecoderError> {
/// Header consensus round.
pub fn consensus_round(header: &Header) -> Result<Round, ::rlp::DecoderError> {
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()
}

View File

@ -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.

View File

@ -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:

View File

@ -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<Engine>, // consensus engine of the chain.
db_path: PathBuf, // database path
db_config: &'a DatabaseConfig, // configuration for the database.
writer: Option<LooseWriter>, // 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,

View File

@ -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(),

View File

@ -294,7 +294,7 @@ fn new_db(path: &str) -> Arc<Database> {
pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult<BlockChain> {
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<BlockCh
pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempResult<BlockChain> {
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<BlockChain> {
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::<BlockChain> {
_temp: temp,