Merge changes from #674 into branch.

This commit is contained in:
Gav Wood 2016-03-13 15:29:55 +01:00
parent 4a58e142bd
commit 08b9cc2c41
9 changed files with 93 additions and 44 deletions

10
Cargo.lock generated
View File

@ -93,6 +93,16 @@ dependencies = [
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "clippy"
version = "0.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "clippy" name = "clippy"
version = "0.0.50" version = "0.0.50"

View File

@ -35,7 +35,7 @@ use extras::TransactionAddress;
use filter::Filter; use filter::Filter;
use log_entry::LocalizedLogEntry; use log_entry::LocalizedLogEntry;
use block_queue::{BlockQueue, BlockQueueInfo}; use block_queue::{BlockQueue, BlockQueueInfo};
use blockchain::{BlockChain, BlockProvider, TreeRoute}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient};
pub use blockchain::CacheSize as BlockChainCacheSize; pub use blockchain::CacheSize as BlockChainCacheSize;
@ -222,12 +222,39 @@ impl<V> Client<V> where V: Verifier {
Ok(closed_block) Ok(closed_block)
} }
fn calculate_enacted_retracted(&self, import_results: Vec<ImportRoute>) -> (Vec<H256>, Vec<H256>) {
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
map.into_iter().map(|(k, _v)| k).collect()
}
// In ImportRoute we get all the blocks that have been enacted and retracted by single insert.
// Because we are doing multiple inserts some of the blocks that were enacted in import `k`
// could be retracted in import `k+1`. This is why to understand if after all inserts
// the block is enacted or retracted we iterate over all routes and at the end final state
// will be in the hashmap
let map = import_results.into_iter().fold(HashMap::new(), |mut map, route| {
for hash in route.enacted {
map.insert(hash, true);
}
for hash in route.retracted {
map.insert(hash, false);
}
map
});
// Split to enacted retracted (using hashmap value)
let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v);
// And convert tuples to keys
(map_to_vec(enacted), map_to_vec(retracted))
}
/// This is triggered by a message coming from a block queue when the block is ready for insertion /// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self, io: &IoChannel<NetSyncMessage>) -> usize { pub fn import_verified_blocks(&self, io: &IoChannel<NetSyncMessage>) -> usize {
let max_blocks_to_import = 128; let max_blocks_to_import = 128;
let mut good_blocks = Vec::with_capacity(max_blocks_to_import); let mut imported_blocks = Vec::with_capacity(max_blocks_to_import);
let mut bad_blocks = HashSet::new(); let mut invalid_blocks = HashSet::new();
let mut import_results = Vec::with_capacity(max_blocks_to_import);
let _import_lock = self.import_lock.lock(); let _import_lock = self.import_lock.lock();
let blocks = self.block_queue.drain(max_blocks_to_import); let blocks = self.block_queue.drain(max_blocks_to_import);
@ -237,16 +264,16 @@ impl<V> Client<V> where V: Verifier {
for block in blocks { for block in blocks {
let header = &block.header; let header = &block.header;
if bad_blocks.contains(&header.parent_hash) { if invalid_blocks.contains(&header.parent_hash) {
bad_blocks.insert(header.hash()); invalid_blocks.insert(header.hash());
continue; continue;
} }
let closed_block = self.check_and_close_block(&block); let closed_block = self.check_and_close_block(&block);
if let Err(_) = closed_block { if let Err(_) = closed_block {
bad_blocks.insert(header.hash()); invalid_blocks.insert(header.hash());
break; break;
} }
good_blocks.push(header.hash()); imported_blocks.push(header.hash());
// Are we committing an era? // Are we committing an era?
let ancient = if header.number() >= HISTORY { let ancient = if header.number() >= HISTORY {
@ -265,31 +292,33 @@ impl<V> Client<V> where V: Verifier {
// And update the chain after commit to prevent race conditions // And update the chain after commit to prevent race conditions
// (when something is in chain but you are not able to fetch details) // (when something is in chain but you are not able to fetch details)
self.chain.insert_block(&block.bytes, receipts); let route = self.chain.insert_block(&block.bytes, receipts);
import_results.push(route);
self.report.write().unwrap().accrue_block(&block); self.report.write().unwrap().accrue_block(&block);
trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); trace!(target: "client", "Imported #{} ({})", header.number(), header.hash());
} }
let imported = good_blocks.len(); let imported = imported_blocks.len();
let bad_blocks = bad_blocks.into_iter().collect::<Vec<H256>>(); let invalid_blocks = invalid_blocks.into_iter().collect::<Vec<H256>>();
{ {
if !bad_blocks.is_empty() { if !invalid_blocks.is_empty() {
self.block_queue.mark_as_bad(&bad_blocks); self.block_queue.mark_as_bad(&invalid_blocks);
} }
if !good_blocks.is_empty() { if !imported_blocks.is_empty() {
self.block_queue.mark_as_good(&good_blocks); self.block_queue.mark_as_good(&imported_blocks);
} }
} }
{ {
if !good_blocks.is_empty() && self.block_queue.queue_info().is_empty() { if !imported_blocks.is_empty() && self.block_queue.queue_info().is_empty() {
let (enacted, retracted) = self.calculate_enacted_retracted(import_results);
io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks { io.send(NetworkIoMessage::User(SyncMessage::NewChainBlocks {
good: good_blocks, good: imported_blocks,
bad: bad_blocks, invalid: invalid_blocks,
// TODO [todr] were to take those from? enacted: enacted,
retracted: vec![], retracted: retracted,
})).unwrap(); })).unwrap();
} }
} }

View File

@ -28,11 +28,13 @@ pub enum SyncMessage {
/// New block has been imported into the blockchain /// New block has been imported into the blockchain
NewChainBlocks { NewChainBlocks {
/// Hashes of blocks imported to blockchain /// Hashes of blocks imported to blockchain
good: Vec<H256>, imported: Vec<H256>,
/// Hashes of blocks not imported to blockchain /// Hashes of blocks not imported to blockchain (because were invalid)
bad: Vec<H256>, invalid: Vec<H256>,
/// Hashes of blocks that were removed from canonical chain /// Hashes of blocks that were removed from canonical chain
retracted: Vec<H256>, retracted: Vec<H256>,
/// Hashes of blocks that are now included in cannonical chain
enacted: Vec<H256>,
}, },
/// Best Block Hash in chain has been changed /// Best Block Hash in chain has been changed
NewChainHead, NewChainHead,

View File

@ -89,7 +89,7 @@ pub trait MinerService : Send + Sync {
fn clear_and_reset(&self, chain: &BlockChainClient); fn clear_and_reset(&self, chain: &BlockChainClient);
/// Called when blocks are imported to chain, updates transactions queue. /// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], retracted: &[H256]); fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]);
/// New chain head event. Restart mining operation. /// New chain head event. Restart mining operation.
fn prepare_sealing(&self, chain: &BlockChainClient); fn prepare_sealing(&self, chain: &BlockChainClient);

View File

@ -150,7 +150,7 @@ impl MinerService for Miner {
} }
} }
fn chain_new_blocks(&self, chain: &BlockChainClient, good: &[H256], bad: &[H256], _retracted: &[H256]) { fn chain_new_blocks(&self, chain: &BlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], _retracted: &[H256]) {
fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> { fn fetch_transactions(chain: &BlockChainClient, hash: &H256) -> Vec<SignedTransaction> {
let block = chain let block = chain
.block(BlockId::Hash(*hash)) .block(BlockId::Hash(*hash))
@ -161,15 +161,20 @@ impl MinerService for Miner {
} }
{ {
let good = good.par_iter().map(|h| fetch_transactions(chain, h)); let in_chain = vec![imported, enacted, invalid];
let bad = bad.par_iter().map(|h| fetch_transactions(chain, h)); let in_chain = in_chain
.par_iter()
.flat_map(|h| h.par_iter().map(|h| fetch_transactions(chain, h)));
.map(|h| fetch_transactions(chain, h));
let out_of_chain = retracted
.par_iter()
good.for_each(|txs| { in_chain.for_each(|txs| {
let mut transaction_queue = self.transaction_queue.lock().unwrap(); let mut transaction_queue = self.transaction_queue.lock().unwrap();
let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>(); let hashes = txs.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
transaction_queue.remove_all(&hashes, |a| chain.nonce(a)); transaction_queue.remove_all(&hashes, |a| chain.nonce(a));
}); });
bad.for_each(|txs| { out_of_chain.for_each(|txs| {
// populate sender // populate sender
for tx in &txs { for tx in &txs {
let _sender = tx.sender(); let _sender = tx.sender();

View File

@ -114,7 +114,7 @@ API and Console Options:
--rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible).
Sealing/Mining Options: Sealing/Mining Options:
--gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. --gas-price WEI Minimum amount of Wei to be paid for a transaction to be accepted for mining [default: 20000000000].
--author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards
from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63].
--extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters.
@ -138,11 +138,12 @@ Geth-Compatibility Options
--maxpeers COUNT Equivalent to --peers COUNT. --maxpeers COUNT Equivalent to --peers COUNT.
--nodekey KEY Equivalent to --node-key KEY. --nodekey KEY Equivalent to --node-key KEY.
--nodiscover Equivalent to --no-discovery. --nodiscover Equivalent to --no-discovery.
--gasprice WEI Equivalent to --gas-price WEI.
--etherbase ADDRESS Equivalent to --author ADDRESS. --etherbase ADDRESS Equivalent to --author ADDRESS.
--extradata STRING Equivalent to --extra-data STRING. --extradata STRING Equivalent to --extra-data STRING.
Miscellaneous Options: Miscellaneous Options:
-l --logging LOGGING Specify the logging level. -l --logging LOGGING Specify the logging level. Must conform to the same format as RUST_LOG.
-v --version Show information about version. -v --version Show information about version.
-h --help Show this screen. -h --help Show this screen.
"#; "#;
@ -175,18 +176,19 @@ struct Args {
flag_jsonrpc_port: u16, flag_jsonrpc_port: u16,
flag_jsonrpc_cors: String, flag_jsonrpc_cors: String,
flag_jsonrpc_apis: String, flag_jsonrpc_apis: String,
flag_author: String,
flag_gas_price: String,
flag_extra_data: Option<String>,
flag_logging: Option<String>, flag_logging: Option<String>,
flag_version: bool, flag_version: bool,
// geth-compatibility... // geth-compatibility...
flag_nodekey: Option<String>, flag_nodekey: Option<String>,
flag_nodiscover: bool, flag_nodiscover: bool,
flag_maxpeers: Option<usize>, flag_maxpeers: Option<usize>,
flag_gasprice: String,
flag_author: String,
flag_extra_data: Option<String>,
flag_datadir: Option<String>, flag_datadir: Option<String>,
flag_extradata: Option<String>, flag_extradata: Option<String>,
flag_etherbase: Option<String>, flag_etherbase: Option<String>,
flag_gasprice: Option<String>,
flag_rpc: bool, flag_rpc: bool,
flag_rpcaddr: Option<String>, flag_rpcaddr: Option<String>,
flag_rpcport: Option<u16>, flag_rpcport: Option<u16>,
@ -301,9 +303,10 @@ impl Configuration {
}) })
} }
fn gasprice(&self) -> U256 { fn gas_price(&self) -> U256 {
U256::from_dec_str(self.args.flag_gasprice.as_str()).unwrap_or_else(|_| { let d = self.args.flag_gasprice.as_ref().unwrap_or(&self.args.flag_gas_price);
die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", self.args.flag_gasprice) U256::from_dec_str(d).unwrap_or_else(|_| {
die!("{}: Invalid gas price given. Must be a decimal unsigned 256-bit number.", d)
}) })
} }
@ -483,7 +486,7 @@ impl Configuration {
let miner = Miner::new(); let miner = Miner::new();
miner.set_author(self.author()); miner.set_author(self.author());
miner.set_extra_data(self.extra_data()); miner.set_extra_data(self.extra_data());
miner.set_minimal_gas_price(self.gasprice()); miner.set_minimal_gas_price(self.gas_price());
// Sync // Sync
let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone());

View File

@ -1263,9 +1263,9 @@ impl ChainSync {
} }
/// called when block is imported to chain, updates transactions queue and propagates the blocks /// called when block is imported to chain, updates transactions queue and propagates the blocks
pub fn chain_new_blocks(&mut self, io: &mut SyncIo, good: &[H256], bad: &[H256], retracted: &[H256]) { pub fn chain_new_blocks(&mut self, io: &mut SyncIo, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
// Notify miner // Notify miner
self.miner.chain_new_blocks(io.chain(), good, bad, retracted); self.miner.chain_new_blocks(io.chain(), imported, invalid, enacted, retracted);
// Propagate latests blocks // Propagate latests blocks
self.propagate_latest_blocks(io); self.propagate_latest_blocks(io);
// TODO [todr] propagate transactions? // TODO [todr] propagate transactions?
@ -1616,10 +1616,10 @@ mod tests {
let mut io = TestIo::new(&mut client, &mut queue, None); let mut io = TestIo::new(&mut client, &mut queue, None);
// when // when
sync.chain_new_blocks(&mut io, &[], &good_blocks, &[]); sync.chain_new_blocks(&mut io, &[], &good_blocks, &[], &[]);
assert_eq!(sync.miner.status().transaction_queue_future, 0); assert_eq!(sync.miner.status().transaction_queue_future, 0);
assert_eq!(sync.miner.status().transaction_queue_pending, 1); assert_eq!(sync.miner.status().transaction_queue_pending, 1);
sync.chain_new_blocks(&mut io, &good_blocks, &retracted_blocks, &[]); sync.chain_new_blocks(&mut io, &good_blocks, &[], &[], &retracted_blocks);
// then // then
let status = sync.miner.status(); let status = sync.miner.status();

View File

@ -167,9 +167,9 @@ impl NetworkProtocolHandler<SyncMessage> for EthSync {
#[allow(single_match)] #[allow(single_match)]
fn message(&self, io: &NetworkContext<SyncMessage>, message: &SyncMessage) { fn message(&self, io: &NetworkContext<SyncMessage>, message: &SyncMessage) {
match *message { match *message {
SyncMessage::NewChainBlocks { ref good, ref bad, ref retracted } => { SyncMessage::NewChainBlocks { ref imported, ref invalid, ref enacted, ref retracted } => {
let mut sync_io = NetSyncIo::new(io, self.chain.deref()); let mut sync_io = NetSyncIo::new(io, self.chain.deref());
self.sync.write().unwrap().chain_new_blocks(&mut sync_io, good, bad, retracted); self.sync.write().unwrap().chain_new_blocks(&mut sync_io, imported, invalid, enacted, retracted);
}, },
SyncMessage::NewChainHead => { SyncMessage::NewChainHead => {
let mut sync_io = NetSyncIo::new(io, self.chain.deref()); let mut sync_io = NetSyncIo::new(io, self.chain.deref());

View File

@ -168,6 +168,6 @@ impl TestNet {
pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) { pub fn trigger_chain_new_blocks(&mut self, peer_id: usize) {
let mut peer = self.peer_mut(peer_id); let mut peer = self.peer_mut(peer_id);
peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[]); peer.sync.chain_new_blocks(&mut TestIo::new(&mut peer.chain, &mut peer.queue, None), &[], &[], &[], &[]);
} }
} }