-
Notifications
You must be signed in to change notification settings - Fork 1.7k
decode block rlp less often #9252
Changes from all commits
eb78076
91edc42
0efdf0f
8290fb7
35fcb81
a19faf0
32f7b38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as mentioned before, this checks could lead to invalid block being locked, so I removed them |
||
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)> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
) -> 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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed redundant decoding of uncles |
||
engine, | ||
tracing, | ||
db, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,6 +74,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; | ||
|
@@ -209,7 +211,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 | ||
|
@@ -429,19 +431,19 @@ 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(); | ||
|
||
{ | ||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So where does the verification actually happen? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4 lines above, we verify only header for old blocks. No logic has been changed here |
||
// Final commit to the DB | ||
db.write_buffered(batch); | ||
chain.commit(); | ||
|
@@ -1382,22 +1384,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)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed redundant block deserialization |
||
|
||
{ | ||
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)?) | ||
} | ||
} | ||
|
@@ -2022,24 +2017,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)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed redundant header deserialization |
||
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))); | ||
} | ||
} | ||
} | ||
|
@@ -2048,7 +2042,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(); | ||
|
@@ -2060,11 +2054,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(), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a very long and noisy line... |
||
} | ||
sync_client.flush_queue(); | ||
assert_eq!(sync_client.chain_info().best_block_number, 3); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this callback happen after this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/paritytech/parity-ethereum/pull/9252/files#diff-e2e171033e005c3b329818aaff213767R408