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