2020-09-22 14:53:52 +02:00
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
2016-02-05 13:40:41 +01:00
2020-09-22 14:53:52 +02:00
// OpenEthereum is free software: you can redistribute it and/or modify
2016-02-05 13:40:41 +01:00
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2020-09-22 14:53:52 +02:00
// OpenEthereum is distributed in the hope that it will be useful,
2016-02-05 13:40:41 +01:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
2020-09-22 14:53:52 +02:00
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
2016-02-05 13:40:41 +01:00
2018-07-15 11:01:47 +02:00
//! Base data structure of this module is `Block`.
//!
//! Blocks can be produced by a local node or they may be received from the network.
//!
//! To create a block locally, we start with an `OpenBlock`. This block is mutable
//! and can be appended to with transactions and uncles.
//!
//! When ready, `OpenBlock` can be closed and turned into a `ClosedBlock`. A `ClosedBlock` can
//! be reopend again by a miner under certain circumstances. On block close, state commit is
//! performed.
//!
//! `LockedBlock` is a version of a `ClosedBlock` that cannot be reopened. It can be sealed
//! using an engine.
//!
//! `ExecutedBlock` is an underlaying data structure used by all structs above to store block
//! related info.
2016-02-02 15:29:53 +01:00
2020-08-05 06:08:03 +02:00
use std ::{ cmp , collections ::HashSet , ops , sync ::Arc } ;
2016-10-03 23:29:46 +02:00
2017-09-06 20:47:45 +02:00
use bytes ::Bytes ;
2020-08-05 06:08:03 +02:00
use ethereum_types ::{ Address , Bloom , H256 , U256 } ;
2019-01-04 14:05:46 +01:00
2017-09-26 14:19:08 +02:00
use engines ::EthEngine ;
2020-08-05 06:08:03 +02:00
use error ::{ BlockError , Error } ;
2016-10-03 23:29:46 +02:00
use factory ::Factories ;
2018-07-02 18:50:05 +02:00
use state ::State ;
2020-08-05 06:08:03 +02:00
use state_db ::StateDB ;
2018-02-27 18:22:56 +01:00
use trace ::Tracing ;
2018-07-02 18:50:05 +02:00
use triehash ::ordered_trie_root ;
use unexpected ::{ Mismatch , OutOfBounds } ;
2016-10-03 23:29:46 +02:00
use verification ::PreverifiedBlock ;
2018-07-02 18:50:05 +02:00
use vm ::{ EnvInfo , LastHashes } ;
2016-01-08 19:12:19 +01:00
2019-01-04 14:05:46 +01:00
use hash ::keccak ;
2020-12-10 16:42:05 +01:00
use rlp ::{ encode_list , RlpStream } ;
2020-08-05 06:08:03 +02:00
use types ::{
header ::{ ExtendedHeader , Header } ,
2020-12-10 16:42:05 +01:00
receipt ::{ TransactionOutcome , TypedReceipt } ,
2020-08-05 06:08:03 +02:00
transaction ::{ Error as TransactionError , SignedTransaction } ,
} ;
2019-01-04 14:05:46 +01:00
/// Block that is ready for transactions to be added.
///
/// It's a bit like a Vec<Transaction>, except that whenever a transaction is pushed, we execute it and
/// maintain the system `state()`. We also archive execution receipts in preparation for later block creation.
pub struct OpenBlock < ' x > {
2020-08-05 06:08:03 +02:00
block : ExecutedBlock ,
2020-07-29 10:36:15 +02:00
engine : & ' x dyn EthEngine ,
2016-01-26 19:18:22 +01:00
}
2016-01-08 19:12:19 +01:00
2019-01-04 14:05:46 +01:00
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
/// and collected the uncles.
///
/// There is no function available to push a transaction.
#[ derive(Clone) ]
pub struct ClosedBlock {
2020-08-05 06:08:03 +02:00
block : ExecutedBlock ,
unclosed_state : State < StateDB > ,
2016-01-26 19:18:22 +01:00
}
2016-01-08 19:12:19 +01:00
2019-01-04 14:05:46 +01:00
/// Just like `ClosedBlock` except that we can't reopen it and it's faster.
///
/// We actually store the post-`Engine::on_close_block` state, unlike in `ClosedBlock` where it's the pre.
#[ derive(Clone) ]
pub struct LockedBlock {
2020-08-05 06:08:03 +02:00
block : ExecutedBlock ,
2019-01-04 14:05:46 +01:00
}
/// A block that has a valid seal.
///
/// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`.
pub struct SealedBlock {
2020-08-05 06:08:03 +02:00
block : ExecutedBlock ,
2016-01-26 19:18:22 +01:00
}
2016-01-10 14:05:39 +01:00
2016-09-28 23:31:59 +02:00
/// An internal type for a block's common elements.
2016-03-22 13:05:18 +01:00
#[ derive(Clone) ]
2016-01-26 19:18:22 +01:00
pub struct ExecutedBlock {
2020-08-05 06:08:03 +02:00
/// Executed block header.
pub header : Header ,
/// Executed transactions.
pub transactions : Vec < SignedTransaction > ,
/// Uncles.
pub uncles : Vec < Header > ,
/// Transaction receipts.
2020-12-10 16:42:05 +01:00
pub receipts : Vec < TypedReceipt > ,
2020-08-05 06:08:03 +02:00
/// Hashes of already executed transactions.
pub transactions_set : HashSet < H256 > ,
/// Underlaying state.
pub state : State < StateDB > ,
/// Transaction traces.
pub traces : Tracing ,
/// Hashes of last 256 blocks.
pub last_hashes : Arc < LastHashes > ,
2016-01-08 19:12:19 +01:00
}
2016-01-26 19:18:22 +01:00
impl ExecutedBlock {
2020-08-05 06:08:03 +02:00
/// Create a new block from the given `state`.
fn new ( state : State < StateDB > , last_hashes : Arc < LastHashes > , tracing : bool ) -> ExecutedBlock {
ExecutedBlock {
header : Default ::default ( ) ,
transactions : Default ::default ( ) ,
uncles : Default ::default ( ) ,
receipts : Default ::default ( ) ,
transactions_set : Default ::default ( ) ,
state : state ,
traces : if tracing {
Tracing ::enabled ( )
} else {
Tracing ::Disabled
} ,
last_hashes : last_hashes ,
}
}
/// Get the environment info concerning this block.
pub fn env_info ( & self ) -> EnvInfo {
// TODO: memoise.
EnvInfo {
number : self . header . number ( ) ,
author : self . header . author ( ) . clone ( ) ,
timestamp : self . header . timestamp ( ) ,
difficulty : self . header . difficulty ( ) . clone ( ) ,
last_hashes : self . last_hashes . clone ( ) ,
gas_used : self . receipts . last ( ) . map_or ( U256 ::zero ( ) , | r | r . gas_used ) ,
gas_limit : self . header . gas_limit ( ) . clone ( ) ,
}
}
/// Get mutable access to a state.
pub fn state_mut ( & mut self ) -> & mut State < StateDB > {
& mut self . state
}
/// Get mutable reference to traces.
pub fn traces_mut ( & mut self ) -> & mut Tracing {
& mut self . traces
}
2016-01-08 19:12:19 +01:00
}
2018-07-15 11:01:47 +02:00
/// Trait for an object that owns an `ExecutedBlock`
2016-06-29 21:49:12 +02:00
pub trait Drain {
2020-08-05 06:08:03 +02:00
/// Returns `ExecutedBlock`
fn drain ( self ) -> ExecutedBlock ;
2016-06-29 21:49:12 +02:00
}
2016-02-24 11:17:25 +01:00
impl < ' x > OpenBlock < ' x > {
2020-12-09 12:43:32 +01:00
/// t_nb 8.1 Create a new `OpenBlock` ready for transaction pushing.
2020-08-05 06:08:03 +02:00
pub fn new < ' a , I : IntoIterator < Item = ExtendedHeader > > (
2020-07-29 10:36:15 +02:00
engine : & ' x dyn EthEngine ,
2020-08-05 06:08:03 +02:00
factories : Factories ,
tracing : bool ,
db : StateDB ,
parent : & Header ,
last_hashes : Arc < LastHashes > ,
author : Address ,
gas_range_target : ( U256 , U256 ) ,
extra_data : Bytes ,
is_epoch_begin : bool ,
ancestry : I ,
) -> Result < Self , Error > {
let number = parent . number ( ) + 1 ;
2020-12-02 11:31:11 +01:00
// t_nb 8.1.1 get parent StateDB.
2020-08-05 06:08:03 +02:00
let state = State ::from_existing (
db ,
parent . state_root ( ) . clone ( ) ,
engine . account_start_nonce ( number ) ,
factories ,
) ? ;
let mut r = OpenBlock {
block : ExecutedBlock ::new ( state , last_hashes , tracing ) ,
engine : engine ,
} ;
r . block . header . set_parent_hash ( parent . hash ( ) ) ;
r . block . header . set_number ( number ) ;
r . block . header . set_author ( author ) ;
r . block
. header
. set_timestamp ( engine . open_block_header_timestamp ( parent . timestamp ( ) ) ) ;
r . block . header . set_extra_data ( extra_data ) ;
let gas_floor_target = cmp ::max ( gas_range_target . 0 , engine . params ( ) . min_gas_limit ) ;
let gas_ceil_target = cmp ::max ( gas_range_target . 1 , gas_floor_target ) ;
2020-12-02 11:31:11 +01:00
// t_nb 8.1.2 It calculated child gas limits should be.
2020-08-05 06:08:03 +02:00
engine . machine ( ) . populate_from_parent (
& mut r . block . header ,
parent ,
gas_floor_target ,
gas_ceil_target ,
) ;
2020-12-02 11:31:11 +01:00
// t_nb 8.1.3 this adds engine specific things
2020-08-05 06:08:03 +02:00
engine . populate_from_parent ( & mut r . block . header , parent ) ;
2020-12-02 11:31:11 +01:00
// t_nb 8.1.3 updating last hashes and the DAO fork, for ethash.
2020-08-05 06:08:03 +02:00
engine . machine ( ) . on_new_block ( & mut r . block ) ? ;
engine . on_new_block ( & mut r . block , is_epoch_begin , & mut ancestry . into_iter ( ) ) ? ;
Ok ( r )
}
/// Alter the timestamp of the block.
pub fn set_timestamp ( & mut self , timestamp : u64 ) {
self . block . header . set_timestamp ( timestamp ) ;
}
/// Removes block gas limit.
pub fn remove_gas_limit ( & mut self ) {
self . block . header . set_gas_limit ( U256 ::max_value ( ) ) ;
}
2020-12-02 11:31:11 +01:00
// t_nb 8.4 Add an uncle to the block, if possible.
2020-08-05 06:08:03 +02:00
///
/// NOTE Will check chain constraints and the uncle number but will NOT check
/// that the header itself is actually valid.
pub fn push_uncle ( & mut self , valid_uncle_header : Header ) -> Result < ( ) , BlockError > {
let max_uncles = self . engine . maximum_uncle_count ( self . block . header . number ( ) ) ;
if self . block . uncles . len ( ) + 1 > max_uncles {
return Err ( BlockError ::TooManyUncles ( OutOfBounds {
min : None ,
max : Some ( max_uncles ) ,
found : self . block . uncles . len ( ) + 1 ,
} ) ) ;
}
// TODO: check number
// TODO: check not a direct ancestor (use last_hashes for that)
self . block . uncles . push ( valid_uncle_header ) ;
Ok ( ( ) )
}
/// Push a transaction into the block.
///
/// If valid, it will be executed, and archived together with the receipt.
pub fn push_transaction (
& mut self ,
t : SignedTransaction ,
h : Option < H256 > ,
2020-12-10 16:42:05 +01:00
) -> Result < & TypedReceipt , Error > {
2020-08-05 06:08:03 +02:00
if self . block . transactions_set . contains ( & t . hash ( ) ) {
return Err ( TransactionError ::AlreadyImported . into ( ) ) ;
}
let env_info = self . block . env_info ( ) ;
let outcome = self . block . state . apply (
& env_info ,
self . engine . machine ( ) ,
& t ,
self . block . traces . is_enabled ( ) ,
) ? ;
self . block
. transactions_set
. insert ( h . unwrap_or_else ( | | t . hash ( ) ) ) ;
self . block . transactions . push ( t . into ( ) ) ;
if let Tracing ::Enabled ( ref mut traces ) = self . block . traces {
traces . push ( outcome . trace . into ( ) ) ;
}
self . block . receipts . push ( outcome . receipt ) ;
Ok ( self
. block
. receipts
. last ( )
. expect ( " receipt just pushed; qed " ) )
}
/// Push transactions onto the block.
#[ cfg(not(feature = " slow-blocks " )) ]
fn push_transactions ( & mut self , transactions : Vec < SignedTransaction > ) -> Result < ( ) , Error > {
for t in transactions {
self . push_transaction ( t , None ) ? ;
}
Ok ( ( ) )
}
/// Push transactions onto the block.
#[ cfg(feature = " slow-blocks " ) ]
fn push_transactions ( & mut self , transactions : Vec < SignedTransaction > ) -> Result < ( ) , Error > {
use std ::time ;
let slow_tx = option_env! ( " SLOW_TX_DURATION " )
. and_then ( | v | v . parse ( ) . ok ( ) )
. unwrap_or ( 100 ) ;
for t in transactions {
let hash = t . hash ( ) ;
let start = time ::Instant ::now ( ) ;
self . push_transaction ( t , None ) ? ;
let took = start . elapsed ( ) ;
let took_ms = took . as_secs ( ) * 1000 + took . subsec_nanos ( ) as u64 / 1000000 ;
if took > time ::Duration ::from_millis ( slow_tx ) {
warn! (
" Heavy ({} ms) transaction in block {:?}: {:?} " ,
took_ms ,
2020-07-29 08:42:17 +02:00
self . block . header . number ( ) ,
2020-08-05 06:08:03 +02:00
hash
) ;
}
debug! ( target : " tx " , " Transaction {:?} took: {} ms " , hash , took_ms ) ;
}
Ok ( ( ) )
}
/// Populate self from a header.
fn populate_from ( & mut self , header : & Header ) {
self . block . header . set_difficulty ( * header . difficulty ( ) ) ;
self . block . header . set_gas_limit ( * header . gas_limit ( ) ) ;
self . block . header . set_timestamp ( header . timestamp ( ) ) ;
self . block . header . set_uncles_hash ( * header . uncles_hash ( ) ) ;
self . block
. header
. set_transactions_root ( * header . transactions_root ( ) ) ;
// TODO: that's horrible. set only for backwards compatibility
if header . extra_data ( ) . len ( ) > self . engine . maximum_extra_data_size ( ) {
warn! ( " Couldn't set extradata. Ignoring. " ) ;
} else {
self . block
. header
. set_extra_data ( header . extra_data ( ) . clone ( ) ) ;
}
}
/// Turn this into a `ClosedBlock`.
pub fn close ( self ) -> Result < ClosedBlock , Error > {
let unclosed_state = self . block . state . clone ( ) ;
let locked = self . close_and_lock ( ) ? ;
Ok ( ClosedBlock {
block : locked . block ,
unclosed_state ,
} )
}
2020-12-09 12:43:32 +01:00
/// t_nb 8.5 Turn this into a `LockedBlock`.
2020-08-05 06:08:03 +02:00
pub fn close_and_lock ( self ) -> Result < LockedBlock , Error > {
let mut s = self ;
2020-12-02 11:31:11 +01:00
// t_nb 8.5.1 engine applies block rewards (Ethash and AuRa do.Clique is empty)
2020-08-05 06:08:03 +02:00
s . engine . on_close_block ( & mut s . block ) ? ;
2020-12-02 11:31:11 +01:00
// t_nb 8.5.2 commit account changes from cache to tree
2020-08-05 06:08:03 +02:00
s . block . state . commit ( ) ? ;
2020-12-02 11:31:11 +01:00
// t_nb 8.5.3 fill open block header with all other fields
2020-08-05 06:08:03 +02:00
s . block . header . set_transactions_root ( ordered_trie_root (
2020-12-10 16:42:05 +01:00
s . block . transactions . iter ( ) . map ( | e | e . encode ( ) ) ,
2020-08-05 06:08:03 +02:00
) ) ;
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 (
2020-12-10 16:42:05 +01:00
s . block . receipts . iter ( ) . map ( | r | r . encode ( ) ) ,
2020-08-05 06:08:03 +02:00
) ) ;
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 ) ,
) ;
Ok ( LockedBlock { block : s . block } )
}
#[ cfg(test) ]
/// Return mutable block reference. To be used in tests only.
pub fn block_mut ( & mut self ) -> & mut ExecutedBlock {
& mut self . block
}
2016-01-08 19:12:19 +01:00
}
2019-03-15 13:22:47 +01:00
impl < ' a > ops ::Deref for OpenBlock < ' a > {
2020-08-05 06:08:03 +02:00
type Target = ExecutedBlock ;
2019-03-15 13:22:47 +01:00
2020-08-05 06:08:03 +02:00
fn deref ( & self ) -> & Self ::Target {
& self . block
}
2016-01-08 19:12:19 +01:00
}
2019-03-15 13:22:47 +01:00
impl ops ::Deref for ClosedBlock {
2020-08-05 06:08:03 +02:00
type Target = ExecutedBlock ;
2019-03-15 13:22:47 +01:00
2020-08-05 06:08:03 +02:00
fn deref ( & self ) -> & Self ::Target {
& self . block
}
2016-01-10 14:05:39 +01:00
}
2019-03-15 13:22:47 +01:00
impl ops ::Deref for LockedBlock {
2020-08-05 06:08:03 +02:00
type Target = ExecutedBlock ;
2019-03-15 13:22:47 +01:00
2020-08-05 06:08:03 +02:00
fn deref ( & self ) -> & Self ::Target {
& self . block
}
2016-03-27 20:33:23 +02:00
}
2019-03-15 13:22:47 +01:00
impl ops ::Deref for SealedBlock {
2020-08-05 06:08:03 +02:00
type Target = ExecutedBlock ;
2016-01-08 19:12:19 +01:00
2020-08-05 06:08:03 +02:00
fn deref ( & self ) -> & Self ::Target {
& self . block
}
2019-03-15 13:22:47 +01:00
}
impl ClosedBlock {
2020-08-05 06:08:03 +02:00
/// Turn this into a `LockedBlock`, unable to be reopened again.
pub fn lock ( self ) -> LockedBlock {
LockedBlock { block : self . block }
}
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
2020-07-29 10:36:15 +02:00
pub fn reopen ( self , engine : & dyn EthEngine ) -> OpenBlock {
2020-08-05 06:08:03 +02:00
// revert rewards (i.e. set state back at last transaction's state).
let mut block = self . block ;
block . state = self . unclosed_state ;
OpenBlock {
block : block ,
engine : engine ,
}
}
2016-03-27 20:33:23 +02:00
}
impl LockedBlock {
2020-08-05 06:08:03 +02:00
/// Removes outcomes from receipts and updates the receipt root.
///
/// This is done after the block is enacted for historical reasons.
/// We allow inconsistency in receipts for some chains if `validate_receipts_transition`
/// is set to non-zero value, so the check only happens if we detect
/// unmatching root first and then fall back to striped receipts.
pub fn strip_receipts_outcomes ( & mut self ) {
for receipt in & mut self . block . receipts {
receipt . outcome = TransactionOutcome ::Unknown ;
}
self . block . header . set_receipts_root ( ordered_trie_root (
2020-12-10 16:42:05 +01:00
self . block . receipts . iter ( ) . map ( | r | r . encode ( ) ) ,
2020-08-05 06:08:03 +02:00
) ) ;
}
/// Provide a valid seal in order to turn this into a `SealedBlock`.
///
/// NOTE: This does not check the validity of `seal` with the engine.
2020-07-29 10:36:15 +02:00
pub fn seal ( self , engine : & dyn EthEngine , seal : Vec < Bytes > ) -> Result < SealedBlock , Error > {
2020-08-05 06:08:03 +02:00
let expected_seal_fields = engine . seal_fields ( & self . header ) ;
let mut s = self ;
if seal . len ( ) ! = expected_seal_fields {
Err ( BlockError ::InvalidSealArity ( Mismatch {
expected : expected_seal_fields ,
found : seal . len ( ) ,
} ) ) ? ;
}
s . block . header . set_seal ( seal ) ;
engine . on_seal_block ( & mut s . block ) ? ;
s . block . header . compute_hash ( ) ;
Ok ( SealedBlock { block : s . block } )
}
/// Provide a valid seal in order to turn this into a `SealedBlock`.
/// This does check the validity of `seal` with the engine.
/// Returns the `ClosedBlock` back again if the seal is no good.
2020-09-22 14:53:52 +02:00
/// TODO(https://github.com/openethereum/openethereum/issues/10407): This is currently only used in POW chain call paths, we should really merge it with seal() above.
2020-07-29 10:36:15 +02:00
pub fn try_seal ( self , engine : & dyn EthEngine , seal : Vec < Bytes > ) -> Result < SealedBlock , Error > {
2020-08-05 06:08:03 +02:00
let mut s = self ;
s . block . header . set_seal ( seal ) ;
s . block . header . compute_hash ( ) ;
// TODO: passing state context to avoid engines owning it?
engine . verify_local_seal ( & s . block . header ) ? ;
Ok ( SealedBlock { block : s . block } )
}
2016-06-29 21:49:12 +02:00
}
2016-03-01 00:02:48 +01:00
2016-06-29 21:49:12 +02:00
impl Drain for LockedBlock {
2020-08-05 06:08:03 +02:00
fn drain ( self ) -> ExecutedBlock {
self . block
}
2016-01-08 19:12:19 +01:00
}
impl SealedBlock {
2020-08-05 06:08:03 +02:00
/// Get the RLP-encoding of the block.
pub fn rlp_bytes ( & self ) -> Bytes {
let mut block_rlp = RlpStream ::new_list ( 3 ) ;
block_rlp . append ( & self . block . header ) ;
2020-12-10 16:42:05 +01:00
SignedTransaction ::rlp_append_list ( & mut block_rlp , & self . block . transactions ) ;
2020-08-05 06:08:03 +02:00
block_rlp . append_list ( & self . block . uncles ) ;
block_rlp . out ( )
}
2016-06-29 21:49:12 +02:00
}
2016-01-10 23:10:06 +01:00
2016-06-29 21:49:12 +02:00
impl Drain for SealedBlock {
2020-08-05 06:08:03 +02:00
fn drain ( self ) -> ExecutedBlock {
self . block
}
2016-01-08 19:12:19 +01:00
}
2020-12-02 11:31:11 +01:00
// t_nb 8.0 Enact the block given by block header, transactions and uncles
2019-03-26 23:31:52 +01:00
pub ( crate ) fn enact (
2020-08-05 06:08:03 +02:00
header : Header ,
transactions : Vec < SignedTransaction > ,
uncles : Vec < Header > ,
2020-07-29 10:36:15 +02:00
engine : & dyn EthEngine ,
2020-08-05 06:08:03 +02:00
tracing : bool ,
db : StateDB ,
parent : & Header ,
last_hashes : Arc < LastHashes > ,
factories : Factories ,
is_epoch_begin : bool ,
2020-07-29 10:36:15 +02:00
ancestry : & mut dyn Iterator < Item = ExtendedHeader > ,
2016-06-18 20:26:44 +02:00
) -> Result < LockedBlock , Error > {
2020-08-05 06:08:03 +02:00
// For trace log
let trace_state = if log_enabled! ( target : " enact " , ::log ::Level ::Trace ) {
Some ( State ::from_existing (
db . boxed_clone ( ) ,
parent . state_root ( ) . clone ( ) ,
engine . account_start_nonce ( parent . number ( ) + 1 ) ,
factories . clone ( ) ,
) ? )
} else {
None
} ;
2020-12-02 11:31:11 +01:00
// t_nb 8.1 Created new OpenBlock
2020-08-05 06:08:03 +02:00
let mut b = OpenBlock ::new (
engine ,
factories ,
tracing ,
db ,
parent ,
last_hashes ,
// Engine such as Clique will calculate author from extra_data.
// this is only important for executing contracts as the 'executive_author'.
engine . executive_author ( & header ) ? ,
( 3141562. into ( ) , 31415620. into ( ) ) ,
vec! [ ] ,
is_epoch_begin ,
ancestry ,
) ? ;
if let Some ( ref s ) = trace_state {
let env = b . env_info ( ) ;
let root = s . root ( ) ;
let author_balance = s . balance ( & env . author ) ? ;
trace! ( target : " enact " , " num={}, root={}, author={}, author_balance={} \n " ,
2019-03-26 23:31:52 +01:00
b . block . header . number ( ) , root , env . author , author_balance ) ;
2020-08-05 06:08:03 +02:00
}
2019-03-26 23:31:52 +01:00
2020-12-02 11:31:11 +01:00
// t_nb 8.2 transfer all field from current header to OpenBlock header that we created
2020-08-05 06:08:03 +02:00
b . populate_from ( & header ) ;
2020-12-02 11:31:11 +01:00
// t_nb 8.3 execute transactions one by one
2020-08-05 06:08:03 +02:00
b . push_transactions ( transactions ) ? ;
2016-10-03 23:29:46 +02:00
2020-12-02 11:31:11 +01:00
// t_nb 8.4 Push uncles to OpenBlock and check if we have more then max uncles
2020-08-05 06:08:03 +02:00
for u in uncles {
b . push_uncle ( u ) ? ;
}
2017-07-13 09:48:00 +02:00
2020-12-02 11:31:11 +01:00
// t_nb 8.5 close block
2020-08-05 06:08:03 +02:00
b . close_and_lock ( )
2016-01-14 19:03:48 +01:00
}
2020-12-09 12:43:32 +01:00
/// t_nb 8.0 Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
2016-06-18 20:26:44 +02:00
pub fn enact_verified (
2020-08-05 06:08:03 +02:00
block : PreverifiedBlock ,
2020-07-29 10:36:15 +02:00
engine : & dyn EthEngine ,
2020-08-05 06:08:03 +02:00
tracing : bool ,
db : StateDB ,
parent : & Header ,
last_hashes : Arc < LastHashes > ,
factories : Factories ,
is_epoch_begin : bool ,
2020-07-29 10:36:15 +02:00
ancestry : & mut dyn Iterator < Item = ExtendedHeader > ,
2016-06-18 20:26:44 +02:00
) -> Result < LockedBlock , Error > {
2020-08-05 06:08:03 +02:00
enact (
block . header ,
block . transactions ,
block . uncles ,
engine ,
tracing ,
db ,
parent ,
last_hashes ,
factories ,
is_epoch_begin ,
ancestry ,
)
2016-01-17 23:07:58 +01:00
}
2016-01-31 10:52:07 +01:00
#[ cfg(test) ]
mod tests {
2020-08-05 06:08:03 +02:00
use super ::* ;
use engines ::EthEngine ;
use error ::Error ;
use ethereum_types ::Address ;
use factory ::Factories ;
use state_db ::StateDB ;
use std ::sync ::Arc ;
use test_helpers ::get_temp_state_db ;
use types ::{ header ::Header , transaction ::SignedTransaction , view , views ::BlockView } ;
use verification ::queue ::kind ::blocks ::Unverified ;
use vm ::LastHashes ;
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
fn enact_bytes (
block_bytes : Vec < u8 > ,
2020-07-29 10:36:15 +02:00
engine : & dyn EthEngine ,
2020-08-05 06:08:03 +02:00
tracing : bool ,
db : StateDB ,
parent : & Header ,
last_hashes : Arc < LastHashes > ,
factories : Factories ,
) -> Result < LockedBlock , Error > {
let block = Unverified ::from_rlp ( block_bytes ) ? ;
let header = block . header ;
let transactions : Result < Vec < _ > , Error > = block
. transactions
. into_iter ( )
. map ( SignedTransaction ::new )
. map ( | r | r . map_err ( Into ::into ) )
. collect ( ) ;
let transactions = transactions ? ;
{
if ::log ::max_level ( ) > = ::log ::Level ::Trace {
let s = State ::from_existing (
db . boxed_clone ( ) ,
parent . state_root ( ) . clone ( ) ,
engine . account_start_nonce ( parent . number ( ) + 1 ) ,
factories . clone ( ) ,
) ? ;
trace! ( target : " enact " , " num={}, root={}, author={}, author_balance={} \n " ,
2017-07-13 09:48:00 +02:00
header . number ( ) , s . root ( ) , header . author ( ) , s . balance ( & header . author ( ) ) ? ) ;
2020-08-05 06:08:03 +02:00
}
}
let mut b = OpenBlock ::new (
engine ,
factories ,
tracing ,
db ,
parent ,
last_hashes ,
2021-03-12 10:12:42 +01:00
Address ::default ( ) ,
2020-08-05 06:08:03 +02:00
( 3141562. into ( ) , 31415620. into ( ) ) ,
vec! [ ] ,
false ,
None ,
) ? ;
b . populate_from ( & header ) ;
b . push_transactions ( transactions ) ? ;
for u in block . uncles {
b . push_uncle ( u ) ? ;
}
b . close_and_lock ( )
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
fn enact_and_seal (
block_bytes : Vec < u8 > ,
2020-07-29 10:36:15 +02:00
engine : & dyn EthEngine ,
2020-08-05 06:08:03 +02:00
tracing : bool ,
db : StateDB ,
parent : & Header ,
last_hashes : Arc < LastHashes > ,
factories : Factories ,
) -> Result < SealedBlock , Error > {
let header = Unverified ::from_rlp ( block_bytes . clone ( ) ) ? . header ;
Ok ( enact_bytes (
block_bytes ,
engine ,
tracing ,
db ,
parent ,
last_hashes ,
factories ,
) ?
. seal ( engine , header . seal ( ) . to_vec ( ) ) ? )
}
#[ test ]
fn open_block ( ) {
use spec ::* ;
let spec = Spec ::new_test ( ) ;
let genesis_header = spec . genesis_header ( ) ;
let db = spec
. ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) )
. unwrap ( ) ;
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
let b = OpenBlock ::new (
& * spec . engine ,
Default ::default ( ) ,
false ,
db ,
& genesis_header ,
last_hashes ,
Address ::zero ( ) ,
( 3141562. into ( ) , 31415620. into ( ) ) ,
vec! [ ] ,
false ,
None ,
)
. unwrap ( ) ;
let b = b . close_and_lock ( ) . unwrap ( ) ;
let _ = b . seal ( & * spec . engine , vec! [ ] ) ;
}
#[ test ]
fn enact_block ( ) {
use spec ::* ;
let spec = Spec ::new_test ( ) ;
let engine = & * spec . engine ;
let genesis_header = spec . genesis_header ( ) ;
let db = spec
. ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) )
. unwrap ( ) ;
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
let b = OpenBlock ::new (
engine ,
Default ::default ( ) ,
false ,
db ,
& genesis_header ,
last_hashes . clone ( ) ,
Address ::zero ( ) ,
( 3141562. into ( ) , 31415620. into ( ) ) ,
vec! [ ] ,
false ,
None ,
)
. unwrap ( )
. close_and_lock ( )
. unwrap ( )
. seal ( engine , vec! [ ] )
. unwrap ( ) ;
let orig_bytes = b . rlp_bytes ( ) ;
let orig_db = b . drain ( ) . state . drop ( ) . 1 ;
let db = spec
. ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) )
. unwrap ( ) ;
let e = enact_and_seal (
orig_bytes . clone ( ) ,
engine ,
false ,
db ,
& genesis_header ,
last_hashes ,
Default ::default ( ) ,
)
. unwrap ( ) ;
assert_eq! ( e . rlp_bytes ( ) , orig_bytes ) ;
let db = e . drain ( ) . state . drop ( ) . 1 ;
assert_eq! ( orig_db . journal_db ( ) . keys ( ) , db . journal_db ( ) . keys ( ) ) ;
assert! (
orig_db
. journal_db ( )
. keys ( )
. iter ( )
. filter ( | k | orig_db . journal_db ( ) . get ( k . 0 ) ! = db . journal_db ( ) . get ( k . 0 ) )
. next ( )
= = None
) ;
}
#[ test ]
fn enact_block_with_uncle ( ) {
use spec ::* ;
let spec = Spec ::new_test ( ) ;
let engine = & * spec . engine ;
let genesis_header = spec . genesis_header ( ) ;
let db = spec
. ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) )
. unwrap ( ) ;
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
let mut open_block = OpenBlock ::new (
engine ,
Default ::default ( ) ,
false ,
db ,
& genesis_header ,
last_hashes . clone ( ) ,
Address ::zero ( ) ,
( 3141562. into ( ) , 31415620. into ( ) ) ,
vec! [ ] ,
false ,
None ,
)
. unwrap ( ) ;
let mut uncle1_header = Header ::new ( ) ;
uncle1_header . set_extra_data ( b " uncle1 " . to_vec ( ) ) ;
let mut uncle2_header = Header ::new ( ) ;
uncle2_header . set_extra_data ( b " uncle2 " . to_vec ( ) ) ;
open_block . push_uncle ( uncle1_header ) . unwrap ( ) ;
open_block . push_uncle ( uncle2_header ) . unwrap ( ) ;
let b = open_block
. close_and_lock ( )
. unwrap ( )
. seal ( engine , vec! [ ] )
. unwrap ( ) ;
let orig_bytes = b . rlp_bytes ( ) ;
let orig_db = b . drain ( ) . state . drop ( ) . 1 ;
let db = spec
. ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) )
. unwrap ( ) ;
let e = enact_and_seal (
orig_bytes . clone ( ) ,
engine ,
false ,
db ,
& genesis_header ,
last_hashes ,
Default ::default ( ) ,
)
. unwrap ( ) ;
let bytes = e . rlp_bytes ( ) ;
assert_eq! ( bytes , orig_bytes ) ;
let uncles = view! ( BlockView , & bytes ) . uncles ( ) ;
assert_eq! ( uncles [ 1 ] . extra_data ( ) , b " uncle2 " ) ;
let db = e . drain ( ) . state . drop ( ) . 1 ;
assert_eq! ( orig_db . journal_db ( ) . keys ( ) , db . journal_db ( ) . keys ( ) ) ;
assert! (
orig_db
. journal_db ( )
. keys ( )
. iter ( )
. filter ( | k | orig_db . journal_db ( ) . get ( k . 0 ) ! = db . journal_db ( ) . get ( k . 0 ) )
. next ( )
= = None
) ;
}
2016-02-02 15:29:53 +01:00
}