use rlp::{self, Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
use bigint::{Address, Gas, H256, U256, B256, H64};
use bloom::LogsBloom;
use std::cmp::Ordering;
use sha3::{Keccak256, Digest};
use super::RlpHash;
pub trait HeaderHash<H: Copy> {
fn parent_hash(&self) -> Option<H>;
fn header_hash(&self) -> H;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TotalHeader(pub Header, U256);
impl TotalHeader {
pub fn from_genesis(header: Header) -> TotalHeader {
let diff = header.difficulty;
TotalHeader(header, diff)
}
pub fn from_parent(header: Header, parent: &TotalHeader) -> TotalHeader {
let diff = header.difficulty + parent.1;
TotalHeader(header, diff)
}
pub fn total_difficulty(&self) -> U256 {
self.1
}
}
impl HeaderHash<H256> for TotalHeader {
fn parent_hash(&self) -> Option<H256> {
self.0.parent_hash()
}
fn header_hash(&self) -> H256 {
self.0.header_hash()
}
}
impl Into<Header> for TotalHeader {
fn into(self) -> Header {
self.0
}
}
impl Ord for TotalHeader {
fn cmp(&self, other: &TotalHeader) -> Ordering {
self.1.cmp(&other.1)
}
}
impl PartialOrd for TotalHeader {
fn partial_cmp(&self, other: &TotalHeader) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Header {
pub parent_hash: H256,
pub ommers_hash: H256,
pub beneficiary: Address,
pub state_root: H256,
pub transactions_root: H256,
pub receipts_root: H256,
pub logs_bloom: LogsBloom,
pub difficulty: U256,
pub number: U256,
pub gas_limit: Gas,
pub gas_used: Gas,
pub timestamp: u64,
pub extra_data: B256,
pub mix_hash: H256,
pub nonce: H64,
}
impl HeaderHash<H256> for Header {
fn parent_hash(&self) -> Option<H256> {
if self.number == U256::zero() {
None
} else {
Some(self.parent_hash)
}
}
fn header_hash(&self) -> H256 {
H256::from(Keccak256::digest(&rlp::encode(self).to_vec()).as_slice())
}
}
impl Header {
pub fn partial_rlp_append(&self, s: &mut RlpStream) {
s.begin_list(13);
s.append(&self.parent_hash);
s.append(&self.ommers_hash);
s.append(&self.beneficiary);
s.append(&self.state_root);
s.append(&self.transactions_root);
s.append(&self.receipts_root);
s.append(&self.logs_bloom);
s.append(&self.difficulty);
s.append(&self.number);
s.append(&self.gas_limit);
s.append(&self.gas_used);
s.append(&self.timestamp);
s.append(&self.extra_data);
}
pub fn partial_hash(&self) -> H256 {
let mut stream = RlpStream::new();
self.partial_rlp_append(&mut stream);
H256::from(Keccak256::digest(&stream.drain()).as_slice())
}
}
impl Encodable for Header {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(15);
s.append(&self.parent_hash);
s.append(&self.ommers_hash);
s.append(&self.beneficiary);
s.append(&self.state_root);
s.append(&self.transactions_root);
s.append(&self.receipts_root);
s.append(&self.logs_bloom);
s.append(&self.difficulty);
s.append(&self.number);
s.append(&self.gas_limit);
s.append(&self.gas_used);
s.append(&self.timestamp);
s.append(&self.extra_data);
s.append(&self.mix_hash);
s.append(&self.nonce);
}
}
impl Decodable for Header {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Self {
parent_hash: rlp.val_at(0)?,
ommers_hash: rlp.val_at(1)?,
beneficiary: rlp.val_at(2)?,
state_root: rlp.val_at(3)?,
transactions_root: rlp.val_at(4)?,
receipts_root: rlp.val_at(5)?,
logs_bloom: rlp.val_at(6)?,
difficulty: rlp.val_at(7)?,
number: rlp.val_at(8)?,
gas_limit: rlp.val_at(9)?,
gas_used: rlp.val_at(10)?,
timestamp: rlp.val_at(11)?,
extra_data: rlp.val_at(12)?,
mix_hash: rlp.val_at(13)?,
nonce: rlp.val_at(14)?,
})
}
}
impl RlpHash for Header {
fn rlp_hash(&self) -> H256 {
H256::from(Keccak256::digest(&rlp::encode(self)).as_slice())
}
}
#[cfg(test)]
mod tests {
use rlp::{encode, decode, Rlp};
use hexutil::read_hex;
use bigint::{U256, H256, Address, Gas};
use bloom::LogsBloom;
use header::Header;
use std::str::FromStr;
#[test]
fn block_0_rlp() {
let raw = read_hex("f90219f90214a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850400000000808213888080a011bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82faa00000000000000000000000000000000000000000000000000000000000000000880000000000000042c0c0").unwrap();
let block_raw = Rlp::new(&raw);
let block: Header = block_raw.val_at(0);
assert_eq!(block.number, U256::from(0u64));
let encoded = encode(&block).to_vec();
let encoded_ref: &[u8] = encoded.as_ref();
assert_eq!(encoded_ref, block_raw.at(0).as_raw());
}
#[test]
fn block_1_rlp() {
let raw = read_hex("f90216f90211a0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479405a56e2d52c817161883f50c441c3228cfe54d9fa0d67e4d450343046425ae4271474353857ab860dbc0a1dde64b41b5cd3a532bf3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008503ff80000001821388808455ba422499476574682f76312e302e302f6c696e75782f676f312e342e32a0969b900de27b6ac6a67742365dd65f55a0526c41fd18e1b16f1a1215c2e66f5988539bd4979fef1ec4c0c0").unwrap();
let block_raw = Rlp::new(&raw);
let block: Header = block_raw.val_at(0);
assert_eq!(block.parent_hash, H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap());
assert_eq!(block.ommers_hash, H256::from_str("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap());
assert_eq!(block.beneficiary, Address::from_str("05a56e2d52c817161883f50c441c3228cfe54d9f").unwrap());
assert_eq!(block.state_root, H256::from_str("d67e4d450343046425ae4271474353857ab860dbc0a1dde64b41b5cd3a532bf3").unwrap());
assert_eq!(block.transactions_root, H256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap());
assert_eq!(block.logs_bloom, LogsBloom::default());
assert_eq!(block.difficulty, U256::from(17171480576u64));
assert_eq!(block.number, U256::from(1u64));
assert_eq!(block.gas_limit, Gas::from(5000u64));
assert_eq!(block.gas_used, Gas::zero());
assert_eq!(block.timestamp, 1438269988u64);
assert_eq!(block, decode(&encode(&block).to_vec()));
let encoded = encode(&block).to_vec();
let encoded_ref: &[u8] = encoded.as_ref();
assert_eq!(encoded_ref, block_raw.at(0).as_raw());
}
}