Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit 143411a

Browse files
authored
deserialize block only once during verification (#9161)
1 parent 7d95484 commit 143411a

File tree

5 files changed

+113
-72
lines changed

5 files changed

+113
-72
lines changed

ethcore/src/client/client.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,14 @@ use transaction::{self, LocalizedTransaction, UnverifiedTransaction, SignedTrans
7373
use types::filter::Filter;
7474
use types::ancestry_action::AncestryAction;
7575
use verification;
76-
use verification::{PreverifiedBlock, Verifier};
77-
use verification::queue::BlockQueue;
76+
use verification::{PreverifiedBlock, Verifier, BlockQueue};
7877
use views::BlockView;
7978

8079
// re-export
8180
pub use types::blockchain_info::BlockChainInfo;
8281
pub use types::block_status::BlockStatus;
8382
pub use blockchain::CacheSize as BlockChainCacheSize;
84-
pub use verification::queue::QueueInfo as BlockQueueInfo;
83+
pub use verification::QueueInfo as BlockQueueInfo;
8584

8685
use_contract!(registry, "Registry", "res/contracts/registrar.json");
8786

@@ -371,8 +370,7 @@ impl Importer {
371370
&parent,
372371
engine,
373372
Some(verification::FullFamilyParams {
374-
block_bytes: &block.bytes,
375-
transactions: &block.transactions,
373+
block: &block,
376374
block_provider: &**chain,
377375
client
378376
}),

ethcore/src/verification/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
//! Block verification utilities.
1818
19-
pub mod verification;
20-
pub mod verifier;
19+
mod verification;
20+
mod verifier;
2121
pub mod queue;
2222
mod canon_verifier;
2323
mod noop_verifier;

ethcore/src/verification/queue/kind.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub mod blocks {
7272
use error::{Error, ErrorKind, BlockError};
7373
use header::Header;
7474
use verification::{PreverifiedBlock, verify_block_basic, verify_block_unordered};
75+
use transaction::UnverifiedTransaction;
7576

7677
use heapsize::HeapSizeOf;
7778
use ethereum_types::{H256, U256};
@@ -86,7 +87,7 @@ pub mod blocks {
8687
type Verified = PreverifiedBlock;
8788

8889
fn create(input: Self::Input, engine: &EthEngine) -> Result<Self::Unverified, Error> {
89-
match verify_block_basic(&input.header, &input.bytes, engine) {
90+
match verify_block_basic(&input, engine) {
9091
Ok(()) => Ok(input),
9192
Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(oob)), _)) => {
9293
debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob);
@@ -101,7 +102,7 @@ pub mod blocks {
101102

102103
fn verify(un: Self::Unverified, engine: &EthEngine, check_seal: bool) -> Result<Self::Verified, Error> {
103104
let hash = un.hash();
104-
match verify_block_unordered(un.header, un.bytes, engine, check_seal) {
105+
match verify_block_unordered(un, engine, check_seal) {
105106
Ok(verified) => Ok(verified),
106107
Err(e) => {
107108
warn!(target: "client", "Stage 2 block verification failed for {}: {:?}", hash, e);
@@ -113,25 +114,43 @@ pub mod blocks {
113114

114115
/// An unverified block.
115116
pub struct Unverified {
116-
header: Header,
117-
bytes: Bytes,
117+
/// Unverified block header.
118+
pub header: Header,
119+
/// Unverified block transactions.
120+
pub transactions: Vec<UnverifiedTransaction>,
121+
/// Unverified block uncles.
122+
pub uncles: Vec<Header>,
123+
/// Raw block bytes.
124+
pub bytes: Bytes,
118125
}
119126

120127
impl Unverified {
121128
/// Create an `Unverified` from raw bytes.
122129
pub fn from_rlp(bytes: Bytes) -> Result<Self, ::rlp::DecoderError> {
130+
use rlp::Rlp;
131+
let (header, transactions, uncles) = {
132+
let rlp = Rlp::new(&bytes);
133+
let header = rlp.val_at(0)?;
134+
let transactions = rlp.list_at(1)?;
135+
let uncles = rlp.list_at(2)?;
136+
(header, transactions, uncles)
137+
};
123138

124-
let header = ::rlp::Rlp::new(&bytes).val_at(0)?;
125139
Ok(Unverified {
126-
header: header,
127-
bytes: bytes,
140+
header,
141+
transactions,
142+
uncles,
143+
bytes,
128144
})
129145
}
130146
}
131147

132148
impl HeapSizeOf for Unverified {
133149
fn heap_size_of_children(&self) -> usize {
134-
self.header.heap_size_of_children() + self.bytes.heap_size_of_children()
150+
self.header.heap_size_of_children()
151+
+ self.transactions.heap_size_of_children()
152+
+ self.uncles.heap_size_of_children()
153+
+ self.bytes.heap_size_of_children()
135154
}
136155
}
137156

ethcore/src/verification/verification.rs

+74-56
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use std::collections::HashSet;
2525
use std::time::{Duration, SystemTime, UNIX_EPOCH};
2626

2727
use bytes::Bytes;
28-
use ethereum_types::H256;
2928
use hash::keccak;
3029
use heapsize::HeapSizeOf;
3130
use rlp::Rlp;
@@ -37,15 +36,17 @@ use client::{BlockInfo, CallContract};
3736
use engines::EthEngine;
3837
use error::{BlockError, Error};
3938
use header::{BlockNumber, Header};
40-
use transaction::{SignedTransaction, UnverifiedTransaction};
41-
use views::BlockView;
39+
use transaction::SignedTransaction;
40+
use verification::queue::kind::blocks::Unverified;
4241

4342
/// Preprocessed block data gathered in `verify_block_unordered` call
4443
pub struct PreverifiedBlock {
4544
/// Populated block header
4645
pub header: Header,
4746
/// Populated block transactions
4847
pub transactions: Vec<SignedTransaction>,
48+
/// Populated block uncles
49+
pub uncles: Vec<Header>,
4950
/// Block bytes
5051
pub bytes: Bytes,
5152
}
@@ -59,63 +60,66 @@ impl HeapSizeOf for PreverifiedBlock {
5960
}
6061

6162
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
62-
pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &EthEngine) -> Result<(), Error> {
63-
verify_header_params(&header, engine, true)?;
64-
verify_block_integrity(bytes, &header.transactions_root(), &header.uncles_hash())?;
65-
engine.verify_block_basic(&header)?;
66-
for u in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
67-
let u = u?;
68-
verify_header_params(&u, engine, false)?;
69-
engine.verify_block_basic(&u)?;
63+
pub fn verify_block_basic(block: &Unverified, engine: &EthEngine) -> Result<(), Error> {
64+
verify_header_params(&block.header, engine, true)?;
65+
verify_block_integrity(block)?;
66+
engine.verify_block_basic(&block.header)?;
67+
68+
for uncle in &block.uncles {
69+
verify_header_params(uncle, engine, false)?;
70+
engine.verify_block_basic(uncle)?;
7071
}
7172

72-
for t in Rlp::new(bytes).at(1)?.iter().map(|rlp| rlp.as_val::<UnverifiedTransaction>()) {
73-
engine.verify_transaction_basic(&t?, &header)?;
73+
for t in &block.transactions {
74+
engine.verify_transaction_basic(t, &block.header)?;
7475
}
76+
7577
Ok(())
7678
}
7779

7880
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
7981
/// Still operates on a individual block
8082
/// Returns a `PreverifiedBlock` structure populated with transactions
81-
pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine, check_seal: bool) -> Result<PreverifiedBlock, Error> {
83+
pub fn verify_block_unordered(block: Unverified, engine: &EthEngine, check_seal: bool) -> Result<PreverifiedBlock, Error> {
84+
let header = block.header;
8285
if check_seal {
8386
engine.verify_block_unordered(&header)?;
84-
for u in Rlp::new(&bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
85-
engine.verify_block_unordered(&u?)?;
87+
for uncle in &block.uncles {
88+
engine.verify_block_unordered(uncle)?;
8689
}
8790
}
8891
// Verify transactions.
89-
let mut transactions = Vec::new();
9092
let nonce_cap = if header.number() >= engine.params().dust_protection_transition {
9193
Some((engine.params().nonce_cap_increment * header.number()).into())
92-
} else { None };
93-
{
94-
let v = view!(BlockView, &bytes);
95-
for t in v.transactions() {
94+
} else {
95+
None
96+
};
97+
98+
let transactions = block.transactions
99+
.into_iter()
100+
.map(|t| {
96101
let t = engine.verify_transaction_unordered(t, &header)?;
97102
if let Some(max_nonce) = nonce_cap {
98103
if t.nonce >= max_nonce {
99104
return Err(BlockError::TooManyTransactions(t.sender()).into());
100105
}
101106
}
102-
transactions.push(t);
103-
}
104-
}
107+
Ok(t)
108+
})
109+
.collect::<Result<Vec<_>, Error>>()?;
110+
105111
Ok(PreverifiedBlock {
106-
header: header,
107-
transactions: transactions,
108-
bytes: bytes,
112+
header,
113+
transactions,
114+
uncles: block.uncles,
115+
bytes: block.bytes,
109116
})
110117
}
111118

112119
/// Parameters for full verification of block family
113120
pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
114-
/// Serialized block bytes
115-
pub block_bytes: &'a [u8],
116-
117-
/// Signed transactions
118-
pub transactions: &'a [SignedTransaction],
121+
/// Preverified block
122+
pub block: &'a PreverifiedBlock,
119123

120124
/// Block provider to use during verification
121125
pub block_provider: &'a BlockProvider,
@@ -135,17 +139,18 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(header: &Header, parent:
135139
None => return Ok(()),
136140
};
137141

138-
verify_uncles(header, params.block_bytes, params.block_provider, engine)?;
142+
verify_uncles(params.block, params.block_provider, engine)?;
139143

140-
for transaction in params.transactions {
141-
engine.machine().verify_transaction(transaction, header, params.client)?;
144+
for tx in &params.block.transactions {
145+
engine.machine().verify_transaction(tx, header, params.client)?;
142146
}
143147

144148
Ok(())
145149
}
146150

147-
fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
148-
let num_uncles = Rlp::new(bytes).at(2)?.item_count()?;
151+
fn verify_uncles(block: &PreverifiedBlock, bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> {
152+
let header = &block.header;
153+
let num_uncles = block.uncles.len();
149154
let max_uncles = engine.maximum_uncle_count(header.number());
150155
if num_uncles != 0 {
151156
if num_uncles > max_uncles {
@@ -174,8 +179,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth
174179
}
175180

176181
let mut verified = HashSet::new();
177-
for uncle in Rlp::new(bytes).at(2)?.iter().map(|rlp| rlp.as_val::<Header>()) {
178-
let uncle = uncle?;
182+
for uncle in &block.uncles {
179183
if excluded.contains(&uncle.hash()) {
180184
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
181185
}
@@ -332,16 +336,22 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result
332336
}
333337

334338
/// Verify block data against header: transactions root and uncles hash.
335-
fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &H256) -> Result<(), Error> {
336-
let block = Rlp::new(block);
337-
let tx = block.at(1)?;
338-
let expected_root = &ordered_trie_root(tx.iter().map(|r| r.as_raw()));
339-
if expected_root != transactions_root {
340-
return Err(From::from(BlockError::InvalidTransactionsRoot(Mismatch { expected: expected_root.clone(), found: transactions_root.clone() })))
341-
}
342-
let expected_uncles = &keccak(block.at(2)?.as_raw());
343-
if expected_uncles != uncles_hash {
344-
return Err(From::from(BlockError::InvalidUnclesHash(Mismatch { expected: expected_uncles.clone(), found: uncles_hash.clone() })))
339+
fn verify_block_integrity(block: &Unverified) -> Result<(), Error> {
340+
let block_rlp = Rlp::new(&block.bytes);
341+
let tx = block_rlp.at(1)?;
342+
let expected_root = ordered_trie_root(tx.iter().map(|r| r.as_raw()));
343+
if &expected_root != block.header.transactions_root() {
344+
bail!(BlockError::InvalidTransactionsRoot(Mismatch {
345+
expected: expected_root,
346+
found: *block.header.transactions_root(),
347+
}));
348+
}
349+
let expected_uncles = keccak(block_rlp.at(2)?.as_raw());
350+
if &expected_uncles != block.header.uncles_hash(){
351+
bail!(BlockError::InvalidUnclesHash(Mismatch {
352+
expected: expected_uncles,
353+
found: *block.header.uncles_hash(),
354+
}));
345355
}
346356
Ok(())
347357
}
@@ -366,6 +376,7 @@ mod tests {
366376
use types::log_entry::{LogEntry, LocalizedLogEntry};
367377
use rlp;
368378
use triehash::ordered_trie_root;
379+
use views::BlockView;
369380

370381
fn check_ok(result: Result<(), Error>) {
371382
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
@@ -486,8 +497,8 @@ mod tests {
486497
}
487498

488499
fn basic_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> {
489-
let header = view!(BlockView, bytes).header();
490-
verify_block_basic(&header, bytes, engine)
500+
let unverified = Unverified::from_rlp(bytes.to_vec())?;
501+
verify_block_basic(&unverified, engine)
491502
}
492503

493504
fn family_test<BC>(bytes: &[u8], engine: &EthEngine, bc: &BC) -> Result<(), Error> where BC: BlockProvider {
@@ -507,18 +518,25 @@ mod tests {
507518
.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?
508519
.decode()?;
509520

521+
let block = PreverifiedBlock {
522+
header,
523+
transactions,
524+
uncles: view.uncles(),
525+
bytes: bytes.to_vec(),
526+
};
527+
510528
let full_params = FullFamilyParams {
511-
block_bytes: bytes,
512-
transactions: &transactions[..],
529+
block: &block,
513530
block_provider: bc as &BlockProvider,
514531
client: &client,
515532
};
516-
verify_block_family(&header, &parent, engine, Some(full_params))
533+
verify_block_family(&block.header, &parent, engine, Some(full_params))
517534
}
518535

519536
fn unordered_test(bytes: &[u8], engine: &EthEngine) -> Result<(), Error> {
520-
let header = view!(BlockView, bytes).header();
521-
verify_block_unordered(header, bytes.to_vec(), engine, false)?;
537+
use verification::queue::kind::blocks::Unverified;
538+
let un = Unverified::from_rlp(bytes.to_vec())?;
539+
verify_block_unordered(un, engine, false)?;
522540
Ok(())
523541
}
524542

ethcore/transaction/src/transaction.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,12 @@ pub struct UnverifiedTransaction {
282282
hash: H256,
283283
}
284284

285+
impl HeapSizeOf for UnverifiedTransaction {
286+
fn heap_size_of_children(&self) -> usize {
287+
self.unsigned.heap_size_of_children()
288+
}
289+
}
290+
285291
impl Deref for UnverifiedTransaction {
286292
type Target = Transaction;
287293

@@ -436,7 +442,7 @@ pub struct SignedTransaction {
436442

437443
impl HeapSizeOf for SignedTransaction {
438444
fn heap_size_of_children(&self) -> usize {
439-
self.transaction.unsigned.heap_size_of_children()
445+
self.transaction.heap_size_of_children()
440446
}
441447
}
442448

0 commit comments

Comments
 (0)