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#[cfg(feature = "std")] use std::rc::Rc;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum TransactionAction {
13 Call(Address),
14 Create,
15 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}