decode block rlp less often (#9252)

in total:
- removed 4 redundant rlp deserializations
- avoid 1 redundant block data copy
This commit is contained in:
Marek Kotewicz 2018-08-02 11:20:46 +02:00 committed by André Silva
parent f442665c46
commit b4ae1b6528
17 changed files with 116 additions and 165 deletions

View File

@ -40,7 +40,7 @@ use engines::EthEngine;
use error::{Error, BlockError};
use ethereum_types::{H256, U256, Address, Bloom};
use factory::Factories;
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
use hash::keccak;
use header::{Header, ExtendedHeader};
use receipt::{Receipt, TransactionOutcome};
use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list};
@ -51,7 +51,6 @@ use transaction::{UnverifiedTransaction, SignedTransaction, Error as Transaction
use triehash::ordered_trie_root;
use unexpected::{Mismatch, OutOfBounds};
use verification::PreverifiedBlock;
use views::BlockView;
use vm::{EnvInfo, LastHashes};
/// A block, encoded as it is on the block chain.
@ -66,11 +65,6 @@ pub struct Block {
}
impl Block {
/// Returns true if the given bytes form a valid encoding of a block in RLP.
pub fn is_good(b: &[u8]) -> bool {
Rlp::new(b).as_val::<Block>().is_ok()
}
/// Get the RLP-encoding of the block with the seal.
pub fn rlp_bytes(&self) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
@ -398,26 +392,11 @@ impl<'x> OpenBlock<'x> {
/// Turn this into a `ClosedBlock`.
pub fn close(self) -> Result<ClosedBlock, Error> {
let mut s = self;
let unclosed_state = s.block.state.clone();
s.engine.on_close_block(&mut s.block)?;
s.block.state.commit()?;
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
let uncle_bytes = encode_list(&s.block.uncles);
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
s.block.header.set_state_root(s.block.state.root().clone());
s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
b.accrue_bloom(&r.log_bloom);
b
}));
s.block.header.set_gas_used(s.block.receipts.last().map_or_else(U256::zero, |r| r.gas_used));
let unclosed_state = self.block.state.clone();
let locked = self.close_and_lock()?;
Ok(ClosedBlock {
block: s.block,
block: locked.block,
unclosed_state,
})
}
@ -429,18 +408,11 @@ impl<'x> OpenBlock<'x> {
s.engine.on_close_block(&mut s.block)?;
s.block.state.commit()?;
if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP {
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
}
if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP {
let uncle_bytes = encode_list(&s.block.uncles);
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
}
if s.block.header.receipts_root().is_zero() || s.block.header.receipts_root() == &KECCAK_NULL_RLP {
s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
}
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
let uncle_bytes = encode_list(&s.block.uncles);
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
s.block.header.set_state_root(s.block.state.root().clone());
s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
b.accrue_bloom(&r.log_bloom);
b
@ -537,18 +509,16 @@ impl LockedBlock {
self,
engine: &EthEngine,
seal: Vec<Bytes>,
) -> Result<SealedBlock, (Error, LockedBlock)> {
) -> Result<SealedBlock, Error> {
let mut s = self;
s.block.header.set_seal(seal);
s.block.header.compute_hash();
// TODO: passing state context to avoid engines owning it?
match engine.verify_local_seal(&s.block.header) {
Err(e) => Err((e, s)),
_ => Ok(SealedBlock {
block: s.block
}),
}
engine.verify_local_seal(&s.block.header)?;
Ok(SealedBlock {
block: s.block
})
}
}
@ -637,12 +607,11 @@ pub fn enact_verified(
is_epoch_begin: bool,
ancestry: &mut Iterator<Item=ExtendedHeader>,
) -> Result<LockedBlock, Error> {
let view = view!(BlockView, &block.bytes);
enact(
block.header,
block.transactions,
view.uncles(),
block.uncles,
engine,
tracing,
db,

View File

@ -73,6 +73,8 @@ use types::filter::Filter;
use types::ancestry_action::AncestryAction;
use verification;
use verification::{PreverifiedBlock, Verifier, BlockQueue};
use verification::queue::kind::blocks::Unverified;
use verification::queue::kind::BlockLike;
// re-export
pub use types::blockchain_info::BlockChainInfo;
@ -208,7 +210,7 @@ pub struct Client {
/// Queued ancient blocks, make sure they are imported in order.
queued_ancient_blocks: Arc<RwLock<(
HashSet<H256>,
VecDeque<(Header, encoded::Block, Bytes)>
VecDeque<(Unverified, Bytes)>
)>>,
ancient_blocks_import_lock: Arc<Mutex<()>>,
/// Consensus messages import queue
@ -428,7 +430,7 @@ impl Importer {
///
/// The block is guaranteed to be the next best blocks in the
/// first block sequence. Does no sealing or transaction validation.
fn import_old_block(&self, header: &Header, block: encoded::Block, receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result<(), ::error::Error> {
fn import_old_block(&self, unverified: Unverified, receipts_bytes: &[u8], db: &KeyValueDB, chain: &BlockChain) -> Result<(), ::error::Error> {
let receipts = ::rlp::decode_list(receipts_bytes);
let _import_lock = self.import_lock.lock();
@ -436,11 +438,11 @@ impl Importer {
trace_time!("import_old_block");
// verify the block, passing the chain for updating the epoch verifier.
let mut rng = OsRng::new()?;
self.ancient_verifier.verify(&mut rng, &header, &chain)?;
self.ancient_verifier.verify(&mut rng, &unverified.header, &chain)?;
// Commit results
let mut batch = DBTransaction::new();
chain.insert_unordered_block(&mut batch, block, receipts, None, false, true);
chain.insert_unordered_block(&mut batch, encoded::Block::new(unverified.bytes), receipts, None, false, true);
// Final commit to the DB
db.write_buffered(batch);
chain.commit();
@ -1381,22 +1383,15 @@ impl CallContract for Client {
}
impl ImportBlock for Client {
fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError> {
use verification::queue::kind::BlockLike;
use verification::queue::kind::blocks::Unverified;
// create unverified block here so the `keccak` calculation can be cached.
let unverified = Unverified::from_rlp(bytes)?;
{
if self.chain.read().is_known(&unverified.hash()) {
bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash())));
}
fn import_block(&self, unverified: Unverified) -> Result<H256, BlockImportError> {
if self.chain.read().is_known(&unverified.hash()) {
bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash())));
}
Ok(self.importer.block_queue.import(unverified)?)
}
}
@ -2027,24 +2022,23 @@ impl IoClient for Client {
});
}
fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError> {
fn queue_ancient_block(&self, unverified: Unverified, receipts_bytes: Bytes) -> Result<H256, BlockImportError> {
trace_time!("queue_ancient_block");
let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?;
let hash = header.hash();
let hash = unverified.hash();
{
// check block order
if self.chain.read().is_known(&hash) {
bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
let parent_hash = header.parent_hash();
let parent_hash = unverified.parent_hash();
// NOTE To prevent race condition with import, make sure to check queued blocks first
// (and attempt to acquire lock)
let is_parent_pending = self.queued_ancient_blocks.read().0.contains(parent_hash);
let is_parent_pending = self.queued_ancient_blocks.read().0.contains(&parent_hash);
if !is_parent_pending {
let status = self.block_status(BlockId::Hash(*parent_hash));
let status = self.block_status(BlockId::Hash(parent_hash));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*parent_hash)));
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(parent_hash)));
}
}
}
@ -2053,7 +2047,7 @@ impl IoClient for Client {
{
let mut queued = self.queued_ancient_blocks.write();
queued.0.insert(hash);
queued.1.push_back((header, encoded::Block::new(block_bytes), receipts_bytes));
queued.1.push_back((unverified, receipts_bytes));
}
let queued = self.queued_ancient_blocks.clone();
@ -2065,11 +2059,10 @@ impl IoClient for Client {
let _lock = lock.lock();
for _i in 0..MAX_ANCIENT_BLOCKS_TO_IMPORT {
let first = queued.write().1.pop_front();
if let Some((header, block_bytes, receipts_bytes)) = first {
let hash = header.hash();
if let Some((unverified, receipts_bytes)) = first {
let hash = unverified.hash();
let result = client.importer.import_old_block(
&header,
block_bytes,
unverified,
&receipts_bytes,
&**client.db.read().key_value(),
&*client.chain.read(),

View File

@ -53,6 +53,7 @@ use spec::Spec;
use types::basic_account::BasicAccount;
use types::pruning_info::PruningInfo;
use verification::queue::QueueInfo;
use verification::queue::kind::blocks::Unverified;
use block::{OpenBlock, SealedBlock, ClosedBlock};
use executive::Executed;
use error::CallError;
@ -280,7 +281,8 @@ impl TestBlockChainClient {
rlp.append(&header);
rlp.append_raw(&txs, 1);
rlp.append_raw(uncles.as_raw(), 1);
self.import_block(rlp.as_raw().to_vec()).unwrap();
let unverified = Unverified::from_rlp(rlp.out()).unwrap();
self.import_block(unverified).unwrap();
}
}
@ -512,8 +514,8 @@ impl RegistryInfo for TestBlockChainClient {
}
impl ImportBlock for TestBlockChainClient {
fn import_block(&self, b: Bytes) -> Result<H256, BlockImportError> {
let header = view!(BlockView, &b).header();
fn import_block(&self, unverified: Unverified) -> Result<H256, BlockImportError> {
let header = unverified.header;
let h = header.hash();
let number: usize = header.number() as usize;
if number > self.blocks.read().len() {
@ -539,7 +541,7 @@ impl ImportBlock for TestBlockChainClient {
*difficulty = *difficulty + header.difficulty().clone();
}
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.blocks.write().insert(h.clone(), unverified.bytes);
self.numbers.write().insert(number, h.clone());
let mut parent_hash = header.parent_hash().clone();
if number > 0 {
@ -552,7 +554,7 @@ impl ImportBlock for TestBlockChainClient {
}
}
else {
self.blocks.write().insert(h.clone(), b.to_vec());
self.blocks.write().insert(h.clone(), unverified.bytes);
}
Ok(h)
}
@ -856,8 +858,8 @@ impl IoClient for TestBlockChainClient {
self.miner.import_external_transactions(self, txs);
}
fn queue_ancient_block(&self, b: Bytes, _r: Bytes) -> Result<H256, BlockImportError> {
self.import_block(b)
fn queue_ancient_block(&self, unverified: Unverified, _r: Bytes) -> Result<H256, BlockImportError> {
self.import_block(unverified)
}
fn queue_consensus_message(&self, message: Bytes) {

View File

@ -34,6 +34,7 @@ use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use transaction::{self, LocalizedTransaction, SignedTransaction};
use verification::queue::QueueInfo as BlockQueueInfo;
use verification::queue::kind::blocks::Unverified;
use state::StateInfo;
use header::Header;
use engines::EthEngine;
@ -167,7 +168,7 @@ pub trait RegistryInfo {
/// Provides methods to import block into blockchain
pub trait ImportBlock {
/// Import a block into the blockchain.
fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError>;
fn import_block(&self, block: Unverified) -> Result<H256, BlockImportError>;
}
/// Provides `call_contract` method
@ -204,7 +205,7 @@ pub trait IoClient: Sync + Send {
fn queue_transactions(&self, transactions: Vec<Bytes>, peer_id: usize);
/// Queue block import with transaction receipts. Does no sealing and transaction validation.
fn queue_ancient_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError>;
fn queue_ancient_block(&self, block_bytes: Unverified, receipts_bytes: Bytes) -> Result<H256, BlockImportError>;
/// Queue conensus engine message.
fn queue_consensus_message(&self, message: Bytes);

View File

@ -158,6 +158,7 @@ mod tests {
use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
use types::ids::BlockId;
use ethereum_types::Address;
use verification::queue::kind::blocks::Unverified;
use super::Multi;
@ -198,7 +199,7 @@ mod tests {
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]);
sync_client.engine().register_client(Arc::downgrade(&sync_client) as _);
for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
sync_client.import_block(Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap()).unwrap();
}
sync_client.flush_queue();
assert_eq!(sync_client.chain_info().best_block_number, 3);

View File

@ -458,6 +458,7 @@ mod tests {
use test_helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
use super::super::ValidatorSet;
use super::{ValidatorSafeContract, EVENT_NAME_HASH};
use verification::queue::kind::blocks::Unverified;
#[test]
fn fetches_validators() {
@ -530,7 +531,7 @@ mod tests {
let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]);
sync_client.engine().register_client(Arc::downgrade(&sync_client) as _);
for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
sync_client.import_block(Unverified::from_rlp(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap()).unwrap();
}
sync_client.flush_queue();
assert_eq!(sync_client.chain_info().best_block_number, 3);

View File

@ -17,12 +17,12 @@
use std::path::Path;
use std::sync::Arc;
use client::{EvmTestClient, Client, ClientConfig, ChainInfo, ImportBlock};
use block::Block;
use spec::Genesis;
use ethjson;
use miner::Miner;
use io::IoChannel;
use test_helpers;
use verification::queue::kind::blocks::Unverified;
use super::HookType;
@ -83,9 +83,9 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_ho
Arc::new(Miner::new_for_tests(&spec, None)),
IoChannel::disconnected(),
).unwrap();
for b in &blockchain.blocks_rlp() {
if Block::is_good(&b) {
let _ = client.import_block(b.clone());
for b in blockchain.blocks_rlp() {
if let Ok(block) = Unverified::from_rlp(b) {
let _ = client.import_block(block);
client.flush_queue();
client.import_verified_blocks();
}

View File

@ -1148,7 +1148,7 @@ impl miner::MinerService for Miner {
|b| &b.hash() == &block_hash
) {
trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal);
b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| {
b.lock().try_seal(&*self.engine, seal).or_else(|e| {
warn!(target: "miner", "Mined solution rejected: {}", e);
Err(ErrorKind::PowInvalid.into())
})

View File

@ -43,6 +43,7 @@ use blooms_db;
use kvdb::KeyValueDB;
use kvdb_rocksdb;
use tempdir::TempDir;
use verification::queue::kind::blocks::Unverified;
use encoded;
/// Creates test block with corresponding header
@ -175,7 +176,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data<F>(test_spec: F, accoun
let b = b.close_and_lock().unwrap().seal(test_engine, vec![]).unwrap();
if let Err(e) = client.import_block(b.rlp_bytes()) {
if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
@ -211,7 +212,7 @@ pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting
rolling_block_number = rolling_block_number + 1;
rolling_timestamp = rolling_timestamp + 10;
if let Err(e) = client.import_block(create_test_block(&header)) {
if let Err(e) = client.import_block(Unverified::from_rlp(create_test_block(&header)).unwrap()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
}
@ -231,7 +232,7 @@ pub fn push_block_with_transactions(client: &Arc<Client>, transactions: &[Signed
}
let b = b.close_and_lock().unwrap().seal(test_engine, vec![]).unwrap();
if let Err(e) = client.import_block(b.rlp_bytes()) {
if let Err(e) = client.import_block(Unverified::from_rlp(b.rlp_bytes()).unwrap()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
@ -253,7 +254,7 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> Arc<Client> {
).unwrap();
for block in blocks {
if let Err(e) = client.import_block(block) {
if let Err(e) = client.import_block(Unverified::from_rlp(block).unwrap()) {
panic!("error importing block which is well-formed: {:?}", e);
}
}

View File

@ -35,9 +35,9 @@ use views::BlockView;
use ethkey::KeyPair;
use transaction::{PendingTransaction, Transaction, Action, Condition};
use miner::MinerService;
use rlp::{RlpStream, EMPTY_LIST_RLP};
use tempdir::TempDir;
use test_helpers;
use verification::queue::kind::blocks::Unverified;
#[test]
fn imports_from_empty() {
@ -97,7 +97,7 @@ fn imports_good_block() {
IoChannel::disconnected(),
).unwrap();
let good_block = get_good_dummy_block();
if client.import_block(good_block).is_err() {
if client.import_block(Unverified::from_rlp(good_block).unwrap()).is_err() {
panic!("error importing block being good by definition");
}
client.flush_queue();
@ -107,24 +107,6 @@ fn imports_good_block() {
assert!(!block.into_inner().is_empty());
}
#[test]
fn fails_to_import_block_with_invalid_rlp() {
use error::{BlockImportError, BlockImportErrorKind};
let client = generate_dummy_client(6);
let mut rlp = RlpStream::new_list(3);
rlp.append_raw(&EMPTY_LIST_RLP, 1); // empty header
rlp.append_raw(&EMPTY_LIST_RLP, 1);
rlp.append_raw(&EMPTY_LIST_RLP, 1);
let invalid_header_block = rlp.out();
match client.import_block(invalid_header_block) {
Err(BlockImportError(BlockImportErrorKind::Decoder(_), _)) => (), // all good
Err(_) => panic!("Should fail with a decoder error"),
Ok(_) => panic!("Should not import block with invalid header"),
}
}
#[test]
fn query_none_block() {
let db = test_helpers::new_db();

View File

@ -33,6 +33,7 @@ use views::BlockView;
use trace::{RewardType, LocalizedTrace};
use trace::trace::Action::Reward;
use test_helpers;
use verification::queue::kind::blocks::Unverified;
#[test]
fn can_trace_block_and_uncle_reward() {
@ -91,7 +92,7 @@ fn can_trace_block_and_uncle_reward() {
let root_block = root_block.close_and_lock().unwrap().seal(engine, vec![]).unwrap();
if let Err(e) = client.import_block(root_block.rlp_bytes()) {
if let Err(e) = client.import_block(Unverified::from_rlp(root_block.rlp_bytes()).unwrap()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
@ -120,7 +121,7 @@ fn can_trace_block_and_uncle_reward() {
let parent_block = parent_block.close_and_lock().unwrap().seal(engine, vec![]).unwrap();
if let Err(e) = client.import_block(parent_block.rlp_bytes()) {
if let Err(e) = client.import_block(Unverified::from_rlp(parent_block.rlp_bytes()).unwrap()) {
panic!("error importing block which is valid by definition: {:?}", e);
}
@ -170,7 +171,7 @@ fn can_trace_block_and_uncle_reward() {
let block = block.close_and_lock().unwrap().seal(engine, vec![]).unwrap();
let res = client.import_block(block.rlp_bytes());
let res = client.import_block(Unverified::from_rlp(block.rlp_bytes()).unwrap());
if res.is_err() {
panic!("error importing block: {:#?}", res.err().unwrap());
}

View File

@ -23,11 +23,10 @@ use std::cmp;
use heapsize::HeapSizeOf;
use ethereum_types::H256;
use rlp::{self, Rlp};
use ethcore::views::BlockView;
use ethcore::header::{BlockNumber, Header as BlockHeader};
use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind};
use ethcore::block::Block;
use ethcore::error::{ImportErrorKind, BlockError};
use ethcore::verification::queue::kind::blocks::Unverified;
use sync_io::SyncIo;
use blocks::BlockCollection;
@ -484,18 +483,19 @@ impl BlockDownloader {
let block = block_and_receipts.block;
let receipts = block_and_receipts.receipts;
// Perform basic block verification
if !Block::is_good(&block) {
debug!(target: "sync", "Bad block rlp: {:?}", block);
bad = true;
break;
}
let (h, number, parent) = {
let header = view!(BlockView, &block).header_view();
(header.hash(), header.number(), header.parent_hash())
let block = match Unverified::from_rlp(block) {
Ok(block) => block,
Err(_) => {
debug!(target: "sync", "Bad block rlp");
bad = true;
break;
}
};
let h = block.header.hash();
let number = block.header.number();
let parent = *block.header.parent_hash();
if self.target_hash.as_ref().map_or(false, |t| t == &h) {
self.state = State::Complete;
trace!(target: "sync", "Sync target reached");

View File

@ -294,7 +294,7 @@ impl BlockCollection {
let header = view!(HeaderView, &block.header);
let block_view = Block::new_from_header_and_body(&header, &body);
drained.push(BlockAndReceipts {
block: block_view.rlp().as_raw().to_vec(),
block: block_view.into_inner(),
receipts: block.receipts.clone(),
});
}

View File

@ -19,8 +19,9 @@ use block_sync::{BlockDownloaderImportError as DownloaderImportError, DownloadAc
use bytes::Bytes;
use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKind};
use ethcore::error::*;
use ethcore::header::{BlockNumber, Header as BlockHeader};
use ethcore::header::BlockNumber;
use ethcore::snapshot::{ManifestData, RestorationStatus};
use ethcore::verification::queue::kind::blocks::Unverified;
use ethereum_types::{H256, U256};
use hash::keccak;
use network::PeerId;
@ -162,44 +163,43 @@ impl SyncHandler {
peer.difficulty = Some(difficulty);
}
}
let block_rlp = r.at(0)?;
let header_rlp = block_rlp.at(0)?;
let h = keccak(&header_rlp.as_raw());
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h);
let header: BlockHeader = header_rlp.as_val()?;
if header.number() > sync.highest_block.unwrap_or(0) {
sync.highest_block = Some(header.number());
let block = Unverified::from_rlp(r.at(0)?.as_raw().to_vec())?;
let hash = block.header.hash();
let number = block.header.number();
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, hash);
if number > sync.highest_block.unwrap_or(0) {
sync.highest_block = Some(number);
}
let mut unknown = false;
{
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
peer.latest_hash = header.hash();
}
if let Some(ref mut peer) = sync.peers.get_mut(&peer_id) {
peer.latest_hash = hash;
}
let last_imported_number = sync.new_blocks.last_imported_block_number();
if last_imported_number > header.number() && last_imported_number - header.number() > MAX_NEW_BLOCK_AGE {
trace!(target: "sync", "Ignored ancient new block {:?}", h);
if last_imported_number > number && last_imported_number - number > MAX_NEW_BLOCK_AGE {
trace!(target: "sync", "Ignored ancient new block {:?}", hash);
return Err(DownloaderImportError::Invalid);
}
match io.chain().import_block(block_rlp.as_raw().to_vec()) {
match io.chain().import_block(block) {
Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => {
trace!(target: "sync", "New block already in chain {:?}", h);
trace!(target: "sync", "New block already in chain {:?}", hash);
},
Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => {
trace!(target: "sync", "New block already queued {:?}", h);
trace!(target: "sync", "New block already queued {:?}", hash);
},
Ok(_) => {
// abort current download of the same block
sync.complete_sync(io);
sync.new_blocks.mark_as_known(&header.hash(), header.number());
trace!(target: "sync", "New block queued {:?} ({})", h, header.number());
sync.new_blocks.mark_as_known(&hash, number);
trace!(target: "sync", "New block queued {:?} ({})", hash, number);
},
Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(p)), _)) => {
unknown = true;
trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, h);
trace!(target: "sync", "New block with unknown parent ({:?}) {:?}", p, hash);
},
Err(e) => {
debug!(target: "sync", "Bad new block {:?} : {:?}", h, e);
debug!(target: "sync", "Bad new block {:?} : {:?}", hash, e);
return Err(DownloaderImportError::Invalid);
}
};
@ -207,7 +207,7 @@ impl SyncHandler {
if sync.state != SyncState::Idle {
trace!(target: "sync", "NewBlock ignored while seeking");
} else {
trace!(target: "sync", "New unknown block {:?}", h);
trace!(target: "sync", "New unknown block {:?}", hash);
//TODO: handle too many unknown blocks
sync.sync_peer(io, peer_id, true);
}

View File

@ -30,6 +30,7 @@ use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError,
use ethcore::error::{ImportErrorKind, BlockImportErrorKind};
use ethcore::miner::Miner;
use ethcore::verification::queue::VerifierSettings;
use ethcore::verification::queue::kind::blocks::Unverified;
use ethcore_service::ClientService;
use cache::CacheConfig;
use informant::{Informant, FullNodeInformantData, MillisecondDuration};
@ -417,8 +418,9 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?;
let do_import = |bytes| {
let block = Unverified::from_rlp(bytes).map_err(|_| "Invalid block rlp")?;
while client.queue_info().is_full() { sleep(Duration::from_secs(1)); }
match client.import_block(bytes) {
match client.import_block(block) {
Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => {
trace!("Skipping block already in chain.");
}

View File

@ -43,7 +43,6 @@ extern crate jsonrpc_ipc_server as ipc;
extern crate jsonrpc_pubsub;
extern crate ethash;
#[cfg_attr(test, macro_use)]
extern crate ethcore;
extern crate parity_bytes as bytes;
extern crate parity_crypto as crypto;

View File

@ -20,14 +20,13 @@ use std::sync::Arc;
use ethereum_types::{H256, Address};
use ethcore::account_provider::AccountProvider;
use ethcore::block::Block;
use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock};
use ethcore::ethereum;
use ethcore::ids::BlockId;
use ethcore::miner::Miner;
use ethcore::spec::{Genesis, Spec};
use ethcore::test_helpers;
use ethcore::views::BlockView;
use ethcore::verification::queue::kind::blocks::Unverified;
use ethjson::blockchain::BlockChain;
use ethjson::state::test::ForkSpec;
use io::IoChannel;
@ -85,9 +84,9 @@ impl EthTester {
fn from_chain(chain: &BlockChain) -> Self {
let tester = Self::from_spec(make_spec(chain));
for b in &chain.blocks_rlp() {
if Block::is_good(&b) {
let _ = tester.client.import_block(b.clone());
for b in chain.blocks_rlp() {
if let Ok(block) = Unverified::from_rlp(b) {
let _ = tester.client.import_block(block);
tester.client.flush_queue();
tester.client.import_verified_blocks();
}
@ -423,11 +422,11 @@ fn verify_transaction_counts(name: String, chain: BlockChain) {
let tester = EthTester::from_chain(&chain);
let mut id = 1;
for b in chain.blocks_rlp().iter().filter(|b| Block::is_good(b)).map(|b| view!(BlockView, b)) {
let count = b.transactions_count();
for b in chain.blocks_rlp().into_iter().filter_map(|b| Unverified::from_rlp(b).ok()) {
let count = b.transactions.len();
let hash = b.hash();
let number = b.header_view().number();
let hash = b.header.hash();
let number = b.header.number();
let (req, res) = by_hash(hash, count, &mut id);
assert_eq!(tester.handler.handle_request_sync(&req), Some(res));