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_memory::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);
    }
}