-
Notifications
You must be signed in to change notification settings - Fork 14
/
transaction.rs
111 lines (99 loc) · 3.48 KB
/
transaction.rs
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use rlp::{UntrustedRlp, DecoderError, RlpStream, Encodable, Decodable};
use bigint::{Address, U256, M256, H256};
use sha3::{Digest, Keccak256};
#[cfg(not(feature = "std"))] use alloc::vec::Vec;
#[cfg(not(feature = "std"))] use alloc::rc::Rc;
#[cfg(feature = "std")] use std::rc::Rc;
// Use transaction action so we can keep most of the common fields
// without creating a large enum.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransactionAction {
Call(Address),
Create,
/// CREATE2 transaction action with salt and code hash
Create2(H256, M256),
}
impl TransactionAction {
pub fn address(&self, caller: Address, nonce: U256) -> Address {
match self {
&TransactionAction::Call(address) => address,
&TransactionAction::Create => {
let mut rlp = RlpStream::new_list(2);
rlp.append(&caller);
rlp.append(&nonce);
Address::from(M256::from(Keccak256::digest(rlp.out().as_slice()).as_slice()))
},
&TransactionAction::Create2(salt, code_hash) => {
let mut digest = Keccak256::new();
digest.input(&[0xff]);
digest.input(&caller);
digest.input(&salt);
digest.input(&H256::from(code_hash));
let hash = digest.result();
Address::from(M256::from(&hash[12..]))
}
}
}
}
const CREATE2_TAG: u8 = 0xc2;
impl Encodable for TransactionAction {
fn rlp_append(&self, s: &mut RlpStream) {
match self {
&TransactionAction::Call(address) => {
s.encoder().encode_value(&address);
},
&TransactionAction::Create => {
s.encoder().encode_value(&[])
},
&TransactionAction::Create2(salt, code_hash) => {
s.begin_list(3)
.append(&CREATE2_TAG)
.append(&salt)
.append(&H256::from(code_hash));
}
}
}
}
impl Decodable for TransactionAction {
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
let action = if rlp.is_empty() {
TransactionAction::Create
} else if let Ok(CREATE2_TAG) = rlp.val_at(0) {
let salt: H256 = rlp.val_at(1)?;
let code_hash: H256 = rlp.val_at(2)?;
TransactionAction::Create2(salt, M256::from(code_hash))
} else {
TransactionAction::Call(rlp.as_val()?)
};
Ok(action)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rlp;
#[test]
fn rlp_roundtrip_call() {
let address = Address::from(M256::from(0xDEADBEEFDEADBEEFDEADBEEF_u64));
let action = TransactionAction::Call(address);
let encoded = rlp::encode(&action);
let decoded: TransactionAction = rlp::decode(&encoded);
assert_eq!(action, decoded);
}
#[test]
fn rlp_roundtrip_create() {
let action = TransactionAction::Create;
let encoded = rlp::encode(&action);
let decoded: TransactionAction = rlp::decode(&encoded);
assert_eq!(action, decoded);
}
#[test]
fn rlp_roundtrip_create2() {
let salt = H256::from(M256::from(0xDEADBEEF));
let code_hash = M256::from(1024);
let action = TransactionAction::Create2(salt, code_hash);
let encoded = rlp::encode(&action);
let decoded: TransactionAction = rlp::decode(&encoded);
assert_eq!(action, decoded);
}
}