block_core/
transaction.rs

1use rlp::{UntrustedRlp, DecoderError, RlpStream, Encodable, Decodable};
2use bigint::{Address, U256, M256, H256};
3use sha3::{Digest, Keccak256};
4
5#[cfg(not(feature = "std"))] use alloc::vec::Vec;
6#[cfg(not(feature = "std"))] use alloc::rc::Rc;
7
8// Use transaction action so we can keep most of the common fields
9// without creating a large enum.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum TransactionAction {
12    Call(Address),
13    Create,
14    /// CREATE2 transaction action with salt and code hash
15    Create2(H256, M256),
16}
17
18impl TransactionAction {
19    pub fn address(&self, caller: Address, nonce: U256) -> Address {
20        match self {
21            &TransactionAction::Call(address) => address,
22            &TransactionAction::Create => {
23                let mut rlp = RlpStream::new_list(2);
24                rlp.append(&caller);
25                rlp.append(&nonce);
26
27                Address::from(M256::from(Keccak256::digest(rlp.out().as_slice()).as_slice()))
28            },
29            &TransactionAction::Create2(salt, code_hash) => {
30                let mut digest = Keccak256::new();
31                digest.input(&[0xff]);
32                digest.input(&caller);
33                digest.input(&salt);
34                digest.input(&H256::from(code_hash));
35                let hash = digest.result();
36                Address::from(M256::from(&hash[12..]))
37            }
38        }
39    }
40}
41
42const CREATE2_TAG: u8 = 0xc2;
43
44impl Encodable for TransactionAction {
45    fn rlp_append(&self, s: &mut RlpStream) {
46        match self {
47            &TransactionAction::Call(address) => {
48                s.encoder().encode_value(&address);
49            },
50            &TransactionAction::Create => {
51                s.encoder().encode_value(&[])
52            },
53            &TransactionAction::Create2(salt, code_hash) => {
54                s.begin_list(3)
55                    .append(&CREATE2_TAG)
56                    .append(&salt)
57                    .append(&H256::from(code_hash));
58            }
59        }
60    }
61}
62
63impl Decodable for TransactionAction {
64    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
65        let action = if rlp.is_empty() {
66            TransactionAction::Create
67        } else if let Ok(CREATE2_TAG) = rlp.val_at(0) {
68            let salt: H256 = rlp.val_at(1)?;
69            let code_hash: H256 = rlp.val_at(2)?;
70            TransactionAction::Create2(salt, M256::from(code_hash))
71        } else {
72            TransactionAction::Call(rlp.as_val()?)
73        };
74
75        Ok(action)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use rlp;
83
84    #[test]
85    fn rlp_roundtrip_call() {
86        let address = Address::from(M256::from(std::u64::MAX));
87        let action = TransactionAction::Call(address);
88        let encoded = rlp::encode(&action);
89        let decoded: TransactionAction = rlp::decode(&encoded);
90        assert_eq!(action, decoded);
91    }
92
93    #[test]
94    fn rlp_roundtrip_create() {
95        let action = TransactionAction::Create;
96        let encoded = rlp::encode(&action);
97        let decoded: TransactionAction = rlp::decode(&encoded);
98        assert_eq!(action, decoded);
99    }
100
101    #[test]
102    fn rlp_roundtrip_create2() {
103        let salt = H256::from(M256::from(std::i32::MAX));
104        let code_hash = M256::from(1024);
105        let action = TransactionAction::Create2(salt, code_hash);
106        let encoded = rlp::encode(&action);
107        let decoded: TransactionAction = rlp::decode(&encoded);
108        assert_eq!(action, decoded);
109    }
110}