block_core/
transaction.rs1use 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub enum TransactionAction {
12 Call(Address),
13 Create,
14 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}