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:
committed by
Marek Kotewicz
parent
d477670cb9
commit
9f775a7673
@@ -17,7 +17,6 @@
|
||||
//! Block header.
|
||||
|
||||
use std::cmp;
|
||||
use std::cell::RefCell;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP, keccak};
|
||||
use heapsize::HeapSizeOf;
|
||||
@@ -28,7 +27,8 @@ use rlp::{UntrustedRlp, RlpStream, Encodable, DecoderError, Decodable};
|
||||
pub use types::BlockNumber;
|
||||
|
||||
/// Semantic boolean for when a seal/signature is included.
|
||||
pub enum Seal {
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Seal {
|
||||
/// The seal/signature is included.
|
||||
With,
|
||||
/// The seal/signature is not included.
|
||||
@@ -75,14 +75,18 @@ pub struct Header {
|
||||
/// Vector of post-RLP-encoded fields.
|
||||
seal: Vec<Bytes>,
|
||||
|
||||
/// The memoized hash of the RLP representation *including* the seal fields.
|
||||
hash: RefCell<Option<H256>>,
|
||||
/// The memoized hash of the RLP representation *without* the seal fields.
|
||||
bare_hash: RefCell<Option<H256>>,
|
||||
/// Memoized hash of that header and the seal.
|
||||
hash: Option<H256>,
|
||||
}
|
||||
|
||||
impl PartialEq for Header {
|
||||
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.timestamp == c.timestamp &&
|
||||
self.number == c.number &&
|
||||
@@ -120,51 +124,57 @@ impl Default for Header {
|
||||
|
||||
difficulty: U256::default(),
|
||||
seal: vec![],
|
||||
hash: RefCell::new(None),
|
||||
bare_hash: RefCell::new(None),
|
||||
hash: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// Create a new, default-valued, header.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn new() -> Self { Self::default() }
|
||||
|
||||
/// Get the parent_hash field of the header.
|
||||
pub fn parent_hash(&self) -> &H256 { &self.parent_hash }
|
||||
|
||||
/// Get the timestamp field of the header.
|
||||
pub fn timestamp(&self) -> u64 { self.timestamp }
|
||||
|
||||
/// Get the number field of the header.
|
||||
pub fn number(&self) -> BlockNumber { self.number }
|
||||
|
||||
/// Get the author field of the header.
|
||||
pub fn author(&self) -> &Address { &self.author }
|
||||
|
||||
/// Get the extra data field of the header.
|
||||
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.
|
||||
pub fn state_root(&self) -> &H256 { &self.state_root }
|
||||
|
||||
/// Get the receipts root field of the header.
|
||||
pub fn receipts_root(&self) -> &H256 { &self.receipts_root }
|
||||
|
||||
/// Get the log bloom field of the header.
|
||||
pub fn log_bloom(&self) -> &Bloom { &self.log_bloom }
|
||||
|
||||
/// Get the transactions root field of the header.
|
||||
pub fn transactions_root(&self) -> &H256 { &self.transactions_root }
|
||||
|
||||
/// Get the uncles hash field of the header.
|
||||
pub fn uncles_hash(&self) -> &H256 { &self.uncles_hash }
|
||||
|
||||
/// Get the gas used field of the header.
|
||||
pub fn gas_used(&self) -> &U256 { &self.gas_used }
|
||||
|
||||
/// Get the gas limit field of the header.
|
||||
pub fn gas_limit(&self) -> &U256 { &self.gas_limit }
|
||||
|
||||
/// Get the difficulty field of the header.
|
||||
pub fn difficulty(&self) -> &U256 { &self.difficulty }
|
||||
|
||||
/// Get the seal field of the header.
|
||||
pub fn seal(&self) -> &[Bytes] { &self.seal }
|
||||
|
||||
/// 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> {
|
||||
self.seal.iter().map(|rlp| {
|
||||
@@ -172,78 +182,126 @@ impl Header {
|
||||
}).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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
pub fn set_difficulty(&mut self, a: U256) { self.difficulty = a; self.note_dirty(); }
|
||||
/// Set the seal field of the header.
|
||||
pub fn set_seal(&mut self, a: Vec<Bytes>) { self.seal = a; self.note_dirty(); }
|
||||
pub fn set_difficulty(&mut self, a: U256) {
|
||||
change_field(&mut self.hash, &mut self.difficulty, a);
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
let mut hash = self.hash.borrow_mut();
|
||||
match &mut *hash {
|
||||
&mut Some(ref h) => h.clone(),
|
||||
hash @ &mut None => {
|
||||
let h = self.rlp_keccak(Seal::With);
|
||||
*hash = Some(h.clone());
|
||||
h
|
||||
}
|
||||
}
|
||||
self.hash.unwrap_or_else(|| keccak(self.rlp(Seal::With)))
|
||||
}
|
||||
|
||||
/// Get the hash of the header excluding the seal
|
||||
pub fn bare_hash(&self) -> H256 {
|
||||
let mut hash = self.bare_hash.borrow_mut();
|
||||
match &mut *hash {
|
||||
&mut Some(ref h) => h.clone(),
|
||||
hash @ &mut None => {
|
||||
let h = self.rlp_keccak(Seal::Without);
|
||||
*hash = Some(h.clone());
|
||||
h
|
||||
}
|
||||
}
|
||||
keccak(self.rlp(Seal::Without))
|
||||
}
|
||||
|
||||
/// Note that some fields have changed. Resets the memoised hash.
|
||||
pub fn note_dirty(&self) {
|
||||
*self.hash.borrow_mut() = None;
|
||||
*self.bare_hash.borrow_mut() = 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))
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
||||
s.begin_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 });
|
||||
fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) {
|
||||
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.uncles_hash);
|
||||
s.append(&self.author);
|
||||
@@ -257,29 +315,24 @@ impl Header {
|
||||
s.append(&self.gas_used);
|
||||
s.append(&self.timestamp);
|
||||
s.append(&self.extra_data);
|
||||
|
||||
if let Seal::With = with_seal {
|
||||
for b in &self.seal {
|
||||
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`.
|
||||
pub fn rlp_keccak(&self, with_seal: Seal) -> H256 { keccak(self.rlp(with_seal)) }
|
||||
|
||||
/// Encode the header, getting a type-safe wrapper around the RLP.
|
||||
pub fn encoded(&self) -> ::encoded::Header {
|
||||
::encoded::Header::new(self.rlp(Seal::With))
|
||||
/// Alter value of given field, reset memoised hash if changed.
|
||||
fn change_field<T>(hash: &mut Option<H256>, field: &mut T, value: T) where T: PartialEq<T> {
|
||||
if field != &value {
|
||||
*field = value;
|
||||
*hash = None;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Decodable for Header {
|
||||
fn decode(r: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||
let mut blockheader = Header {
|
||||
@@ -297,8 +350,7 @@ impl Decodable for Header {
|
||||
timestamp: cmp::min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
||||
extra_data: r.val_at(12)?,
|
||||
seal: vec![],
|
||||
hash: RefCell::new(Some(keccak(r.as_raw()))),
|
||||
bare_hash: RefCell::new(None),
|
||||
hash: keccak(r.as_raw()).into(),
|
||||
};
|
||||
|
||||
for i in 13..r.item_count()? {
|
||||
@@ -376,3 +428,4 @@ mod tests {
|
||||
assert_eq!(header_rlp, encoded_header);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user