Remove RefCell from Header (#8227)
* Cache RLP and header hashes. * Refactor header - WiP * Avoid decoding laster header. * Pre-compute hashes for Sealed/Locked block. * Use accrue bloom. Closes ##8241
This commit is contained in:
parent
d477670cb9
commit
9f775a7673
@ -17,8 +17,7 @@
|
|||||||
//! Tests for the on-demand service.
|
//! Tests for the on-demand service.
|
||||||
|
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use ethcore::encoded;
|
use ethcore::header::Header;
|
||||||
use ethcore::header::{Header, Seal};
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use network::{PeerId, NodeId};
|
use network::{PeerId, NodeId};
|
||||||
use net::*;
|
use net::*;
|
||||||
@ -148,7 +147,7 @@ fn single_request() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let header = Header::default();
|
let header = Header::default();
|
||||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
let encoded = header.encoded();
|
||||||
|
|
||||||
let recv = harness.service.request_raw(
|
let recv = harness.service.request_raw(
|
||||||
&Context::NoOp,
|
&Context::NoOp,
|
||||||
@ -209,7 +208,7 @@ fn reassign() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let header = Header::default();
|
let header = Header::default();
|
||||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
let encoded = header.encoded();
|
||||||
|
|
||||||
let recv = harness.service.request_raw(
|
let recv = harness.service.request_raw(
|
||||||
&Context::NoOp,
|
&Context::NoOp,
|
||||||
@ -257,7 +256,7 @@ fn partial_response() {
|
|||||||
let mut hdr = Header::default();
|
let mut hdr = Header::default();
|
||||||
hdr.set_number(num);
|
hdr.set_number(num);
|
||||||
|
|
||||||
let encoded = encoded::Header::new(hdr.rlp(Seal::With));
|
let encoded = hdr.encoded();
|
||||||
(hdr, encoded)
|
(hdr, encoded)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -316,7 +315,7 @@ fn part_bad_part_good() {
|
|||||||
let mut hdr = Header::default();
|
let mut hdr = Header::default();
|
||||||
hdr.set_number(num);
|
hdr.set_number(num);
|
||||||
|
|
||||||
let encoded = encoded::Header::new(hdr.rlp(Seal::With));
|
let encoded = hdr.encoded();
|
||||||
(hdr, encoded)
|
(hdr, encoded)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -413,7 +412,7 @@ fn back_references() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let header = Header::default();
|
let header = Header::default();
|
||||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
let encoded = header.encoded();
|
||||||
|
|
||||||
let recv = harness.service.request_raw(
|
let recv = harness.service.request_raw(
|
||||||
&Context::NoOp,
|
&Context::NoOp,
|
||||||
@ -470,7 +469,7 @@ fn fill_from_cache() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let header = Header::default();
|
let header = Header::default();
|
||||||
let encoded = encoded::Header::new(header.rlp(Seal::With));
|
let encoded = header.encoded();
|
||||||
|
|
||||||
let recv = harness.service.request_raw(
|
let recv = harness.service.request_raw(
|
||||||
&Context::NoOp,
|
&Context::NoOp,
|
||||||
|
@ -31,7 +31,7 @@ use vm::{EnvInfo, LastHashes};
|
|||||||
use engines::EthEngine;
|
use engines::EthEngine;
|
||||||
use error::{Error, BlockError};
|
use error::{Error, BlockError};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
use header::{Header, Seal};
|
use header::Header;
|
||||||
use receipt::{Receipt, TransactionOutcome};
|
use receipt::{Receipt, TransactionOutcome};
|
||||||
use state::State;
|
use state::State;
|
||||||
use state_db::StateDB;
|
use state_db::StateDB;
|
||||||
@ -57,10 +57,10 @@ impl Block {
|
|||||||
UntrustedRlp::new(b).as_val::<Block>().is_ok()
|
UntrustedRlp::new(b).as_val::<Block>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the RLP-encoding of the block with or without the seal.
|
/// Get the RLP-encoding of the block with the seal.
|
||||||
pub fn rlp_bytes(&self, seal: Seal) -> Bytes {
|
pub fn rlp_bytes(&self) -> Bytes {
|
||||||
let mut block_rlp = RlpStream::new_list(3);
|
let mut block_rlp = RlpStream::new_list(3);
|
||||||
self.header.stream_rlp(&mut block_rlp, seal);
|
block_rlp.append(&self.header);
|
||||||
block_rlp.append_list(&self.transactions);
|
block_rlp.append_list(&self.transactions);
|
||||||
block_rlp.append_list(&self.uncles);
|
block_rlp.append_list(&self.uncles);
|
||||||
block_rlp.out()
|
block_rlp.out()
|
||||||
@ -269,7 +269,6 @@ impl<'x> OpenBlock<'x> {
|
|||||||
r.block.header.set_author(author);
|
r.block.header.set_author(author);
|
||||||
r.block.header.set_timestamp_now(parent.timestamp());
|
r.block.header.set_timestamp_now(parent.timestamp());
|
||||||
r.block.header.set_extra_data(extra_data);
|
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_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);
|
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
||||||
@ -284,7 +283,9 @@ impl<'x> OpenBlock<'x> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Alter the timestamp of the block.
|
/// Alter the timestamp of the block.
|
||||||
pub fn set_timestamp(&mut self, timestamp: u64) { self.block.header.set_timestamp(timestamp); }
|
pub fn set_timestamp(&mut self, timestamp: u64) {
|
||||||
|
self.block.header.set_timestamp(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes block gas limit.
|
/// Removes block gas limit.
|
||||||
pub fn remove_gas_limit(&mut self) {
|
pub fn remove_gas_limit(&mut self) {
|
||||||
@ -374,8 +375,11 @@ impl<'x> OpenBlock<'x> {
|
|||||||
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
||||||
s.block.header.set_state_root(s.block.state.root().clone());
|
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_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_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
|
||||||
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
|
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));
|
||||||
|
|
||||||
ClosedBlock {
|
ClosedBlock {
|
||||||
block: s.block,
|
block: s.block,
|
||||||
@ -395,6 +399,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
if let Err(e) = s.block.state.commit() {
|
if let Err(e) = s.block.state.commit() {
|
||||||
warn!("Encountered error on state commit: {}", e);
|
warn!("Encountered error on state commit: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &KECCAK_NULL_RLP {
|
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())));
|
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes())));
|
||||||
}
|
}
|
||||||
@ -407,8 +412,11 @@ impl<'x> OpenBlock<'x> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.block.header.set_state_root(s.block.state.root().clone());
|
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_log_bloom(s.block.receipts.iter().fold(Bloom::zero(), |mut b, r| {
|
||||||
s.block.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
|
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));
|
||||||
|
|
||||||
LockedBlock {
|
LockedBlock {
|
||||||
block: s.block,
|
block: s.block,
|
||||||
@ -435,7 +443,7 @@ impl<'x> IsBlock for LockedBlock {
|
|||||||
|
|
||||||
impl ClosedBlock {
|
impl ClosedBlock {
|
||||||
/// Get the hash of the header without seal arguments.
|
/// Get the hash of the header without seal arguments.
|
||||||
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
|
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||||
|
|
||||||
/// Turn this into a `LockedBlock`, unable to be reopened again.
|
/// Turn this into a `LockedBlock`, unable to be reopened again.
|
||||||
pub fn lock(self) -> LockedBlock {
|
pub fn lock(self) -> LockedBlock {
|
||||||
@ -459,7 +467,7 @@ impl ClosedBlock {
|
|||||||
|
|
||||||
impl LockedBlock {
|
impl LockedBlock {
|
||||||
/// Get the hash of the header without seal arguments.
|
/// Get the hash of the header without seal arguments.
|
||||||
pub fn hash(&self) -> H256 { self.header().rlp_keccak(Seal::Without) }
|
pub fn hash(&self) -> H256 { self.header().bare_hash() }
|
||||||
|
|
||||||
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
||||||
///
|
///
|
||||||
@ -472,6 +480,7 @@ impl LockedBlock {
|
|||||||
Mismatch { expected: expected_seal_fields, found: seal.len() }));
|
Mismatch { expected: expected_seal_fields, found: seal.len() }));
|
||||||
}
|
}
|
||||||
s.block.header.set_seal(seal);
|
s.block.header.set_seal(seal);
|
||||||
|
s.block.header.compute_hash();
|
||||||
Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
|
Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,6 +494,7 @@ impl LockedBlock {
|
|||||||
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
||||||
let mut s = self;
|
let mut s = self;
|
||||||
s.block.header.set_seal(seal);
|
s.block.header.set_seal(seal);
|
||||||
|
s.block.header.compute_hash();
|
||||||
|
|
||||||
// TODO: passing state context to avoid engines owning it?
|
// TODO: passing state context to avoid engines owning it?
|
||||||
match engine.verify_local_seal(&s.block.header) {
|
match engine.verify_local_seal(&s.block.header) {
|
||||||
@ -492,16 +502,6 @@ impl LockedBlock {
|
|||||||
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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;
|
|
||||||
}
|
|
||||||
block.block.header.set_receipts_root(ordered_trie_root(block.block.receipts.iter().map(|r| r.rlp_bytes())));
|
|
||||||
block
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drain for LockedBlock {
|
impl Drain for LockedBlock {
|
||||||
@ -515,7 +515,7 @@ impl SealedBlock {
|
|||||||
/// Get the RLP-encoding of the block.
|
/// Get the RLP-encoding of the block.
|
||||||
pub fn rlp_bytes(&self) -> Bytes {
|
pub fn rlp_bytes(&self) -> Bytes {
|
||||||
let mut block_rlp = RlpStream::new_list(3);
|
let mut block_rlp = RlpStream::new_list(3);
|
||||||
self.block.header.stream_rlp(&mut block_rlp, Seal::With);
|
block_rlp.append(&self.block.header);
|
||||||
block_rlp.append_list(&self.block.transactions);
|
block_rlp.append_list(&self.block.transactions);
|
||||||
block_rlp.append_raw(&self.uncle_bytes, 1);
|
block_rlp.append_raw(&self.uncle_bytes, 1);
|
||||||
block_rlp.out()
|
block_rlp.out()
|
||||||
@ -545,6 +545,7 @@ pub fn enact(
|
|||||||
last_hashes: Arc<LastHashes>,
|
last_hashes: Arc<LastHashes>,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
is_epoch_begin: bool,
|
is_epoch_begin: bool,
|
||||||
|
strip_receipts: bool,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> Result<LockedBlock, Error> {
|
||||||
{
|
{
|
||||||
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
||||||
@ -574,6 +575,12 @@ pub fn enact(
|
|||||||
b.push_uncle(u.clone())?;
|
b.push_uncle(u.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strip_receipts {
|
||||||
|
for receipt in &mut b.block.receipts {
|
||||||
|
receipt.outcome = TransactionOutcome::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(b.close_and_lock())
|
Ok(b.close_and_lock())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,6 +623,8 @@ pub fn enact_verified(
|
|||||||
last_hashes: Arc<LastHashes>,
|
last_hashes: Arc<LastHashes>,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
is_epoch_begin: bool,
|
is_epoch_begin: bool,
|
||||||
|
// Remove state root from transaction receipts to make them EIP-98 compatible.
|
||||||
|
strip_receipts: bool,
|
||||||
) -> Result<LockedBlock, Error> {
|
) -> Result<LockedBlock, Error> {
|
||||||
let view = BlockView::new(&block.bytes);
|
let view = BlockView::new(&block.bytes);
|
||||||
|
|
||||||
@ -630,6 +639,7 @@ pub fn enact_verified(
|
|||||||
last_hashes,
|
last_hashes,
|
||||||
factories,
|
factories,
|
||||||
is_epoch_begin,
|
is_epoch_begin,
|
||||||
|
strip_receipts,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
use bytes::Bytes;
|
use encoded;
|
||||||
use header::BlockNumber;
|
use header::{Header, BlockNumber};
|
||||||
|
|
||||||
/// Contains information on a best block that is specific to the consensus engine.
|
/// Contains information on a best block that is specific to the consensus engine.
|
||||||
///
|
///
|
||||||
@ -24,18 +24,13 @@ use header::BlockNumber;
|
|||||||
/// combined difficulty (usually the block with the highest block number).
|
/// combined difficulty (usually the block with the highest block number).
|
||||||
///
|
///
|
||||||
/// Sometimes refered as 'latest block'.
|
/// Sometimes refered as 'latest block'.
|
||||||
#[derive(Default)]
|
|
||||||
pub struct BestBlock {
|
pub struct BestBlock {
|
||||||
/// Best block hash.
|
/// Best block decoded header.
|
||||||
pub hash: H256,
|
pub header: Header,
|
||||||
/// Best block number.
|
/// Best block uncompressed bytes.
|
||||||
pub number: BlockNumber,
|
pub block: encoded::Block,
|
||||||
/// Best block timestamp.
|
|
||||||
pub timestamp: u64,
|
|
||||||
/// Best block total difficulty.
|
/// Best block total difficulty.
|
||||||
pub total_difficulty: U256,
|
pub total_difficulty: U256,
|
||||||
/// Best block uncompressed bytes
|
|
||||||
pub block: Bytes,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best ancient block info. If the blockchain has a gap this keeps track of where it starts.
|
/// Best ancient block info. If the blockchain has a gap this keeps track of where it starts.
|
||||||
|
@ -90,11 +90,6 @@ pub trait BlockProvider {
|
|||||||
/// Get receipts of block with given hash.
|
/// Get receipts of block with given hash.
|
||||||
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
|
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts>;
|
||||||
|
|
||||||
/// Get the partial-header of a block.
|
|
||||||
fn block_header(&self, hash: &H256) -> Option<Header> {
|
|
||||||
self.block_header_data(hash).map(|header| header.decode())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the header RLP of a block.
|
/// Get the header RLP of a block.
|
||||||
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
|
fn block_header_data(&self, hash: &H256) -> Option<encoded::Header>;
|
||||||
|
|
||||||
@ -115,7 +110,7 @@ pub trait BlockProvider {
|
|||||||
|
|
||||||
/// Get the number of given block's hash.
|
/// Get the number of given block's hash.
|
||||||
fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
|
fn block_number(&self, hash: &H256) -> Option<BlockNumber> {
|
||||||
self.block_details(hash).map(|details| details.number)
|
self.block_header_data(hash).map(|header| header.number())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get transaction with given transaction hash.
|
/// Get transaction with given transaction hash.
|
||||||
@ -144,8 +139,8 @@ pub trait BlockProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the header of the genesis block.
|
/// Returns the header of the genesis block.
|
||||||
fn genesis_header(&self) -> Header {
|
fn genesis_header(&self) -> encoded::Header {
|
||||||
self.block_header(&self.genesis_hash())
|
self.block_header_data(&self.genesis_hash())
|
||||||
.expect("Genesis header always stored; qed")
|
.expect("Genesis header always stored; qed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,8 +188,8 @@ pub struct BlockChain {
|
|||||||
first_block: Option<H256>,
|
first_block: Option<H256>,
|
||||||
|
|
||||||
// block cache
|
// block cache
|
||||||
block_headers: RwLock<HashMap<H256, Bytes>>,
|
block_headers: RwLock<HashMap<H256, encoded::Header>>,
|
||||||
block_bodies: RwLock<HashMap<H256, Bytes>>,
|
block_bodies: RwLock<HashMap<H256, encoded::Body>>,
|
||||||
|
|
||||||
// extra caches
|
// extra caches
|
||||||
block_details: RwLock<HashMap<H256, BlockDetails>>,
|
block_details: RwLock<HashMap<H256, BlockDetails>>,
|
||||||
@ -251,17 +246,15 @@ impl BlockProvider for BlockChain {
|
|||||||
{
|
{
|
||||||
let read = self.block_headers.read();
|
let read = self.block_headers.read();
|
||||||
if let Some(v) = read.get(hash) {
|
if let Some(v) = read.get(hash) {
|
||||||
return Some(encoded::Header::new(v.clone()));
|
return Some(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's the best block
|
// Check if it's the best block
|
||||||
{
|
{
|
||||||
let best_block = self.best_block.read();
|
let best_block = self.best_block.read();
|
||||||
if &best_block.hash == hash {
|
if &best_block.header.hash() == hash {
|
||||||
return Some(encoded::Header::new(
|
return Some(best_block.header.encoded())
|
||||||
Rlp::new(&best_block.block).at(0).as_raw().to_vec()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,12 +262,12 @@ impl BlockProvider for BlockChain {
|
|||||||
let b = self.db.get(db::COL_HEADERS, hash)
|
let b = self.db.get(db::COL_HEADERS, hash)
|
||||||
.expect("Low level database error. Some issue with disk?")?;
|
.expect("Low level database error. Some issue with disk?")?;
|
||||||
|
|
||||||
let bytes = decompress(&b, blocks_swapper()).into_vec();
|
let header = encoded::Header::new(decompress(&b, blocks_swapper()).into_vec());
|
||||||
let mut write = self.block_headers.write();
|
let mut write = self.block_headers.write();
|
||||||
write.insert(*hash, bytes.clone());
|
write.insert(*hash, header.clone());
|
||||||
|
|
||||||
self.cache_man.lock().note_used(CacheId::BlockHeader(*hash));
|
self.cache_man.lock().note_used(CacheId::BlockHeader(*hash));
|
||||||
Some(encoded::Header::new(bytes))
|
Some(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get block body data
|
/// Get block body data
|
||||||
@ -283,15 +276,15 @@ impl BlockProvider for BlockChain {
|
|||||||
{
|
{
|
||||||
let read = self.block_bodies.read();
|
let read = self.block_bodies.read();
|
||||||
if let Some(v) = read.get(hash) {
|
if let Some(v) = read.get(hash) {
|
||||||
return Some(encoded::Body::new(v.clone()));
|
return Some(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's the best block
|
// Check if it's the best block
|
||||||
{
|
{
|
||||||
let best_block = self.best_block.read();
|
let best_block = self.best_block.read();
|
||||||
if &best_block.hash == hash {
|
if &best_block.header.hash() == hash {
|
||||||
return Some(encoded::Body::new(Self::block_to_body(&best_block.block)));
|
return Some(encoded::Body::new(Self::block_to_body(best_block.block.rlp().as_raw())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,12 +292,12 @@ impl BlockProvider for BlockChain {
|
|||||||
let b = self.db.get(db::COL_BODIES, hash)
|
let b = self.db.get(db::COL_BODIES, hash)
|
||||||
.expect("Low level database error. Some issue with disk?")?;
|
.expect("Low level database error. Some issue with disk?")?;
|
||||||
|
|
||||||
let bytes = decompress(&b, blocks_swapper()).into_vec();
|
let body = encoded::Body::new(decompress(&b, blocks_swapper()).into_vec());
|
||||||
let mut write = self.block_bodies.write();
|
let mut write = self.block_bodies.write();
|
||||||
write.insert(*hash, bytes.clone());
|
write.insert(*hash, body.clone());
|
||||||
|
|
||||||
self.cache_man.lock().note_used(CacheId::BlockBody(*hash));
|
self.cache_man.lock().note_used(CacheId::BlockBody(*hash));
|
||||||
Some(encoded::Body::new(bytes))
|
Some(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the familial details concerning a block.
|
/// Get the familial details concerning a block.
|
||||||
@ -476,7 +469,12 @@ impl BlockChain {
|
|||||||
elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX,
|
elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX,
|
||||||
},
|
},
|
||||||
first_block: None,
|
first_block: None,
|
||||||
best_block: RwLock::new(BestBlock::default()),
|
best_block: RwLock::new(BestBlock {
|
||||||
|
// BestBlock will be overwritten anyway.
|
||||||
|
header: Default::default(),
|
||||||
|
total_difficulty: Default::default(),
|
||||||
|
block: encoded::Block::new(genesis.into()),
|
||||||
|
}),
|
||||||
best_ancient_block: RwLock::new(None),
|
best_ancient_block: RwLock::new(None),
|
||||||
block_headers: RwLock::new(HashMap::new()),
|
block_headers: RwLock::new(HashMap::new()),
|
||||||
block_bodies: RwLock::new(HashMap::new()),
|
block_bodies: RwLock::new(HashMap::new()),
|
||||||
@ -527,11 +525,21 @@ impl BlockChain {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Fetch best block details
|
// Fetch best block details
|
||||||
let best_block_number = bc.block_number(&best_block_hash).unwrap();
|
|
||||||
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
let best_block_total_difficulty = bc.block_details(&best_block_hash).unwrap().total_difficulty;
|
||||||
let best_block_rlp = bc.block(&best_block_hash).unwrap().into_inner();
|
let best_block_rlp = bc.block(&best_block_hash).unwrap();
|
||||||
let best_block_timestamp = BlockView::new(&best_block_rlp).header().timestamp();
|
|
||||||
|
|
||||||
|
// and write them
|
||||||
|
let mut best_block = bc.best_block.write();
|
||||||
|
*best_block = BestBlock {
|
||||||
|
total_difficulty: best_block_total_difficulty,
|
||||||
|
header: best_block_rlp.decode_header(),
|
||||||
|
block: best_block_rlp,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let best_block_number = bc.best_block.read().header.number();
|
||||||
|
// Fetch first and best ancient block details
|
||||||
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec());
|
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec());
|
||||||
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
|
||||||
let best_ancient_number;
|
let best_ancient_number;
|
||||||
@ -574,15 +582,6 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// and write them
|
// and write them
|
||||||
let mut best_block = bc.best_block.write();
|
|
||||||
*best_block = BestBlock {
|
|
||||||
number: best_block_number,
|
|
||||||
total_difficulty: best_block_total_difficulty,
|
|
||||||
hash: best_block_hash,
|
|
||||||
timestamp: best_block_timestamp,
|
|
||||||
block: best_block_rlp,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let (Some(hash), Some(number)) = (best_ancient, best_ancient_number) {
|
if let (Some(hash), Some(number)) = (best_ancient, best_ancient_number) {
|
||||||
let mut best_ancient_block = bc.best_ancient_block.write();
|
let mut best_ancient_block = bc.best_ancient_block.write();
|
||||||
*best_ancient_block = Some(BestAncientBlock {
|
*best_ancient_block = Some(BestAncientBlock {
|
||||||
@ -737,7 +736,6 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info,
|
info: info,
|
||||||
timestamp: header.timestamp(),
|
|
||||||
block: bytes
|
block: bytes
|
||||||
}, is_best);
|
}, is_best);
|
||||||
|
|
||||||
@ -786,7 +784,6 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info,
|
info: info,
|
||||||
timestamp: header.timestamp(),
|
|
||||||
block: bytes,
|
block: bytes,
|
||||||
}, is_best);
|
}, is_best);
|
||||||
true
|
true
|
||||||
@ -936,7 +933,6 @@ impl BlockChain {
|
|||||||
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
blocks_blooms: self.prepare_block_blooms_update(bytes, &info),
|
||||||
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
transactions_addresses: self.prepare_transaction_addresses_update(bytes, &info),
|
||||||
info: info.clone(),
|
info: info.clone(),
|
||||||
timestamp: header.timestamp(),
|
|
||||||
block: bytes,
|
block: bytes,
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
@ -1028,12 +1024,11 @@ impl BlockChain {
|
|||||||
let mut best_block = self.pending_best_block.write();
|
let mut best_block = self.pending_best_block.write();
|
||||||
if is_best && update.info.location != BlockLocation::Branch {
|
if is_best && update.info.location != BlockLocation::Branch {
|
||||||
batch.put(db::COL_EXTRA, b"best", &update.info.hash);
|
batch.put(db::COL_EXTRA, b"best", &update.info.hash);
|
||||||
|
let block = encoded::Block::new(update.block.to_vec());
|
||||||
*best_block = Some(BestBlock {
|
*best_block = Some(BestBlock {
|
||||||
hash: update.info.hash,
|
|
||||||
number: update.info.number,
|
|
||||||
total_difficulty: update.info.total_difficulty,
|
total_difficulty: update.info.total_difficulty,
|
||||||
timestamp: update.timestamp,
|
header: block.decode_header(),
|
||||||
block: update.block.to_vec(),
|
block,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1105,8 +1100,9 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given a block's `parent`, find every block header which represents a valid possible uncle.
|
/// Given a block's `parent`, find every block header which represents a valid possible uncle.
|
||||||
pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option<Vec<Header>> {
|
pub fn find_uncle_headers(&self, parent: &H256, uncle_generations: usize) -> Option<Vec<encoded::Header>> {
|
||||||
self.find_uncle_hashes(parent, uncle_generations).map(|v| v.into_iter().filter_map(|h| self.block_header(&h)).collect())
|
self.find_uncle_hashes(parent, uncle_generations)
|
||||||
|
.map(|v| v.into_iter().filter_map(|h| self.block_header_data(&h)).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a block's `parent`, find every block hash which represents a valid possible uncle.
|
/// Given a block's `parent`, find every block hash which represents a valid possible uncle.
|
||||||
@ -1307,17 +1303,17 @@ impl BlockChain {
|
|||||||
|
|
||||||
/// Get best block hash.
|
/// Get best block hash.
|
||||||
pub fn best_block_hash(&self) -> H256 {
|
pub fn best_block_hash(&self) -> H256 {
|
||||||
self.best_block.read().hash
|
self.best_block.read().header.hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block number.
|
/// Get best block number.
|
||||||
pub fn best_block_number(&self) -> BlockNumber {
|
pub fn best_block_number(&self) -> BlockNumber {
|
||||||
self.best_block.read().number
|
self.best_block.read().header.number()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block timestamp.
|
/// Get best block timestamp.
|
||||||
pub fn best_block_timestamp(&self) -> u64 {
|
pub fn best_block_timestamp(&self) -> u64 {
|
||||||
self.best_block.read().timestamp
|
self.best_block.read().header.timestamp()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block total difficulty.
|
/// Get best block total difficulty.
|
||||||
@ -1326,10 +1322,8 @@ impl BlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get best block header
|
/// Get best block header
|
||||||
pub fn best_block_header(&self) -> encoded::Header {
|
pub fn best_block_header(&self) -> Header {
|
||||||
let block = self.best_block.read();
|
self.best_block.read().header.clone()
|
||||||
let raw = BlockView::new(&block.block).header_view().rlp().as_raw().to_vec();
|
|
||||||
encoded::Header::new(raw)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current cache size.
|
/// Get current cache size.
|
||||||
@ -1402,12 +1396,12 @@ impl BlockChain {
|
|||||||
let best_block = self.best_block.read();
|
let best_block = self.best_block.read();
|
||||||
let best_ancient_block = self.best_ancient_block.read();
|
let best_ancient_block = self.best_ancient_block.read();
|
||||||
BlockChainInfo {
|
BlockChainInfo {
|
||||||
total_difficulty: best_block.total_difficulty.clone(),
|
total_difficulty: best_block.total_difficulty,
|
||||||
pending_total_difficulty: best_block.total_difficulty.clone(),
|
pending_total_difficulty: best_block.total_difficulty,
|
||||||
genesis_hash: self.genesis_hash(),
|
genesis_hash: self.genesis_hash(),
|
||||||
best_block_hash: best_block.hash,
|
best_block_hash: best_block.header.hash(),
|
||||||
best_block_number: best_block.number,
|
best_block_number: best_block.header.number(),
|
||||||
best_block_timestamp: best_block.timestamp,
|
best_block_timestamp: best_block.header.timestamp(),
|
||||||
first_block_hash: self.first_block(),
|
first_block_hash: self.first_block(),
|
||||||
first_block_number: From::from(self.first_block_number()),
|
first_block_number: From::from(self.first_block_number()),
|
||||||
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash),
|
ancient_block_hash: best_ancient_block.as_ref().map(|b| b.hash),
|
||||||
@ -1539,7 +1533,11 @@ mod tests {
|
|||||||
let b4b = b3a.add_block_with_difficulty(9);
|
let b4b = b3a.add_block_with_difficulty(9);
|
||||||
let b5b = b4a.add_block_with_difficulty(9);
|
let b5b = b4a.add_block_with_difficulty(9);
|
||||||
|
|
||||||
let uncle_headers = vec![b4b.last().header(), b3b.last().header(), b2b.last().header()];
|
let uncle_headers = vec![
|
||||||
|
b4b.last().header().encoded(),
|
||||||
|
b3b.last().header().encoded(),
|
||||||
|
b2b.last().header().encoded(),
|
||||||
|
];
|
||||||
let b4a_hash = b4a.last().hash();
|
let b4a_hash = b4a.last().hash();
|
||||||
|
|
||||||
let generator = BlockGenerator::new(
|
let generator = BlockGenerator::new(
|
||||||
@ -1862,10 +1860,10 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(bc.best_block_number(), 2999);
|
assert_eq!(bc.best_block_number(), 2999);
|
||||||
let best_hash = bc.best_block_hash();
|
let best_hash = bc.best_block_hash();
|
||||||
let mut block_header = bc.block_header(&best_hash);
|
let mut block_header = bc.block_header_data(&best_hash);
|
||||||
|
|
||||||
while !block_header.is_none() {
|
while !block_header.is_none() {
|
||||||
block_header = bc.block_header(block_header.unwrap().parent_hash());
|
block_header = bc.block_header_data(&block_header.unwrap().parent_hash());
|
||||||
}
|
}
|
||||||
assert!(bc.cache_size().blocks > 1024 * 1024);
|
assert!(bc.cache_size().blocks > 1024 * 1024);
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ use blooms::{BloomGroup, GroupPosition};
|
|||||||
pub struct ExtrasUpdate<'a> {
|
pub struct ExtrasUpdate<'a> {
|
||||||
/// Block info.
|
/// Block info.
|
||||||
pub info: BlockInfo,
|
pub info: BlockInfo,
|
||||||
/// Block timestamp.
|
|
||||||
pub timestamp: u64,
|
|
||||||
/// Current block uncompressed rlp bytes
|
/// Current block uncompressed rlp bytes
|
||||||
pub block: &'a [u8],
|
pub block: &'a [u8],
|
||||||
/// Modified block hashes.
|
/// Modified block hashes.
|
||||||
|
@ -362,16 +362,15 @@ impl Importer {
|
|||||||
let engine = &*self.engine;
|
let engine = &*self.engine;
|
||||||
let header = &block.header;
|
let header = &block.header;
|
||||||
|
|
||||||
let chain = client.chain.read();
|
|
||||||
// Check the block isn't so old we won't be able to enact it.
|
// Check the block isn't so old we won't be able to enact it.
|
||||||
let best_block_number = chain.best_block_number();
|
let best_block_number = client.chain.read().best_block_number();
|
||||||
if client.pruning_info().earliest_state > header.number() {
|
if client.pruning_info().earliest_state > header.number() {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
warn!(target: "client", "Block import failed for #{} ({})\nBlock is ancient (current best block: #{}).", header.number(), header.hash(), best_block_number);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if parent is in chain
|
// Check if parent is in chain
|
||||||
let parent = match chain.block_header(header.parent_hash()) {
|
let parent = match client.block_header_decoded(BlockId::Hash(*header.parent_hash())) {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
None => {
|
None => {
|
||||||
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash());
|
warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash());
|
||||||
@ -379,6 +378,7 @@ impl Importer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let chain = client.chain.read();
|
||||||
// Verify Block Family
|
// Verify Block Family
|
||||||
let verify_family_result = self.verifier.verify_block_family(
|
let verify_family_result = self.verifier.verify_block_family(
|
||||||
header,
|
header,
|
||||||
@ -408,6 +408,7 @@ impl Importer {
|
|||||||
let db = client.state_db.read().boxed_clone_canon(header.parent_hash());
|
let db = client.state_db.read().boxed_clone_canon(header.parent_hash());
|
||||||
|
|
||||||
let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some();
|
let is_epoch_begin = chain.epoch_transition(parent.number(), *header.parent_hash()).is_some();
|
||||||
|
let strip_receipts = header.number() < engine.params().validate_receipts_transition;
|
||||||
let enact_result = enact_verified(block,
|
let enact_result = enact_verified(block,
|
||||||
engine,
|
engine,
|
||||||
client.tracedb.read().tracing_enabled(),
|
client.tracedb.read().tracing_enabled(),
|
||||||
@ -416,15 +417,13 @@ impl Importer {
|
|||||||
last_hashes,
|
last_hashes,
|
||||||
client.factories.clone(),
|
client.factories.clone(),
|
||||||
is_epoch_begin,
|
is_epoch_begin,
|
||||||
|
strip_receipts,
|
||||||
);
|
);
|
||||||
let mut locked_block = enact_result.map_err(|e| {
|
|
||||||
|
let locked_block = enact_result.map_err(|e| {
|
||||||
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if header.number() < engine.params().validate_receipts_transition && header.receipts_root() != locked_block.block().header().receipts_root() {
|
|
||||||
locked_block = locked_block.strip_receipts();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Final Verification
|
// Final Verification
|
||||||
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
|
if let Err(e) = self.verifier.verify_block_final(header, locked_block.block().header()) {
|
||||||
warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
warn!(target: "client", "Stage 5 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||||
@ -655,7 +654,7 @@ impl Importer {
|
|||||||
fn check_epoch_end<'a>(&self, header: &'a Header, chain: &BlockChain, client: &Client) {
|
fn check_epoch_end<'a>(&self, header: &'a Header, chain: &BlockChain, client: &Client) {
|
||||||
let is_epoch_end = self.engine.is_epoch_end(
|
let is_epoch_end = self.engine.is_epoch_end(
|
||||||
header,
|
header,
|
||||||
&(|hash| chain.block_header(&hash)),
|
&(|hash| client.block_header_decoded(BlockId::Hash(hash))),
|
||||||
&(|hash| chain.get_pending_transition(hash)), // TODO: limit to current epoch.
|
&(|hash| chain.get_pending_transition(hash)), // TODO: limit to current epoch.
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -724,7 +723,7 @@ impl Client {
|
|||||||
config.history
|
config.history
|
||||||
};
|
};
|
||||||
|
|
||||||
if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(h.state_root())) {
|
if !chain.block_header_data(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(&h.state_root())) {
|
||||||
warn!("State root not found for block #{} ({:x})", chain.best_block_number(), chain.best_block_hash());
|
warn!("State root not found for block #{} ({:x})", chain.best_block_number(), chain.best_block_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1000,7 +999,7 @@ impl Client {
|
|||||||
let header = self.best_block_header();
|
let header = self.best_block_header();
|
||||||
State::from_existing(
|
State::from_existing(
|
||||||
self.state_db.read().boxed_clone_canon(&header.hash()),
|
self.state_db.read().boxed_clone_canon(&header.hash()),
|
||||||
header.state_root(),
|
*header.state_root(),
|
||||||
self.engine.account_start_nonce(header.number()),
|
self.engine.account_start_nonce(header.number()),
|
||||||
self.factories.clone()
|
self.factories.clone()
|
||||||
)
|
)
|
||||||
@ -1260,6 +1259,23 @@ impl Client {
|
|||||||
BlockId::Latest => Some(self.chain.read().best_block_number()),
|
BlockId::Latest => Some(self.chain.read().best_block_number()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve a decoded header given `BlockId`
|
||||||
|
///
|
||||||
|
/// This method optimizes access patterns for latest block header
|
||||||
|
/// to avoid excessive RLP encoding, decoding and hashing.
|
||||||
|
fn block_header_decoded(&self, id: BlockId) -> Option<Header> {
|
||||||
|
match id {
|
||||||
|
BlockId::Latest
|
||||||
|
=> Some(self.chain.read().best_block_header()),
|
||||||
|
BlockId::Hash(ref hash) if hash == &self.chain.read().best_block_hash()
|
||||||
|
=> Some(self.chain.read().best_block_header()),
|
||||||
|
BlockId::Number(number) if number == self.chain.read().best_block_number()
|
||||||
|
=> Some(self.chain.read().best_block_header()),
|
||||||
|
_
|
||||||
|
=> self.block_header(id).map(|h| h.decode()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl snapshot::DatabaseRestore for Client {
|
impl snapshot::DatabaseRestore for Client {
|
||||||
@ -1315,16 +1331,14 @@ impl BlockInfo for Client {
|
|||||||
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
|
Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_header(&self) -> encoded::Header {
|
fn best_block_header(&self) -> Header {
|
||||||
self.chain.read().best_block_header()
|
self.chain.read().best_block_header()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
|
|
||||||
Self::block_hash(&chain, id).and_then(|hash| {
|
Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash))
|
||||||
chain.block(&hash)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
|
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
|
||||||
@ -1360,11 +1374,11 @@ impl CallContract for Client {
|
|||||||
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
|
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
|
||||||
let state_pruned = || CallError::StatePruned.to_string();
|
let state_pruned = || CallError::StatePruned.to_string();
|
||||||
let state = &mut self.state_at(block_id).ok_or_else(&state_pruned)?;
|
let state = &mut self.state_at(block_id).ok_or_else(&state_pruned)?;
|
||||||
let header = self.block_header(block_id).ok_or_else(&state_pruned)?;
|
let header = self.block_header_decoded(block_id).ok_or_else(&state_pruned)?;
|
||||||
|
|
||||||
let transaction = self.contract_call_tx(block_id, address, data);
|
let transaction = self.contract_call_tx(block_id, address, data);
|
||||||
|
|
||||||
self.call(&transaction, Default::default(), state, &header.decode())
|
self.call(&transaction, Default::default(), state, &header)
|
||||||
.map_err(|e| format!("{:?}", e))
|
.map_err(|e| format!("{:?}", e))
|
||||||
.map(|executed| executed.output)
|
.map(|executed| executed.output)
|
||||||
}
|
}
|
||||||
@ -1918,8 +1932,8 @@ impl BlockChainClient for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
|
||||||
self.block_header(id)
|
self.block_header_decoded(id)
|
||||||
.map(|header| self.engine.extra_info(&header.decode()))
|
.map(|header| self.engine.extra_info(&header))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
||||||
@ -1973,8 +1987,8 @@ impl ReopenBlock for Client {
|
|||||||
|
|
||||||
for h in uncles {
|
for h in uncles {
|
||||||
if !block.uncles().iter().any(|header| header.hash() == h) {
|
if !block.uncles().iter().any(|header| header.hash() == h) {
|
||||||
let uncle = chain.block_header(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
||||||
block.push_uncle(uncle).expect("pushing up to maximum_uncle_count;
|
block.push_uncle(uncle.decode()).expect("pushing up to maximum_uncle_count;
|
||||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||||
so all push_uncle are Ok;
|
so all push_uncle are Ok;
|
||||||
qed");
|
qed");
|
||||||
@ -1991,9 +2005,8 @@ impl PrepareOpenBlock for Client {
|
|||||||
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||||
let engine = &*self.engine;
|
let engine = &*self.engine;
|
||||||
let chain = self.chain.read();
|
let chain = self.chain.read();
|
||||||
let h = chain.best_block_hash();
|
let best_header = chain.best_block_header();
|
||||||
let best_header = &chain.block_header(&h)
|
let h = best_header.hash();
|
||||||
.expect("h is best block hash: so its header must exist: qed");
|
|
||||||
|
|
||||||
let is_epoch_begin = chain.epoch_transition(best_header.number(), h).is_some();
|
let is_epoch_begin = chain.epoch_transition(best_header.number(), h).is_some();
|
||||||
let mut open_block = OpenBlock::new(
|
let mut open_block = OpenBlock::new(
|
||||||
@ -2001,7 +2014,7 @@ impl PrepareOpenBlock for Client {
|
|||||||
self.factories.clone(),
|
self.factories.clone(),
|
||||||
self.tracedb.read().tracing_enabled(),
|
self.tracedb.read().tracing_enabled(),
|
||||||
self.state_db.read().boxed_clone_canon(&h),
|
self.state_db.read().boxed_clone_canon(&h),
|
||||||
best_header,
|
&best_header,
|
||||||
self.build_last_hashes(&h),
|
self.build_last_hashes(&h),
|
||||||
author,
|
author,
|
||||||
gas_range_target,
|
gas_range_target,
|
||||||
@ -2016,7 +2029,7 @@ impl PrepareOpenBlock for Client {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.take(engine.maximum_uncle_count(open_block.header().number()))
|
.take(engine.maximum_uncle_count(open_block.header().number()))
|
||||||
.foreach(|h| {
|
.foreach(|h| {
|
||||||
open_block.push_uncle(h).expect("pushing maximum_uncle_count;
|
open_block.push_uncle(h.decode()).expect("pushing maximum_uncle_count;
|
||||||
open_block was just created;
|
open_block was just created;
|
||||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||||
so all push_uncle are Ok;
|
so all push_uncle are Ok;
|
||||||
|
@ -474,9 +474,10 @@ impl BlockInfo for TestBlockChainClient {
|
|||||||
.map(encoded::Header::new)
|
.map(encoded::Header::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn best_block_header(&self) -> encoded::Header {
|
fn best_block_header(&self) -> Header {
|
||||||
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
||||||
.expect("Best block always has header.")
|
.expect("Best block always has header.")
|
||||||
|
.decode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
||||||
|
@ -121,7 +121,7 @@ pub trait BlockInfo {
|
|||||||
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Get the best block header.
|
/// Get the best block header.
|
||||||
fn best_block_header(&self) -> encoded::Header;
|
fn best_block_header(&self) -> Header;
|
||||||
|
|
||||||
/// Get raw block data by block header hash.
|
/// Get raw block data by block header hash.
|
||||||
fn block(&self, id: BlockId) -> Option<encoded::Block>;
|
fn block(&self, id: BlockId) -> Option<encoded::Block>;
|
||||||
|
@ -201,7 +201,7 @@ mod tests {
|
|||||||
"0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e"
|
"0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e"
|
||||||
);
|
);
|
||||||
// Simulate a misbehaving validator by handling a double proposal.
|
// Simulate a misbehaving validator by handling a double proposal.
|
||||||
let header = client.best_block_header().decode();
|
let header = client.best_block_header();
|
||||||
assert!(client.engine().verify_block_family(&header, &header).is_err());
|
assert!(client.engine().verify_block_family(&header, &header).is_err());
|
||||||
// Seal a block.
|
// Seal a block.
|
||||||
client.engine().step();
|
client.engine().step();
|
||||||
|
@ -20,7 +20,7 @@ use std::sync::{Weak, Arc};
|
|||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
|
|
||||||
use ethereum_types::{H256, U256, Address, Bloom};
|
use ethereum_types::{H256, U256, Address, Bloom};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use memory_cache::MemoryLruCache;
|
use memory_cache::MemoryLruCache;
|
||||||
@ -53,19 +53,19 @@ lazy_static! {
|
|||||||
// only "first" proofs are such.
|
// only "first" proofs are such.
|
||||||
struct StateProof {
|
struct StateProof {
|
||||||
contract_address: Address,
|
contract_address: Address,
|
||||||
header: Mutex<Header>,
|
header: Header,
|
||||||
provider: validator_set::ValidatorSet,
|
provider: validator_set::ValidatorSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
|
impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
|
||||||
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
|
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
|
||||||
prove_initial(&self.provider, self.contract_address, &*self.header.lock(), caller)
|
prove_initial(&self.provider, self.contract_address, &self.header, caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
|
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
|
||||||
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
|
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
|
||||||
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
||||||
if &header != &*self.header.lock(){
|
if &header != &self.header {
|
||||||
return Err("wrong header in proof".into());
|
return Err("wrong header in proof".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
debug!(target: "engine", "signalling transition to fresh contract.");
|
debug!(target: "engine", "signalling transition to fresh contract.");
|
||||||
let state_proof = Arc::new(StateProof {
|
let state_proof = Arc::new(StateProof {
|
||||||
contract_address: self.contract_address,
|
contract_address: self.contract_address,
|
||||||
header: Mutex::new(header.clone()),
|
header: header.clone(),
|
||||||
provider: validator_set::ValidatorSet::default(),
|
provider: validator_set::ValidatorSet::default(),
|
||||||
});
|
});
|
||||||
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
|
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
//! Block header.
|
//! Block header.
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak};
|
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak};
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
@ -28,7 +27,8 @@ use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable};
|
|||||||
pub use types::BlockNumber;
|
pub use types::BlockNumber;
|
||||||
|
|
||||||
/// Semantic boolean for when a seal/signature is included.
|
/// Semantic boolean for when a seal/signature is included.
|
||||||
pub enum Seal {
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Seal {
|
||||||
/// The seal/signature is included.
|
/// The seal/signature is included.
|
||||||
With,
|
With,
|
||||||
/// The seal/signature is not included.
|
/// The seal/signature is not included.
|
||||||
@ -75,14 +75,18 @@ pub struct Header {
|
|||||||
/// Vector of post-RLP-encoded fields.
|
/// Vector of post-RLP-encoded fields.
|
||||||
seal: Vec<Bytes>,
|
seal: Vec<Bytes>,
|
||||||
|
|
||||||
/// The memoized hash of the RLP representation *including* the seal fields.
|
/// Memoized hash of that header and the seal.
|
||||||
hash: RefCell<Option<H256>>,
|
hash: Option<H256>,
|
||||||
/// The memoized hash of the RLP representation *without* the seal fields.
|
|
||||||
bare_hash: RefCell<Option<H256>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Header {
|
impl PartialEq for Header {
|
||||||
fn eq(&self, c: &Header) -> bool {
|
fn eq(&self, c: &Header) -> bool {
|
||||||
|
if let (&Some(ref h1), &Some(ref h2)) = (&self.hash, &c.hash) {
|
||||||
|
if h1 == h2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.parent_hash == c.parent_hash &&
|
self.parent_hash == c.parent_hash &&
|
||||||
self.timestamp == c.timestamp &&
|
self.timestamp == c.timestamp &&
|
||||||
self.number == c.number &&
|
self.number == c.number &&
|
||||||
@ -120,51 +124,57 @@ impl Default for Header {
|
|||||||
|
|
||||||
difficulty: U256::default(),
|
difficulty: U256::default(),
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: RefCell::new(None),
|
hash: None,
|
||||||
bare_hash: RefCell::new(None),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
/// Create a new, default-valued, header.
|
/// Create a new, default-valued, header.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self::default() }
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the parent_hash field of the header.
|
/// Get the parent_hash field of the header.
|
||||||
pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
|
pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
|
||||||
|
|
||||||
/// Get the timestamp field of the header.
|
/// Get the timestamp field of the header.
|
||||||
pub fn timestamp(&self) -> u64 { self.timestamp }
|
pub fn timestamp(&self) -> u64 { self.timestamp }
|
||||||
|
|
||||||
/// Get the number field of the header.
|
/// Get the number field of the header.
|
||||||
pub fn number(&self) -> BlockNumber { self.number }
|
pub fn number(&self) -> BlockNumber { self.number }
|
||||||
|
|
||||||
/// Get the author field of the header.
|
/// Get the author field of the header.
|
||||||
pub fn author(&self) -> &Address { &self.author }
|
pub fn author(&self) -> &Address { &self.author }
|
||||||
|
|
||||||
/// Get the extra data field of the header.
|
/// Get the extra data field of the header.
|
||||||
pub fn extra_data(&self) -> &Bytes { &self.extra_data }
|
pub fn extra_data(&self) -> &Bytes { &self.extra_data }
|
||||||
/// Get a mutable reference to extra_data
|
|
||||||
pub fn extra_data_mut(&mut self) -> &mut Bytes { self.note_dirty(); &mut self.extra_data }
|
|
||||||
|
|
||||||
/// Get the state root field of the header.
|
/// Get the state root field of the header.
|
||||||
pub fn state_root(&self) -> &H256 { &self.state_root }
|
pub fn state_root(&self) -> &H256 { &self.state_root }
|
||||||
|
|
||||||
/// Get the receipts root field of the header.
|
/// Get the receipts root field of the header.
|
||||||
pub fn receipts_root(&self) -> &H256 { &self.receipts_root }
|
pub fn receipts_root(&self) -> &H256 { &self.receipts_root }
|
||||||
|
|
||||||
/// Get the log bloom field of the header.
|
/// Get the log bloom field of the header.
|
||||||
pub fn log_bloom(&self) -> &Bloom { &self.log_bloom }
|
pub fn log_bloom(&self) -> &Bloom { &self.log_bloom }
|
||||||
|
|
||||||
/// Get the transactions root field of the header.
|
/// Get the transactions root field of the header.
|
||||||
pub fn transactions_root(&self) -> &H256 { &self.transactions_root }
|
pub fn transactions_root(&self) -> &H256 { &self.transactions_root }
|
||||||
|
|
||||||
/// Get the uncles hash field of the header.
|
/// Get the uncles hash field of the header.
|
||||||
pub fn uncles_hash(&self) -> &H256 { &self.uncles_hash }
|
pub fn uncles_hash(&self) -> &H256 { &self.uncles_hash }
|
||||||
|
|
||||||
/// Get the gas used field of the header.
|
/// Get the gas used field of the header.
|
||||||
pub fn gas_used(&self) -> &U256 { &self.gas_used }
|
pub fn gas_used(&self) -> &U256 { &self.gas_used }
|
||||||
|
|
||||||
/// Get the gas limit field of the header.
|
/// Get the gas limit field of the header.
|
||||||
pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
|
pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
|
||||||
|
|
||||||
/// Get the difficulty field of the header.
|
/// Get the difficulty field of the header.
|
||||||
pub fn difficulty(&self) -> &U256 { &self.difficulty }
|
pub fn difficulty(&self) -> &U256 { &self.difficulty }
|
||||||
|
|
||||||
/// Get the seal field of the header.
|
/// Get the seal field of the header.
|
||||||
pub fn seal(&self) -> &[Bytes] { &self.seal }
|
pub fn seal(&self) -> &[Bytes] { &self.seal }
|
||||||
|
|
||||||
/// Get the seal field with RLP-decoded values as bytes.
|
/// Get the seal field with RLP-decoded values as bytes.
|
||||||
pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result<T, DecoderError> {
|
pub fn decode_seal<'a, T: ::std::iter::FromIterator<&'a [u8]>>(&'a self) -> Result<T, DecoderError> {
|
||||||
self.seal.iter().map(|rlp| {
|
self.seal.iter().map(|rlp| {
|
||||||
@ -172,78 +182,126 @@ impl Header {
|
|||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: seal_at, set_seal_at &c.
|
/// Get a mutable reference to extra_data
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn extra_data_mut(&mut self) -> &mut Bytes {
|
||||||
|
self.hash = None;
|
||||||
|
&mut self.extra_data
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the number field of the header.
|
/// Set the number field of the header.
|
||||||
pub fn set_parent_hash(&mut self, a: H256) { self.parent_hash = a; self.note_dirty(); }
|
pub fn set_parent_hash(&mut self, a: H256) {
|
||||||
|
change_field(&mut self.hash, &mut self.parent_hash, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the uncles hash field of the header.
|
/// Set the uncles hash field of the header.
|
||||||
pub fn set_uncles_hash(&mut self, a: H256) { self.uncles_hash = a; self.note_dirty(); }
|
pub fn set_uncles_hash(&mut self, a: H256) {
|
||||||
|
change_field(&mut self.hash, &mut self.uncles_hash, a);
|
||||||
|
|
||||||
|
}
|
||||||
/// Set the state root field of the header.
|
/// Set the state root field of the header.
|
||||||
pub fn set_state_root(&mut self, a: H256) { self.state_root = a; self.note_dirty(); }
|
pub fn set_state_root(&mut self, a: H256) {
|
||||||
|
change_field(&mut self.hash, &mut self.state_root, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the transactions root field of the header.
|
/// Set the transactions root field of the header.
|
||||||
pub fn set_transactions_root(&mut self, a: H256) { self.transactions_root = a; self.note_dirty() }
|
pub fn set_transactions_root(&mut self, a: H256) {
|
||||||
|
change_field(&mut self.hash, &mut self.transactions_root, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the receipts root field of the header.
|
/// Set the receipts root field of the header.
|
||||||
pub fn set_receipts_root(&mut self, a: H256) { self.receipts_root = a; self.note_dirty() }
|
pub fn set_receipts_root(&mut self, a: H256) {
|
||||||
|
change_field(&mut self.hash, &mut self.receipts_root, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the log bloom field of the header.
|
/// Set the log bloom field of the header.
|
||||||
pub fn set_log_bloom(&mut self, a: Bloom) { self.log_bloom = a; self.note_dirty() }
|
pub fn set_log_bloom(&mut self, a: Bloom) {
|
||||||
|
change_field(&mut self.hash, &mut self.log_bloom, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the timestamp field of the header.
|
/// Set the timestamp field of the header.
|
||||||
pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); }
|
pub fn set_timestamp(&mut self, a: u64) {
|
||||||
|
change_field(&mut self.hash, &mut self.timestamp, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the timestamp field of the header to the current time.
|
/// Set the timestamp field of the header to the current time.
|
||||||
pub fn set_timestamp_now(&mut self, but_later_than: u64) { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default(); self.timestamp = cmp::max(now.as_secs() as u64, but_later_than + 1); self.note_dirty(); }
|
pub fn set_timestamp_now(&mut self, but_later_than: u64) {
|
||||||
|
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default();
|
||||||
|
self.set_timestamp(cmp::max(now.as_secs() as u64, but_later_than + 1));
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the number field of the header.
|
/// Set the number field of the header.
|
||||||
pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); }
|
pub fn set_number(&mut self, a: BlockNumber) {
|
||||||
|
change_field(&mut self.hash, &mut self.number, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the author field of the header.
|
/// Set the author field of the header.
|
||||||
pub fn set_author(&mut self, a: Address) { if a != self.author { self.author = a; self.note_dirty(); } }
|
pub fn set_author(&mut self, a: Address) {
|
||||||
|
change_field(&mut self.hash, &mut self.author, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the extra data field of the header.
|
/// Set the extra data field of the header.
|
||||||
pub fn set_extra_data(&mut self, a: Bytes) { if a != self.extra_data { self.extra_data = a; self.note_dirty(); } }
|
pub fn set_extra_data(&mut self, a: Bytes) {
|
||||||
|
change_field(&mut self.hash, &mut self.extra_data, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the gas used field of the header.
|
/// Set the gas used field of the header.
|
||||||
pub fn set_gas_used(&mut self, a: U256) { self.gas_used = a; self.note_dirty(); }
|
pub fn set_gas_used(&mut self, a: U256) {
|
||||||
|
change_field(&mut self.hash, &mut self.gas_used, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the gas limit field of the header.
|
/// Set the gas limit field of the header.
|
||||||
pub fn set_gas_limit(&mut self, a: U256) { self.gas_limit = a; self.note_dirty(); }
|
pub fn set_gas_limit(&mut self, a: U256) {
|
||||||
|
change_field(&mut self.hash, &mut self.gas_limit, a);
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the difficulty field of the header.
|
/// Set the difficulty field of the header.
|
||||||
pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); }
|
pub fn set_difficulty(&mut self, a: U256) {
|
||||||
/// Set the seal field of the header.
|
change_field(&mut self.hash, &mut self.difficulty, a);
|
||||||
pub fn set_seal(&mut self, a: Vec<Bytes>) { self.seal = a; self.note_dirty(); }
|
}
|
||||||
|
|
||||||
/// Get the hash of this header (keccak of the RLP).
|
/// Set the seal field of the header.
|
||||||
|
pub fn set_seal(&mut self, a: Vec<Bytes>) {
|
||||||
|
change_field(&mut self.hash, &mut self.seal, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get & memoize the hash of this header (keccak of the RLP with seal).
|
||||||
|
pub fn compute_hash(&mut self) -> H256 {
|
||||||
|
let hash = self.hash();
|
||||||
|
self.hash = Some(hash);
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the hash of this header (keccak of the RLP with seal).
|
||||||
pub fn hash(&self) -> H256 {
|
pub fn hash(&self) -> H256 {
|
||||||
let mut hash = self.hash.borrow_mut();
|
self.hash.unwrap_or_else(|| keccak(self.rlp(Seal::With)))
|
||||||
match &mut *hash {
|
|
||||||
&mut Some(ref h) => h.clone(),
|
|
||||||
hash @ &mut None => {
|
|
||||||
let h = self.rlp_keccak(Seal::With);
|
|
||||||
*hash = Some(h.clone());
|
|
||||||
h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the hash of the header excluding the seal
|
/// Get the hash of the header excluding the seal
|
||||||
pub fn bare_hash(&self) -> H256 {
|
pub fn bare_hash(&self) -> H256 {
|
||||||
let mut hash = self.bare_hash.borrow_mut();
|
keccak(self.rlp(Seal::Without))
|
||||||
match &mut *hash {
|
|
||||||
&mut Some(ref h) => h.clone(),
|
|
||||||
hash @ &mut None => {
|
|
||||||
let h = self.rlp_keccak(Seal::Without);
|
|
||||||
*hash = Some(h.clone());
|
|
||||||
h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that some fields have changed. Resets the memoised hash.
|
/// Encode the header, getting a type-safe wrapper around the RLP.
|
||||||
pub fn note_dirty(&self) {
|
pub fn encoded(&self) -> ::encoded::Header {
|
||||||
*self.hash.borrow_mut() = None;
|
::encoded::Header::new(self.rlp(Seal::With))
|
||||||
*self.bare_hash.borrow_mut() = None;
|
}
|
||||||
|
|
||||||
|
/// Get the RLP representation of this Header.
|
||||||
|
fn rlp(&self, with_seal: Seal) -> Bytes {
|
||||||
|
let mut s = RlpStream::new();
|
||||||
|
self.stream_rlp(&mut s, with_seal);
|
||||||
|
s.out()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make these functions traity
|
|
||||||
/// Place this header into an RLP stream `s`, optionally `with_seal`.
|
/// Place this header into an RLP stream `s`, optionally `with_seal`.
|
||||||
pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
||||||
s.begin_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 });
|
if let Seal::With = with_seal {
|
||||||
|
s.begin_list(13 + self.seal.len());
|
||||||
|
} else {
|
||||||
|
s.begin_list(13);
|
||||||
|
}
|
||||||
|
|
||||||
s.append(&self.parent_hash);
|
s.append(&self.parent_hash);
|
||||||
s.append(&self.uncles_hash);
|
s.append(&self.uncles_hash);
|
||||||
s.append(&self.author);
|
s.append(&self.author);
|
||||||
@ -257,28 +315,23 @@ impl Header {
|
|||||||
s.append(&self.gas_used);
|
s.append(&self.gas_used);
|
||||||
s.append(&self.timestamp);
|
s.append(&self.timestamp);
|
||||||
s.append(&self.extra_data);
|
s.append(&self.extra_data);
|
||||||
|
|
||||||
if let Seal::With = with_seal {
|
if let Seal::With = with_seal {
|
||||||
for b in &self.seal {
|
for b in &self.seal {
|
||||||
s.append_raw(b, 1);
|
s.append_raw(b, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the RLP of this header, optionally `with_seal`.
|
|
||||||
pub fn rlp(&self, with_seal: Seal) -> Bytes {
|
|
||||||
let mut s = RlpStream::new();
|
|
||||||
self.stream_rlp(&mut s, with_seal);
|
|
||||||
s.out()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the SHA3 (Keccak) of this header, optionally `with_seal`.
|
/// Alter value of given field, reset memoised hash if changed.
|
||||||
pub fn rlp_keccak(&self, with_seal: Seal) -> H256 { keccak(self.rlp(with_seal)) }
|
fn change_field<T>(hash: &mut Option<H256>, field: &mut T, value: T) where T: PartialEq<T> {
|
||||||
|
if field != &value {
|
||||||
|
*field = value;
|
||||||
|
*hash = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Encode the header, getting a type-safe wrapper around the RLP.
|
|
||||||
pub fn encoded(&self) -> ::encoded::Header {
|
|
||||||
::encoded::Header::new(self.rlp(Seal::With))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Decodable for Header {
|
impl Decodable for Header {
|
||||||
fn decode(r: &UntrustedRlp) -> Result<Self, DecoderError> {
|
fn decode(r: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
@ -297,8 +350,7 @@ impl Decodable for Header {
|
|||||||
timestamp: cmp::min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
timestamp: cmp::min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
||||||
extra_data: r.val_at(12)?,
|
extra_data: r.val_at(12)?,
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: RefCell::new(Some(keccak(r.as_raw()))),
|
hash: keccak(r.as_raw()).into(),
|
||||||
bare_hash: RefCell::new(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in 13..r.item_count()? {
|
for i in 13..r.item_count()? {
|
||||||
@ -376,3 +428,4 @@ mod tests {
|
|||||||
assert_eq!(header_rlp, encoded_header);
|
assert_eq!(header_rlp, encoded_header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,7 +653,7 @@ impl Miner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_gas_limit<C: BlockChain>(&self, client: &C) {
|
fn update_gas_limit<C: BlockChain>(&self, client: &C) {
|
||||||
let gas_limit = client.best_block_header().gas_limit();
|
let gas_limit = *client.best_block_header().gas_limit();
|
||||||
let mut queue = self.transaction_queue.write();
|
let mut queue = self.transaction_queue.write();
|
||||||
queue.set_gas_limit(gas_limit);
|
queue.set_gas_limit(gas_limit);
|
||||||
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
|
||||||
@ -703,7 +703,7 @@ impl Miner {
|
|||||||
condition: Option<TransactionCondition>,
|
condition: Option<TransactionCondition>,
|
||||||
transaction_queue: &mut BanningTransactionQueue,
|
transaction_queue: &mut BanningTransactionQueue,
|
||||||
) -> Vec<Result<TransactionImportResult, Error>> {
|
) -> Vec<Result<TransactionImportResult, Error>> {
|
||||||
let best_block_header = client.best_block_header().decode();
|
let best_block_header = client.best_block_header();
|
||||||
let insertion_time = client.chain_info().best_block_number;
|
let insertion_time = client.chain_info().best_block_number;
|
||||||
let mut inserted = Vec::with_capacity(transactions.len());
|
let mut inserted = Vec::with_capacity(transactions.len());
|
||||||
|
|
||||||
|
@ -135,7 +135,6 @@ impl AbridgedBlock {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use block::Block;
|
use block::Block;
|
||||||
use header::Seal;
|
|
||||||
use super::AbridgedBlock;
|
use super::AbridgedBlock;
|
||||||
use transaction::{Action, Transaction};
|
use transaction::{Action, Transaction};
|
||||||
|
|
||||||
@ -143,7 +142,7 @@ mod tests {
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
fn encode_block(b: &Block) -> Bytes {
|
fn encode_block(b: &Block) -> Bytes {
|
||||||
b.rlp_bytes(Seal::With)
|
b.rlp_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -28,7 +28,7 @@ use blockchain::{BlockChain, BlockProvider};
|
|||||||
use engines::{EthEngine, EpochVerifier, EpochTransition};
|
use engines::{EthEngine, EpochVerifier, EpochTransition};
|
||||||
use machine::EthereumMachine;
|
use machine::EthereumMachine;
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use header::{Header, Seal};
|
use header::Header;
|
||||||
use receipt::Receipt;
|
use receipt::Receipt;
|
||||||
use snapshot::{Error, ManifestData};
|
use snapshot::{Error, ManifestData};
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ impl Rebuilder for ChunkRebuilder {
|
|||||||
transactions: last_rlp.list_at(1)?,
|
transactions: last_rlp.list_at(1)?,
|
||||||
uncles: last_rlp.list_at(2)?,
|
uncles: last_rlp.list_at(2)?,
|
||||||
};
|
};
|
||||||
let block_data = block.rlp_bytes(Seal::With);
|
let block_data = block.rlp_bytes();
|
||||||
let receipts: Vec<Receipt> = last_rlp.list_at(3)?;
|
let receipts: Vec<Receipt> = last_rlp.list_at(3)?;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -153,19 +153,19 @@ impl<'a> PowWorker<'a> {
|
|||||||
fn write_chunk(&mut self, last: H256) -> Result<(), Error> {
|
fn write_chunk(&mut self, last: H256) -> Result<(), Error> {
|
||||||
trace!(target: "snapshot", "prepared block chunk with {} blocks", self.rlps.len());
|
trace!(target: "snapshot", "prepared block chunk with {} blocks", self.rlps.len());
|
||||||
|
|
||||||
let (last_header, last_details) = self.chain.block_header(&last)
|
let (last_header, last_details) = self.chain.block_header_data(&last)
|
||||||
.and_then(|n| self.chain.block_details(&last).map(|d| (n, d)))
|
.and_then(|n| self.chain.block_details(&last).map(|d| (n, d)))
|
||||||
.ok_or(Error::BlockNotFound(last))?;
|
.ok_or(Error::BlockNotFound(last))?;
|
||||||
|
|
||||||
let parent_number = last_header.number() - 1;
|
let parent_number = last_header.number() - 1;
|
||||||
let parent_hash = last_header.parent_hash();
|
let parent_hash = last_header.parent_hash();
|
||||||
let parent_total_difficulty = last_details.total_difficulty - *last_header.difficulty();
|
let parent_total_difficulty = last_details.total_difficulty - last_header.difficulty();
|
||||||
|
|
||||||
trace!(target: "snapshot", "parent last written block: {}", parent_hash);
|
trace!(target: "snapshot", "parent last written block: {}", parent_hash);
|
||||||
|
|
||||||
let num_entries = self.rlps.len();
|
let num_entries = self.rlps.len();
|
||||||
let mut rlp_stream = RlpStream::new_list(3 + num_entries);
|
let mut rlp_stream = RlpStream::new_list(3 + num_entries);
|
||||||
rlp_stream.append(&parent_number).append(parent_hash).append(&parent_total_difficulty);
|
rlp_stream.append(&parent_number).append(&parent_hash).append(&parent_total_difficulty);
|
||||||
|
|
||||||
for pair in self.rlps.drain(..) {
|
for pair in self.rlps.drain(..) {
|
||||||
rlp_stream.append_raw(&pair, 1);
|
rlp_stream.append_raw(&pair, 1);
|
||||||
@ -220,7 +220,6 @@ impl Rebuilder for PowRebuilder {
|
|||||||
/// Feed the rebuilder an uncompressed block chunk.
|
/// Feed the rebuilder an uncompressed block chunk.
|
||||||
/// Returns the number of blocks fed or any errors.
|
/// Returns the number of blocks fed or any errors.
|
||||||
fn feed(&mut self, chunk: &[u8], engine: &EthEngine, abort_flag: &AtomicBool) -> Result<(), ::error::Error> {
|
fn feed(&mut self, chunk: &[u8], engine: &EthEngine, abort_flag: &AtomicBool) -> Result<(), ::error::Error> {
|
||||||
use header::Seal;
|
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use snapshot::verify_old_block;
|
use snapshot::verify_old_block;
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
@ -251,7 +250,7 @@ impl Rebuilder for PowRebuilder {
|
|||||||
let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw()));
|
let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw()));
|
||||||
|
|
||||||
let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
|
let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
|
||||||
let block_bytes = block.rlp_bytes(Seal::With);
|
let block_bytes = block.rlp_bytes();
|
||||||
let is_best = cur_number == self.best_number;
|
let is_best = cur_number == self.best_number;
|
||||||
|
|
||||||
if is_best {
|
if is_best {
|
||||||
|
@ -130,7 +130,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
|||||||
writer: W,
|
writer: W,
|
||||||
p: &Progress
|
p: &Progress
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let start_header = chain.block_header(&block_at)
|
let start_header = chain.block_header_data(&block_at)
|
||||||
.ok_or(Error::InvalidStartingBlock(BlockId::Hash(block_at)))?;
|
.ok_or(Error::InvalidStartingBlock(BlockId::Hash(block_at)))?;
|
||||||
let state_root = start_header.state_root();
|
let state_root = start_header.state_root();
|
||||||
let number = start_header.number();
|
let number = start_header.number();
|
||||||
@ -143,7 +143,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
|||||||
let (state_hashes, block_hashes) = scope(|scope| {
|
let (state_hashes, block_hashes) = scope(|scope| {
|
||||||
let writer = &writer;
|
let writer = &writer;
|
||||||
let block_guard = scope.spawn(move || chunk_secondary(chunker, chain, block_at, writer, p));
|
let block_guard = scope.spawn(move || chunk_secondary(chunker, chain, block_at, writer, p));
|
||||||
let state_res = chunk_state(state_db, state_root, writer, p);
|
let state_res = chunk_state(state_db, &state_root, writer, p);
|
||||||
|
|
||||||
state_res.and_then(|state_hashes| {
|
state_res.and_then(|state_hashes| {
|
||||||
block_guard.join().map(|block_hashes| (state_hashes, block_hashes))
|
block_guard.join().map(|block_hashes| (state_hashes, block_hashes))
|
||||||
@ -156,7 +156,7 @@ pub fn take_snapshot<W: SnapshotWriter + Send>(
|
|||||||
version: snapshot_version,
|
version: snapshot_version,
|
||||||
state_hashes: state_hashes,
|
state_hashes: state_hashes,
|
||||||
block_hashes: block_hashes,
|
block_hashes: block_hashes,
|
||||||
state_root: *state_root,
|
state_root: state_root,
|
||||||
block_number: number,
|
block_number: number,
|
||||||
block_hash: block_at,
|
block_hash: block_at,
|
||||||
};
|
};
|
||||||
@ -486,8 +486,8 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, ch
|
|||||||
|
|
||||||
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
||||||
engine.verify_block_unordered(header)?;
|
engine.verify_block_unordered(header)?;
|
||||||
match chain.block_header(header.parent_hash()) {
|
match chain.block_header_data(header.parent_hash()) {
|
||||||
Some(parent) => engine.verify_block_family(header, &parent),
|
Some(parent) => engine.verify_block_family(header, &parent.decode()),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -362,7 +362,7 @@ fn transaction_proof() {
|
|||||||
|
|
||||||
let mut factories = ::factory::Factories::default();
|
let mut factories = ::factory::Factories::default();
|
||||||
factories.accountdb = ::account_db::Factory::Plain; // raw state values, no mangled keys.
|
factories.accountdb = ::account_db::Factory::Plain; // raw state values, no mangled keys.
|
||||||
let root = client.best_block_header().state_root();
|
let root = *client.best_block_header().state_root();
|
||||||
|
|
||||||
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
|
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
|
||||||
Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine())
|
Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine())
|
||||||
|
@ -211,7 +211,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth
|
|||||||
// cB.p^7 -------------/
|
// cB.p^7 -------------/
|
||||||
// cB.p^8
|
// cB.p^8
|
||||||
let mut expected_uncle_parent = header.parent_hash().clone();
|
let mut expected_uncle_parent = header.parent_hash().clone();
|
||||||
let uncle_parent = bc.block_header(&uncle.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash().clone())))?;
|
let uncle_parent = bc.block_header_data(&uncle.parent_hash()).ok_or_else(|| Error::from(BlockError::UnknownUncleParent(uncle.parent_hash().clone())))?;
|
||||||
for _ in 0..depth {
|
for _ in 0..depth {
|
||||||
match bc.block_details(&expected_uncle_parent) {
|
match bc.block_details(&expected_uncle_parent) {
|
||||||
Some(details) => {
|
Some(details) => {
|
||||||
@ -224,6 +224,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth
|
|||||||
return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash())));
|
return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let uncle_parent = uncle_parent.decode();
|
||||||
verify_parent(&uncle, &uncle_parent, engine.params().gas_limit_bound_divisor)?;
|
verify_parent(&uncle, &uncle_parent, engine.params().gas_limit_bound_divisor)?;
|
||||||
engine.verify_block_family(&uncle, &uncle_parent)?;
|
engine.verify_block_family(&uncle, &uncle_parent)?;
|
||||||
verified.insert(uncle.hash());
|
verified.insert(uncle.hash());
|
||||||
@ -496,8 +497,9 @@ mod tests {
|
|||||||
// is fine.
|
// is fine.
|
||||||
let client = ::client::TestBlockChainClient::default();
|
let client = ::client::TestBlockChainClient::default();
|
||||||
|
|
||||||
let parent = bc.block_header(header.parent_hash())
|
let parent = bc.block_header_data(header.parent_hash())
|
||||||
.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?;
|
.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?
|
||||||
|
.decode();
|
||||||
|
|
||||||
let full_params = FullFamilyParams {
|
let full_params = FullFamilyParams {
|
||||||
block_bytes: bytes,
|
block_bytes: bytes,
|
||||||
|
@ -30,7 +30,7 @@ use ethcore::block::IsBlock;
|
|||||||
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
|
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
|
||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
use ethcore::filter::Filter as EthcoreFilter;
|
use ethcore::filter::Filter as EthcoreFilter;
|
||||||
use ethcore::header::{BlockNumber as EthBlockNumber, Seal};
|
use ethcore::header::{BlockNumber as EthBlockNumber};
|
||||||
use ethcore::log_entry::LogEntry;
|
use ethcore::log_entry::LogEntry;
|
||||||
use ethcore::miner::MinerService;
|
use ethcore::miner::MinerService;
|
||||||
use ethcore::snapshot::SnapshotService;
|
use ethcore::snapshot::SnapshotService;
|
||||||
@ -199,7 +199,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
|
|||||||
|
|
||||||
let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header));
|
let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header));
|
||||||
|
|
||||||
(pending_block.map(|b| encoded::Block::new(b.rlp_bytes(Seal::Without))), Some(difficulty), extra, true)
|
(pending_block.map(|b| encoded::Block::new(b.rlp_bytes())), Some(difficulty), extra, true)
|
||||||
},
|
},
|
||||||
|
|
||||||
BlockNumberOrId::Number(num) => {
|
BlockNumberOrId::Number(num) => {
|
||||||
|
@ -1974,7 +1974,7 @@ impl ChainSync {
|
|||||||
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize {
|
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo, peers: &[PeerId]) -> usize {
|
||||||
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
|
trace!(target: "sync", "Sending NewHashes to {:?}", peers);
|
||||||
let mut sent = 0;
|
let mut sent = 0;
|
||||||
let last_parent = &io.chain().best_block_header().parent_hash();
|
let last_parent = *io.chain().best_block_header().parent_hash();
|
||||||
for peer_id in peers {
|
for peer_id in peers {
|
||||||
sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) {
|
sent += match ChainSync::create_new_hashes_rlp(io.chain(), &last_parent, &chain_info.best_block_hash) {
|
||||||
Some(rlp) => {
|
Some(rlp) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user