1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use rlp::{self, Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
use bigint::{Address, Gas, H256, U256, B256, H64, H2048};
use bloom::LogsBloom;
use trie::FixedMemoryTrieMut;
use sha3::{Keccak256, Digest};
use std::collections::HashMap;
use super::{Header, Transaction, Receipt, SignaturePatch};
pub fn transactions_root(transactions: &[Transaction]) -> H256 {
let mut trie = FixedMemoryTrieMut::default();
for (i, transaction) in transactions.iter().enumerate() {
trie.insert(&U256::from(i), transaction);
}
trie.root()
}
pub fn receipts_root(receipts: &[Receipt]) -> H256 {
let mut trie = FixedMemoryTrieMut::default();
for (i, receipt) in receipts.iter().enumerate() {
trie.insert(&U256::from(i), receipt);
}
trie.root()
}
pub fn ommers_hash(ommers: &[Header]) -> H256 {
let encoded = rlp::encode_list(ommers).to_vec();
let hash = H256::from(Keccak256::digest(&encoded).as_slice());
hash
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Block {
pub header: Header,
pub transactions: Vec<Transaction>,
pub ommers: Vec<Header>,
}
impl Block {
pub fn is_basic_valid(&self) -> bool {
if transactions_root(&self.transactions) != self.header.transactions_root {
return false;
}
if ommers_hash(&self.ommers) != self.header.ommers_hash {
return false;
}
return true;
}
}
impl Encodable for Block {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3);
s.append(&self.header);
s.append_list(&self.transactions);
s.append_list(&self.ommers);
}
}
impl Decodable for Block {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
Ok(Self {
header: rlp.val_at(0)?,
transactions: rlp.list_at(1)?,
ommers: rlp.list_at(2)?,
})
}
}
#[cfg(test)]
mod tests {
use rlp::{encode, decode, Rlp};
use hexutil::read_hex;
use bigint::{U256, H256, Address, Gas};
use bloom::LogsBloom;
use block::Block;
use TransactionAction;
use transaction::GlobalSignaturePatch;
use std::str::FromStr;
#[test]
fn block_53165_rlp() {
let raw = read_hex("f9050df901ffa037ecbfd908ece3c54fa5b9f8e1b4a6089139da1dc4b5013a46c5818304de47b3a05cd40176209a61f3b26f3b5b491f177b93a3c33c595d0be75c26c97bdb60e7a294a50ec0d39fa913e62f1bae7074e6f36caa71855ba0a1b07a1f98248efee3d2111fcf9dcb2c1ad9f961a192e02571c0b55e7539b427a0f739c0f6d17bcad52552bfe3a4950885222ae694750135a75f452efc033d425da0b61bbed645e5b6366521a5c3bddb98d788067dc7a0f1515bfe4bdad0fb63b188b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086016f2c8a34da82cfad8320f4018307a1208455c5e86b80a05fca8f6fce90e5f92549824d7b7d456cefafb92f223f97d60efee8e62522b9778870cee9238ebd5c31f8ecf8ea04850d9afee4208307a12094dc884e349103eaee4aef913d532cb5db2745f48b80b884de6f24bb0000000000000000000000008674c218f0351a62c3ba78c34fd2182a93da94e20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000568656c6c6f0000000000000000000000000000000000000000000000000000001ba04f2dfebd7c0f712119678fdd5ce6abc357a91df2284edafa5dc1c7503bb2d5c6a023b85af577d777b5cc5af8a4ece80bf45ae9f0be7b8e166a91271deb938b72aff9021af90217a059c53a8471fdc848352699052890b6156753a94743cfb4dc3f921df67e16978aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794f2d2aff1320476cb8c6b607199d23175cc595693a0bf6464bc0efe71b06723bf303cc661322eff513b247e714537d6593472ae76bea056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086016f2c8ff18c82cfab8320f404808455c5e84b9b476574682f76312e302e312f77696e646f77732f676f312e342e32a0fc0a1197dee6cf57a6d8afeaa1d070462638d484e1f71266b114b9cc5d5a5b0e88f48a42a38b85ccf0").unwrap();
let block: Block = decode(&raw);
assert_eq!(block.header.parent_hash, H256::from_str("37ecbfd908ece3c54fa5b9f8e1b4a6089139da1dc4b5013a46c5818304de47b3").unwrap());
assert_eq!(block.transactions[0].action, TransactionAction::Call(Address::from_str("0xdc884e349103eaee4aef913d532cb5db2745f48b").unwrap()));
assert_eq!(block.transactions[0].gas_limit, Gas::from(500000u64));
assert_eq!(block.transactions[0].value, U256::zero());
assert_eq!(block.ommers[0].parent_hash, H256::from_str("59c53a8471fdc848352699052890b6156753a94743cfb4dc3f921df67e16978a").unwrap());
assert_eq!(block.ommers[0].beneficiary, Address::from_str("f2d2aff1320476cb8c6b607199d23175cc595693").unwrap());
assert_eq!(block, decode(&encode(&block).to_vec()));
let encoded = encode(&block).to_vec();
assert_eq!(encoded, raw);
}
}