openethereum/ethcore/src/block.rs

864 lines
27 KiB
Rust
Raw Normal View History

// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-02-05 13:40:41 +01:00
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// 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.
// Parity is distributed in the hope that it will be useful,
// 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
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
2016-02-02 15:29:53 +01:00
//! Blockchain block.
use std::cmp;
use std::sync::Arc;
use std::collections::HashSet;
2017-08-31 11:53:26 +02:00
use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
use triehash::ordered_trie_root;
use rlp::{UntrustedRlp, RlpStream, Encodable, Decodable, DecoderError};
use ethereum_types::{H256, U256, Address, Bloom};
use bytes::Bytes;
use unexpected::{Mismatch, OutOfBounds};
use vm::{EnvInfo, LastHashes};
use engines::EthEngine;
use error::{Error, BlockError};
use factory::Factories;
use header::{Header, Seal};
use receipt::{Receipt, TransactionOutcome};
use state::State;
use state_db::StateDB;
use trace::FlatTrace;
use transaction::{UnverifiedTransaction, SignedTransaction, Error as TransactionError};
use verification::PreverifiedBlock;
use views::BlockView;
2016-01-08 19:12:19 +01:00
/// A block, encoded as it is on the block chain.
2016-07-11 18:31:18 +02:00
#[derive(Default, Debug, Clone, PartialEq)]
2016-01-08 19:12:19 +01:00
pub struct Block {
/// The header of this block.
pub header: Header,
/// The transactions in this block.
pub transactions: Vec<UnverifiedTransaction>,
/// The uncles of this block.
pub uncles: Vec<Header>,
}
2016-01-08 19:12:19 +01:00
impl Block {
/// Returns true if the given bytes form a valid encoding of a block in RLP.
pub fn is_good(b: &[u8]) -> bool {
UntrustedRlp::new(b).as_val::<Block>().is_ok()
}
Snapshot creation and restoration (#1679) * to_rlp takes self by-reference * clean up some derefs * out-of-order insertion for blockchain * implement block rebuilder without verification * group block chunk header into struct * block rebuilder does verification * integrate snapshot service with client service; flesh out implementation more * initial implementation of snapshot service * remove snapshottaker trait * snapshot writer trait with packed and loose implementations * write chunks using "snapshotwriter" in service * have snapshot taking use snapshotwriter * implement snapshot readers * back up client dbs when replacing * use snapshot reader in snapshot service * describe offset format * use new get_db_path in parity, allow some errors in service * blockchain formatting * implement parity snapshot * implement snapshot restore * force blocks to be submitted in order * fix bug loading block hashes in packed reader * fix seal field loading * fix uncle hash computation * fix a few bugs * store genesis state in db. reverse block chunk order in packed writer * allow out-of-order import for blocks * bring restoration types together * only snapshot the last 30000 blocks * restore into overlaydb instead of journaldb * commit version to database * use memorydbs and commit directly * fix trie test compilation * fix failing tests * sha3_null_rlp, not H256::zero * move overlaydb to ref_overlaydb, add new overlaydb without on-disk rc * port archivedb to new overlaydb * add deletion mode tests for overlaydb * use new overlaydb, check state root at end * share chain info between state and block snapshotting * create blocks snapshot using blockchain directly * allow snapshot from arbitrary block, remove panickers from snapshot creation * begin test framework * blockchain chunking test * implement stateproducer::tick * state snapshot test * create block and state chunks concurrently, better restoration informant * fix tests * add deletion mode tests for overlaydb * address comments * more tests * Fix up tests. * remove a few printlns * add a little more documentation to `commit` * fix tests * fix ref_overlaydb test names * snapshot command skeleton * revert ref_overlaydb renaming * reimplement snapshot commands * fix many errors * everything but inject * get ethcore compiling * get snapshot tests passing again * instrument snapshot commands again * fix fallout from other changes, mark snapshots as experimental * optimize injection patterns * do two injections * fix up tests * take snapshots from 1000 blocks efore * address minor comments * fix a few io crate related errors * clarify names about total difficulty [ci skip]
2016-08-05 17:00:46 +02:00
/// Get the RLP-encoding of the block with or without the seal.
pub fn rlp_bytes(&self, seal: Seal) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
self.header.stream_rlp(&mut block_rlp, seal);
block_rlp.append_list(&self.transactions);
block_rlp.append_list(&self.uncles);
block_rlp.out()
}
}
2016-01-08 19:12:19 +01:00
impl Decodable for Block {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
if rlp.as_raw().len() != rlp.payload_info()?.total() {
return Err(DecoderError::RlpIsTooBig);
}
if rlp.item_count()? != 3 {
return Err(DecoderError::RlpIncorrectListLen);
}
Ok(Block {
header: rlp.val_at(0)?,
transactions: rlp.list_at(1)?,
uncles: rlp.list_at(2)?,
})
}
}
2016-01-10 14:05:39 +01:00
/// An internal type for a block's common elements.
2016-03-22 13:05:18 +01:00
#[derive(Clone)]
pub struct ExecutedBlock {
header: Header,
transactions: Vec<SignedTransaction>,
uncles: Vec<Header>,
receipts: Vec<Receipt>,
transactions_set: HashSet<H256>,
state: State<StateDB>,
traces: Option<Vec<Vec<FlatTrace>>>,
last_hashes: Arc<LastHashes>,
2016-01-08 19:12:19 +01:00
}
/// A set of references to `ExecutedBlock` fields that are publicly accessible.
2016-01-10 17:11:46 +01:00
pub struct BlockRefMut<'a> {
/// Block header.
pub header: &'a mut Header,
/// Block transactions.
pub transactions: &'a [SignedTransaction],
/// Block uncles.
pub uncles: &'a [Header],
/// Transaction receipts.
pub receipts: &'a [Receipt],
/// State.
pub state: &'a mut State<StateDB>,
/// Traces.
pub traces: &'a mut Option<Vec<Vec<FlatTrace>>>,
2016-01-10 17:11:46 +01:00
}
impl<'a> BlockRefMut<'a> {
/// Add traces if tracing is enabled.
pub fn push_traces(&mut self, tracer: ::trace::ExecutiveTracer) {
use trace::Tracer;
if let Some(ref mut traces) = self.traces.as_mut() {
traces.push(tracer.drain())
}
}
}
2016-03-24 23:03:22 +01:00
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible.
pub struct BlockRef<'a> {
/// Block header.
pub header: &'a Header,
/// Block transactions.
pub transactions: &'a [SignedTransaction],
2016-03-24 23:03:22 +01:00
/// Block uncles.
pub uncles: &'a [Header],
2016-03-24 23:03:22 +01:00
/// Transaction receipts.
pub receipts: &'a [Receipt],
2016-03-24 23:03:22 +01:00
/// State.
pub state: &'a State<StateDB>,
2016-03-24 23:03:22 +01:00
/// Traces.
pub traces: &'a Option<Vec<Vec<FlatTrace>>>,
2016-03-24 23:03:22 +01:00
}
impl ExecutedBlock {
2016-01-10 17:11:46 +01: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 {Some(Vec::new())} else {None},
last_hashes: last_hashes,
}
}
2016-01-08 19:12:19 +01:00
2016-01-10 17:11:46 +01:00
/// Get a structure containing individual references to all public fields.
2016-03-24 23:03:22 +01:00
pub fn fields_mut(&mut self) -> BlockRefMut {
BlockRefMut {
header: &mut self.header,
transactions: &self.transactions,
uncles: &self.uncles,
state: &mut self.state,
receipts: &self.receipts,
traces: &mut self.traces,
}
}
2016-03-24 23:03:22 +01:00
/// Get a structure containing individual references to all public fields.
pub fn fields(&self) -> BlockRef {
BlockRef {
header: &self.header,
transactions: &self.transactions,
uncles: &self.uncles,
2016-03-24 23:03:22 +01:00
state: &self.state,
receipts: &self.receipts,
traces: &self.traces,
}
}
/// 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(),
}
}
2016-01-08 19:12:19 +01:00
}
2016-04-06 10:07:24 +02:00
/// Trait for a object that is a `ExecutedBlock`.
2016-01-08 21:33:41 +01:00
pub trait IsBlock {
/// Get the `ExecutedBlock` associated with this object.
fn block(&self) -> &ExecutedBlock;
2016-01-08 19:12:19 +01:00
/// Get the base `Block` object associated with this.
fn to_base(&self) -> Block {
Block {
header: self.header().clone(),
transactions: self.transactions().iter().cloned().map(Into::into).collect(),
uncles: self.uncles().to_vec(),
}
}
2016-01-08 19:12:19 +01:00
/// Get the header associated with this object's block.
fn header(&self) -> &Header { &self.block().header }
2016-01-08 19:12:19 +01:00
/// Get the final state associated with this object's block.
fn state(&self) -> &State<StateDB> { &self.block().state }
2016-01-08 19:12:19 +01:00
/// Get all information on transactions in this block.
fn transactions(&self) -> &[SignedTransaction] { &self.block().transactions }
/// Get all information on receipts in this block.
fn receipts(&self) -> &[Receipt] { &self.block().receipts }
2016-01-10 14:05:39 +01:00
/// Get all information concerning transaction tracing in this block.
fn traces(&self) -> &Option<Vec<Vec<FlatTrace>>> { &self.block().traces }
2016-01-10 14:05:39 +01:00
/// Get all uncles in this block.
fn uncles(&self) -> &[Header] { &self.block().uncles }
/// Get tracing enabled flag for this block.
2017-08-02 17:10:06 +02:00
fn tracing_enabled(&self) -> bool { self.block().traces.is_some() }
2016-01-08 19:12:19 +01:00
}
2016-06-29 21:49:12 +02:00
/// Trait for a object that has a state database.
pub trait Drain {
/// Drop this object and return the underlying database.
fn drain(self) -> StateDB;
2016-06-29 21:49:12 +02:00
}
impl IsBlock for ExecutedBlock {
fn block(&self) -> &ExecutedBlock { self }
2016-01-08 19:12:19 +01:00
}
2016-01-08 22:04:21 +01:00
impl ::parity_machine::LiveBlock for ExecutedBlock {
type Header = Header;
fn header(&self) -> &Header {
&self.header
}
fn uncles(&self) -> &[Header] {
&self.uncles
}
}
impl ::parity_machine::Transactions for ExecutedBlock {
type Transaction = SignedTransaction;
fn transactions(&self) -> &[SignedTransaction] {
&self.transactions
}
}
2016-01-08 19:12:19 +01:00
/// Block that is ready for transactions to be added.
///
2016-02-26 17:27:56 +01:00
/// It's a bit like a Vec<Transaction>, except that whenever a transaction is pushed, we execute it and
2016-01-08 19:12:19 +01:00
/// maintain the system `state()`. We also archive execution receipts in preparation for later block creation.
2016-02-24 11:17:25 +01:00
pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x EthEngine,
2016-01-08 19:12:19 +01:00
}
2016-04-06 10:07:24 +02:00
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
2016-01-08 19:12:19 +01:00
/// and collected the uncles.
///
2016-02-29 14:57:41 +01:00
/// There is no function available to push a transaction.
2016-03-22 13:05:18 +01:00
#[derive(Clone)]
2016-02-29 14:57:41 +01:00
pub struct ClosedBlock {
block: ExecutedBlock,
2016-01-10 14:05:39 +01:00
uncle_bytes: Bytes,
unclosed_state: State<StateDB>,
}
2016-04-06 10:07:24 +02: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 {
block: ExecutedBlock,
uncle_bytes: Bytes,
2016-01-08 19:12:19 +01:00
}
/// A block that has a valid seal.
///
2016-04-06 10:07:24 +02:00
/// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`.
2016-01-08 19:12:19 +01:00
pub struct SealedBlock {
block: ExecutedBlock,
2016-01-10 14:05:39 +01:00
uncle_bytes: Bytes,
2016-01-08 19:12:19 +01:00
}
2016-02-24 11:17:25 +01:00
impl<'x> OpenBlock<'x> {
2016-04-06 10:07:24 +02:00
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(
engine: &'x EthEngine,
factories: Factories,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
author: Address,
2016-06-23 14:29:16 +02:00
gas_range_target: (U256, U256),
extra_data: Bytes,
is_epoch_begin: bool,
) -> Result<Self, Error> {
let number = parent.number() + 1;
let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?;
2016-01-08 19:12:19 +01:00
let mut r = OpenBlock {
block: ExecutedBlock::new(state, last_hashes, tracing),
2016-01-08 19:12:19 +01:00
engine: engine,
2016-01-08 22:04:21 +01:00
};
2016-01-08 19:12:19 +01:00
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_now(parent.timestamp());
r.block.header.set_extra_data(extra_data);
r.block.header.note_dirty();
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);
engine.machine().populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target);
engine.populate_from_parent(&mut r.block.header, parent);
engine.machine().on_new_block(&mut r.block)?;
engine.on_new_block(&mut r.block, is_epoch_begin)?;
Ok(r)
2016-01-08 19:12:19 +01:00
}
2016-01-10 14:05:39 +01:00
/// Alter the author for the block.
pub fn set_author(&mut self, author: Address) { self.block.header.set_author(author); }
2016-01-10 14:05:39 +01:00
/// Alter the timestamp of the block.
pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); }
2016-01-15 23:32:17 +01:00
/// Alter the difficulty for the block.
pub fn set_difficulty(&mut self, a: U256) { self.block.header.set_difficulty(a); }
2016-01-15 23:32:17 +01:00
/// Alter the gas limit for the block.
pub fn set_gas_limit(&mut self, a: U256) { self.block.header.set_gas_limit(a); }
2016-01-15 23:32:17 +01:00
/// Alter the gas limit for the block.
pub fn set_gas_used(&mut self, a: U256) { self.block.header.set_gas_used(a); }
2016-01-15 23:32:17 +01:00
/// Alter the uncles hash the block.
pub fn set_uncles_hash(&mut self, h: H256) { self.block.header.set_uncles_hash(h); }
/// Alter transactions root for the block.
pub fn set_transactions_root(&mut self, h: H256) { self.block.header.set_transactions_root(h); }
/// Alter the receipts root for the block.
pub fn set_receipts_root(&mut self, h: H256) { self.block.header.set_receipts_root(h); }
2016-01-10 14:05:39 +01:00
/// Alter the extra_data for the block.
pub fn set_extra_data(&mut self, extra_data: Bytes) -> Result<(), BlockError> {
if extra_data.len() > self.engine.maximum_extra_data_size() {
Err(BlockError::ExtraDataOutOfBounds(OutOfBounds{min: None, max: Some(self.engine.maximum_extra_data_size()), found: extra_data.len()}))
2016-01-10 14:05:39 +01:00
} else {
self.block.header.set_extra_data(extra_data);
2016-01-10 14:05:39 +01:00
Ok(())
}
}
/// Add an uncle to the block, if possible.
///
/// 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,
}));
2016-01-10 14:05:39 +01:00
}
// TODO: check number
// TODO: check not a direct ancestor (use last_hashes for that)
self.block.uncles.push(valid_uncle_header);
2016-01-10 14:05:39 +01:00
Ok(())
}
2016-01-08 22:04:21 +01:00
/// Get the environment info concerning this block.
pub fn env_info(&self) -> EnvInfo {
self.block.env_info()
2016-01-08 22:04:21 +01:00
}
2016-01-10 14:05:39 +01:00
/// Push a transaction into the block.
///
/// If valid, it will be executed, and archived together with the receipt.
2016-02-04 17:23:53 +01:00
pub fn push_transaction(&mut self, t: SignedTransaction, h: Option<H256>) -> Result<&Receipt, Error> {
2016-03-24 23:03:22 +01:00
if self.block.transactions_set.contains(&t.hash()) {
return Err(From::from(TransactionError::AlreadyImported));
}
2016-01-08 22:04:21 +01:00
let env_info = self.env_info();
2016-01-15 23:32:17 +01:00
// info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine.machine(), &t, self.block.traces.is_some()) {
Ok(outcome) => {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.transactions.push(t.into());
let t = outcome.trace;
self.block.traces.as_mut().map(|traces| traces.push(t));
self.block.receipts.push(outcome.receipt);
Ok(self.block.receipts.last().expect("receipt just pushed; qed"))
2016-01-08 19:12:19 +01:00
}
2016-01-11 17:37:22 +01:00
Err(x) => Err(From::from(x))
2016-01-08 19:12:19 +01:00
}
}
/// Push transactions onto the block.
pub fn push_transactions(&mut self, transactions: &[SignedTransaction]) -> Result<(), Error> {
push_transactions(self, transactions)
}
/// Populate self from a header.
pub fn populate_from(&mut self, header: &Header) {
self.set_difficulty(*header.difficulty());
self.set_gas_limit(*header.gas_limit());
self.set_timestamp(header.timestamp());
self.set_author(header.author().clone());
self.set_extra_data(header.extra_data().clone()).unwrap_or_else(|e| warn!("Couldn't set extradata: {}. Ignoring.", e));
self.set_uncles_hash(header.uncles_hash().clone());
self.set_transactions_root(header.transactions_root().clone());
}
/// Turn this into a `ClosedBlock`.
2016-02-29 14:57:41 +01:00
pub fn close(self) -> ClosedBlock {
2016-01-09 22:45:27 +01:00
let mut s = self;
let unclosed_state = s.block.state.clone();
if let Err(e) = s.engine.on_close_block(&mut s.block) {
warn!("Encountered error on closing the block: {}", e);
}
2017-08-31 11:53:26 +02:00
if let Err(e) = s.block.state.commit() {
warn!("Encountered error on state commit: {}", e);
}
2018-02-16 20:24:16 +01:00
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
s.block.header.set_state_root(s.block.state.root().clone());
2018-02-16 20:24:16 +01:00
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 = &b | &r.log_bloom; b})); //TODO: use |= operator
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
2016-01-09 22:45:27 +01:00
2016-02-29 14:57:41 +01:00
ClosedBlock {
block: s.block,
2016-02-29 14:57:41 +01:00
uncle_bytes: uncle_bytes,
unclosed_state: unclosed_state,
}
}
/// Turn this into a `LockedBlock`.
pub fn close_and_lock(self) -> LockedBlock {
let mut s = self;
if let Err(e) = s.engine.on_close_block(&mut s.block) {
warn!("Encountered error on closing the block: {}", e);
}
if let Err(e) = s.block.state.commit() {
warn!("Encountered error on state commit: {}", e);
}
if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP {
2018-02-16 20:24:16 +01:00
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
}
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
2017-08-31 11:53:26 +02:00
if s.block.header.uncles_hash().is_zero() || s.block.header.uncles_hash() == &KECCAK_EMPTY_LIST_RLP {
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 {
2018-02-16 20:24:16 +01:00
s.block.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes())));
}
s.block.header.set_state_root(s.block.state.root().clone());
s.block.header.set_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
LockedBlock {
block: s.block,
uncle_bytes: uncle_bytes,
}
}
#[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
}
2016-02-24 11:17:25 +01:00
impl<'x> IsBlock for OpenBlock<'x> {
fn block(&self) -> &ExecutedBlock { &self.block }
2016-01-08 19:12:19 +01:00
}
2016-02-29 14:57:41 +01:00
impl<'x> IsBlock for ClosedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
2016-01-10 14:05:39 +01:00
}
impl<'x> IsBlock for LockedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
}
2016-02-29 14:57:41 +01:00
impl ClosedBlock {
2016-01-08 19:12:19 +01:00
/// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
2016-01-08 19:12:19 +01:00
/// Turn this into a `LockedBlock`, unable to be reopened again.
2016-09-29 12:46:04 +02:00
pub fn lock(self) -> LockedBlock {
LockedBlock {
block: self.block,
uncle_bytes: self.uncle_bytes,
}
}
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
pub fn reopen(self, engine: &EthEngine) -> OpenBlock {
// 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,
}
}
}
impl LockedBlock {
/// Get the hash of the header without seal arguments.
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
2016-01-10 14:05:39 +01: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.
pub fn seal(self, engine: &EthEngine, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
Aura: Broadcast empty step messages instead of creating empty blocks (#7605) * aura: broadcast empty step message instead of sealing empty block * aura: add empty_step messages to seal * aura: include parent_hash in empty step message * aura: verify received empty step messages * aura: verify empty step messages in block * aura: fix dead lock on empty_steps * aura: fix EmptyStep Encodable * aura: take number of empty steps into account in chain score * aura: use empty step signers for finality * aura: add empty "empty step" messages to seal when reading from spec * aura: fix EmptyStep rlp encoding * aura: use Vec<u8> instead of Bytes * aura: fix block empty step verification * Update .gitlab-ci.yml fix lint * aura: fix accumulation of empty step signatures for finality * aura: include empty steps in seal signature * aura: configurable max number of empty steps * engine: pass block header to seal_fields method This is necessary to make the number of seal fields dynamic, e.g. activating a transition on a certain block number that changes the seal. * aura: add transition to enable empty step messages * aura: clear old empty step messages on verify_block_external * aura: ignore empty step messages from the future * aura: report skipped primaries when empty steps are not enabled * aura: fix tests * aura: report misbehavior * aura: add tests for rolling finality with multiple signatures * engine: fix validator set test In this test the block validation wasn't failing because the block was in the future (expected failure) but was instead failing because the author of the block isn't the expected authority. Since we added reporting of blocks produced by the wrong authority this test started failing. * aura: reward all the authors of empty step messages * aura: fix reward attribution for new blocks * aura: add tests for empty steps broadcasting and inclusion in blocks * aura: reduce size of empty step messages in seal * aura: add test for empty step inclusion in blocks * aura: add test for rewarding of empty steps * aura: add test for empty steps validation * aura: fix rlp encoding of sealed empty step * aura: fix grumbles
2018-02-15 01:39:29 +01:00
let expected_seal_fields = engine.seal_fields(self.header());
2016-01-10 14:05:39 +01:00
let mut s = self;
Aura: Broadcast empty step messages instead of creating empty blocks (#7605) * aura: broadcast empty step message instead of sealing empty block * aura: add empty_step messages to seal * aura: include parent_hash in empty step message * aura: verify received empty step messages * aura: verify empty step messages in block * aura: fix dead lock on empty_steps * aura: fix EmptyStep Encodable * aura: take number of empty steps into account in chain score * aura: use empty step signers for finality * aura: add empty "empty step" messages to seal when reading from spec * aura: fix EmptyStep rlp encoding * aura: use Vec<u8> instead of Bytes * aura: fix block empty step verification * Update .gitlab-ci.yml fix lint * aura: fix accumulation of empty step signatures for finality * aura: include empty steps in seal signature * aura: configurable max number of empty steps * engine: pass block header to seal_fields method This is necessary to make the number of seal fields dynamic, e.g. activating a transition on a certain block number that changes the seal. * aura: add transition to enable empty step messages * aura: clear old empty step messages on verify_block_external * aura: ignore empty step messages from the future * aura: report skipped primaries when empty steps are not enabled * aura: fix tests * aura: report misbehavior * aura: add tests for rolling finality with multiple signatures * engine: fix validator set test In this test the block validation wasn't failing because the block was in the future (expected failure) but was instead failing because the author of the block isn't the expected authority. Since we added reporting of blocks produced by the wrong authority this test started failing. * aura: reward all the authors of empty step messages * aura: fix reward attribution for new blocks * aura: add tests for empty steps broadcasting and inclusion in blocks * aura: reduce size of empty step messages in seal * aura: add test for empty step inclusion in blocks * aura: add test for rewarding of empty steps * aura: add test for empty steps validation * aura: fix rlp encoding of sealed empty step * aura: fix grumbles
2018-02-15 01:39:29 +01:00
if seal.len() != expected_seal_fields {
return Err(BlockError::InvalidSealArity(
Mismatch { expected: expected_seal_fields, found: seal.len() }));
2016-01-10 14:05:39 +01:00
}
s.block.header.set_seal(seal);
2016-02-29 14:57:41 +01:00
Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
2016-01-10 14:05:39 +01:00
}
2016-01-08 19:12:19 +01:00
/// 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.
2017-04-11 17:07:04 +02:00
pub fn try_seal(
self,
engine: &EthEngine,
2017-04-11 17:07:04 +02:00
seal: Vec<Bytes>,
) -> Result<SealedBlock, (Error, LockedBlock)> {
let mut s = self;
s.block.header.set_seal(seal);
// 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, uncle_bytes: s.uncle_bytes }),
}
}
2017-03-29 19:59:20 +02:00
/// Remove state root from transaction receipts to make them EIP-98 compatible.
pub fn strip_receipts(self) -> LockedBlock {
let mut block = self;
for receipt in &mut block.block.receipts {
receipt.outcome = TransactionOutcome::Unknown;
2017-03-29 19:59:20 +02:00
}
2018-02-16 20:24:16 +01:00
block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes())));
2017-03-29 19:59:20 +02:00
block
}
2016-06-29 21:49:12 +02:00
}
2016-06-29 21:49:12 +02:00
impl Drain for LockedBlock {
2016-01-14 19:03:48 +01:00
/// Drop this object and return the underlieing database.
fn drain(self) -> StateDB {
self.block.state.drop().1
}
2016-01-08 19:12:19 +01:00
}
impl SealedBlock {
2016-01-10 14:05:39 +01:00
/// Get the RLP-encoding of the block.
pub fn rlp_bytes(&self) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
self.block.header.stream_rlp(&mut block_rlp, Seal::With);
block_rlp.append_list(&self.block.transactions);
2016-01-10 14:05:39 +01:00
block_rlp.append_raw(&self.uncle_bytes, 1);
block_rlp.out()
2016-01-10 23:10:06 +01:00
}
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 {
2016-01-10 23:10:06 +01:00
/// Drop this object and return the underlieing database.
fn drain(self) -> StateDB {
self.block.state.drop().1
}
2016-01-08 19:12:19 +01:00
}
impl IsBlock for SealedBlock {
fn block(&self) -> &ExecutedBlock { &self.block }
2016-01-08 19:12:19 +01:00
}
2016-01-17 23:07:58 +01:00
/// Enact the block given by block header, transactions and uncles
pub fn enact(
header: &Header,
transactions: &[SignedTransaction],
uncles: &[Header],
engine: &EthEngine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
is_epoch_begin: bool,
) -> Result<LockedBlock, Error> {
2016-01-15 22:55:04 +01:00
{
2016-02-05 01:49:06 +01:00
if ::log::max_log_level() >= ::log::LogLevel::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",
header.number(), s.root(), header.author(), s.balance(&header.author())?);
2016-02-05 01:49:06 +01:00
}
2016-01-15 22:55:04 +01:00
}
2016-01-15 23:32:17 +01:00
let mut b = OpenBlock::new(
engine,
factories,
tracing,
db,
parent,
last_hashes,
Address::new(),
(3141562.into(), 31415620.into()),
vec![],
is_epoch_begin,
)?;
b.populate_from(header);
b.push_transactions(transactions)?;
for u in uncles {
b.push_uncle(u.clone())?;
}
Ok(b.close_and_lock())
2016-01-14 19:03:48 +01:00
}
#[inline]
#[cfg(not(feature = "slow-blocks"))]
fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction]) -> Result<(), Error> {
for t in transactions {
block.push_transaction(t.clone(), None)?;
}
Ok(())
}
#[cfg(feature = "slow-blocks")]
fn push_transactions(block: &mut OpenBlock, transactions: &[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();
block.push_transaction(t.clone(), 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, block.header().number(), hash);
}
debug!(target: "tx", "Transaction {:?} took: {} ms", hash, took_ms);
}
Ok(())
2016-01-17 23:07:58 +01:00
}
// TODO [ToDr] Pass `PreverifiedBlock` by move, this will avoid unecessary allocation
2016-01-17 23:07:58 +01:00
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
pub fn enact_verified(
block: &PreverifiedBlock,
engine: &EthEngine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
is_epoch_begin: bool,
) -> Result<LockedBlock, Error> {
2016-01-17 23:07:58 +01:00
let view = BlockView::new(&block.bytes);
enact(
&block.header,
&block.transactions,
&view.uncles(),
engine,
tracing,
db,
parent,
last_hashes,
factories,
is_epoch_begin,
)
2016-01-17 23:07:58 +01:00
}
#[cfg(test)]
mod tests {
use tests::helpers::*;
use super::*;
use engines::EthEngine;
use vm::LastHashes;
use error::Error;
use header::Header;
use factory::Factories;
use state_db::StateDB;
use views::BlockView;
use ethereum_types::Address;
use std::sync::Arc;
use transaction::SignedTransaction;
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
fn enact_bytes(
block_bytes: &[u8],
engine: &EthEngine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<LockedBlock, Error> {
let block = BlockView::new(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_log_level() >= ::log::LogLevel::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",
header.number(), s.root(), header.author(), s.balance(&header.author())?);
}
}
let mut b = OpenBlock::new(
engine,
factories,
tracing,
db,
parent,
last_hashes,
Address::new(),
(3141562.into(), 31415620.into()),
vec![],
false,
)?;
b.populate_from(&header);
b.push_transactions(&transactions)?;
for u in &block.uncles() {
b.push_uncle(u.clone())?;
}
Ok(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: &[u8],
engine: &EthEngine,
tracing: bool,
db: StateDB,
parent: &Header,
last_hashes: Arc<LastHashes>,
factories: Factories,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)?.seal(engine, header.seal())?)
}
#[test]
fn open_block() {
use spec::*;
let spec = Spec::new_test();
let genesis_header = spec.genesis_header();
2017-04-06 19:26:17 +02:00
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).unwrap();
let b = b.close_and_lock();
let _ = b.seal(&*spec.engine, vec![]);
}
2016-01-10 23:10:06 +01:00
#[test]
fn enact_block() {
use spec::*;
let spec = Spec::new_test();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
2017-04-06 19:26:17 +02:00
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).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
2017-04-06 19:26:17 +02:00
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
let db = e.drain();
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-03-14 18:20:24 +01:00
#[test]
fn enact_block_with_uncle() {
2016-03-15 14:35:45 +01:00
use spec::*;
let spec = Spec::new_test();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
2016-03-15 14:35:45 +01:00
2017-04-06 19:26:17 +02:00
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).unwrap();
2016-03-15 14:35:45 +01:00
let mut uncle1_header = Header::new();
2017-06-28 16:41:08 +02:00
uncle1_header.set_extra_data(b"uncle1".to_vec());
2016-03-15 14:35:45 +01:00
let mut uncle2_header = Header::new();
2017-06-28 16:41:08 +02:00
uncle2_header.set_extra_data(b"uncle2".to_vec());
2016-03-15 14:35:45 +01:00
open_block.push_uncle(uncle1_header).unwrap();
open_block.push_uncle(uncle2_header).unwrap();
let b = open_block.close_and_lock().seal(engine, vec![]).unwrap();
2016-03-15 14:35:45 +01:00
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
2017-04-06 19:26:17 +02:00
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
2016-03-15 14:35:45 +01:00
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);
let uncles = BlockView::new(&bytes).uncles();
assert_eq!(uncles[1].extra_data(), b"uncle2");
2016-03-15 14:35:45 +01:00
let db = e.drain();
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-03-14 18:20:24 +01:00
}
2016-02-02 15:29:53 +01:00
}