block/
transaction.rs

1#[cfg(feature = "c-secp256k1")]
2use secp256k1::{Message, Error, RecoverableSignature, RecoveryId, SECP256K1};
3#[cfg(feature = "c-secp256k1")]
4use secp256k1::key::SecretKey;
5#[cfg(feature = "rust-secp256k1")]
6use secp256k1::{self, Message, Error, Signature, RecoveryId, SecretKey, PublicKey};
7
8use rlp::{self, Encodable, Decodable, RlpStream, DecoderError, UntrustedRlp};
9use bigint::{Address, Gas, H256, U256};
10use sha3::{Digest, Keccak256};
11use address::FromKey;
12use std::str::FromStr;
13use super::{TransactionAction, RlpHash};
14
15/// Refer to EIP155 related to chain ID.
16pub trait SignaturePatch {
17    fn chain_id() -> Option<u64>;
18}
19
20/// Frontier signature patch without EIP155.
21pub struct GlobalSignaturePatch;
22impl SignaturePatch for GlobalSignaturePatch {
23    fn chain_id() -> Option<u64> { None }
24}
25
26/// EIP155 Ethereum Classic chain.
27pub struct ClassicSignaturePatch;
28impl SignaturePatch for ClassicSignaturePatch {
29    fn chain_id() -> Option<u64> { Some(61) }
30}
31
32/// Refer to Homestead transaction validation.
33pub trait ValidationPatch {
34    fn require_low_s() -> bool;
35}
36
37/// Frontier validation patch.
38pub struct FrontierValidationPatch;
39impl ValidationPatch for FrontierValidationPatch {
40    fn require_low_s() -> bool { false }
41}
42
43/// Homestead validation patch.
44pub struct HomesteadValidationPatch;
45impl ValidationPatch for HomesteadValidationPatch {
46    fn require_low_s() -> bool { true }
47}
48
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub struct TransactionSignature {
51    pub v: u64,
52    pub r: H256,
53    pub s: H256,
54}
55
56impl TransactionSignature {
57    pub fn standard_v(&self) -> u8 {
58        let v = self.v;
59        if v == 27 || v == 28 || v > 36 {
60            ((v - 1) % 2) as u8
61        } else {
62            4
63        }
64    }
65
66    pub fn is_low_s(&self) -> bool {
67        self.s <= H256::from_str("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0").unwrap()
68    }
69
70    pub fn is_valid(&self) -> bool {
71        self.standard_v() <= 1 &&
72            self.r < H256::from_str("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141").unwrap() &&
73            self.r >= H256::from(1) &&
74            self.s < H256::from_str("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141").unwrap() &&
75            self.s >= H256::from(1)
76    }
77
78    pub fn chain_id(&self) -> Option<u64> {
79        if self.v > 36 {
80            Some((self.v - 35) / 2)
81        } else {
82            None
83        }
84    }
85
86    #[cfg(feature = "c-secp256k1")]
87    pub fn to_recoverable_signature(&self) -> Result<RecoverableSignature, Error> {
88        let mut sig = [0u8; 64];
89        sig[0..32].copy_from_slice(&self.r);
90        sig[32..64].copy_from_slice(&self.s);
91
92        RecoverableSignature::from_compact(&SECP256K1, &sig, RecoveryId::from_i32(self.standard_v() as i32)?)
93    }
94
95    #[cfg(feature = "rust-secp256k1")]
96    pub fn to_recoverable_signature(&self) -> Result<(Signature, RecoveryId), Error> {
97        let mut sig = [0u8; 64];
98        sig[0..32].copy_from_slice(&self.r);
99        sig[32..64].copy_from_slice(&self.s);
100
101        Ok((Signature::parse(&sig), RecoveryId::parse(self.standard_v() as u8)?))
102    }
103}
104
105pub struct UnsignedTransaction {
106    pub nonce: U256,
107    pub gas_price: Gas,
108    pub gas_limit: Gas,
109    pub action: TransactionAction,
110    pub value: U256,
111    pub input: Vec<u8>,
112}
113
114impl UnsignedTransaction {
115    fn signing_rlp_append(&self, s: &mut RlpStream, chain_id: Option<u64>) {
116        s.begin_list(if chain_id.is_some() { 9 } else { 6 });
117        s.append(&self.nonce);
118        s.append(&self.gas_price);
119        s.append(&self.gas_limit);
120        s.append(&self.action);
121        s.append(&self.value);
122        s.append(&self.input);
123
124        if let Some(chain_id) = chain_id {
125            s.append(&chain_id);
126            s.append(&0u8);
127            s.append(&0u8);
128        }
129    }
130
131    fn signing_hash(&self, chain_id: Option<u64>) -> H256 {
132        let mut stream = RlpStream::new();
133        self.signing_rlp_append(&mut stream, chain_id);
134        H256::from(Keccak256::digest(&stream.drain()).as_slice())
135    }
136
137    pub fn sign<P: SignaturePatch>(self, key: &SecretKey) -> Transaction {
138        let hash = self.signing_hash(P::chain_id());
139        // hash is always MESSAGE_SIZE bytes.
140        let msg = {
141            #[cfg(feature = "c-secp256k1")]
142            { Message::from_slice(&hash).unwrap() }
143            #[cfg(feature = "rust-secp256k1")]
144            { let mut a = [0u8; 32];
145              for i in 0..32 {
146                  a[i] = hash[i];
147              }
148              Message::parse(&a)
149            }
150        };
151
152        // SecretKey and Message are always valid.
153        let s = {
154            #[cfg(feature = "c-secp256k1")]
155            { SECP256K1.sign_recoverable(&msg, key).unwrap() }
156            #[cfg(feature = "rust-secp256k1")]
157            { secp256k1::sign(&msg, key).unwrap() }
158        };
159        let (rid, sig) = {
160            #[cfg(feature = "c-secp256k1")]
161            { s.serialize_compact(&SECP256K1) }
162            #[cfg(feature = "rust-secp256k1")]
163            { (s.1, s.0.serialize()) }
164        };
165
166        let sig = TransactionSignature {
167            v: ({
168                #[cfg(feature = "c-secp256k1")]
169                { rid.to_i32() }
170                #[cfg(feature = "rust-secp256k1")]
171                { let v: i32 = rid.into(); v }
172            } + if let Some(n) = P::chain_id() { (35 + n * 2) as i32 } else { 27 }) as u64,
173            r: H256::from(&sig[0..32]),
174            s: H256::from(&sig[32..64]),
175        };
176
177        Transaction {
178            nonce: self.nonce,
179            gas_price: self.gas_price,
180            gas_limit: self.gas_limit,
181            action: self.action,
182            value: self.value,
183            input: self.input,
184            signature: sig,
185        }
186    }
187
188    pub fn sign_global(self, key: &SecretKey) -> Transaction {
189        self.sign::<GlobalSignaturePatch>(key)
190    }
191}
192
193impl From<Transaction> for UnsignedTransaction {
194    fn from(val: Transaction) -> UnsignedTransaction {
195        UnsignedTransaction {
196            nonce: val.nonce,
197            gas_price: val.gas_price,
198            gas_limit: val.gas_limit,
199            action: val.action,
200            value: val.value,
201            input: val.input,
202        }
203    }
204}
205
206#[derive(Clone, Debug, PartialEq, Eq)]
207pub struct Transaction {
208    pub nonce: U256,
209    pub gas_price: Gas,
210    pub gas_limit: Gas,
211    pub action: TransactionAction,
212    pub value: U256,
213    pub signature: TransactionSignature,
214    pub input: Vec<u8>, // The input data, either data or init, depending on TransactionAction.
215}
216
217impl Transaction {
218    pub fn caller(&self) -> Result<Address, Error> {
219        let unsigned = UnsignedTransaction::from((*self).clone());
220        let hash = unsigned.signing_hash(self.signature.chain_id());
221        let sig = self.signature.to_recoverable_signature()?;
222        let public_key = {
223            #[cfg(feature = "c-secp256k1")]
224            { SECP256K1.recover(&Message::from_slice(&hash).unwrap(), &sig)? }
225            #[cfg(feature = "rust-secp256k1")]
226            { let mut a = [0u8; 32];
227              for i in 0..32 {
228                  a[i] = hash[i];
229              }
230              secp256k1::recover(&Message::parse(&a), &sig.0, &sig.1)?
231            }
232        };
233
234        Ok(Address::from_public_key(&public_key))
235    }
236
237    pub fn address(&self) -> Result<Address, Error> {
238        Ok(self.action.address(self.caller()?, self.nonce))
239    }
240
241    pub fn is_basic_valid<P: SignaturePatch, Q: ValidationPatch>(&self) -> bool {
242        if !self.signature.is_valid() {
243            return false;
244        }
245
246        if self.signature.chain_id().is_some() && self.signature.chain_id() != P::chain_id() {
247            return false;
248        }
249
250        if self.caller().is_err() {
251            return false;
252        }
253
254        if Q::require_low_s() && !self.signature.is_low_s() {
255            return false;
256        }
257
258        return true;
259    }
260}
261
262impl Encodable for Transaction {
263    fn rlp_append(&self, s: &mut RlpStream) {
264        s.begin_list(9);
265        s.append(&self.nonce);
266        s.append(&self.gas_price);
267        s.append(&self.gas_limit);
268        s.append(&self.action);
269        s.append(&self.value);
270        s.append(&self.input);
271        s.append(&self.signature.v);
272        s.append(&self.signature.r);
273        s.append(&self.signature.s);
274    }
275}
276
277impl Decodable for Transaction {
278    fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
279        Ok(Self {
280            nonce: rlp.val_at(0)?,
281            gas_price: rlp.val_at(1)?,
282            gas_limit: rlp.val_at(2)?,
283            action: rlp.val_at(3)?,
284            value: rlp.val_at(4)?,
285            input: rlp.val_at(5)?,
286            signature: TransactionSignature {
287                v: rlp.val_at(6)?,
288                r: rlp.val_at(7)?,
289                s: rlp.val_at(8)?,
290            },
291        })
292    }
293}
294
295impl RlpHash for Transaction {
296    fn rlp_hash(&self) -> H256 {
297        H256::from(Keccak256::digest(&rlp::encode(self)).as_slice())
298    }
299}
300
301#[cfg(test)]
302mod tests {
303    use secp256k1::SECP256K1;
304    use secp256k1::key::SecretKey;
305    use bigint::{Address, Gas, U256};
306    use address::FromKey;
307    use rand::os::OsRng;
308    use super::{UnsignedTransaction, TransactionAction, ClassicSignaturePatch,
309                HomesteadValidationPatch};
310
311    #[test]
312    pub fn should_recover_address() {
313        let mut rng = OsRng::new().unwrap();
314        let secret_key = SecretKey::new(&SECP256K1, &mut rng);
315        let address = Address::from_secret_key(&secret_key);
316
317        let unsigned = UnsignedTransaction {
318            nonce: U256::zero(),
319            gas_price: Gas::zero(),
320            gas_limit: Gas::zero(),
321            action: TransactionAction::Create,
322            value: U256::zero(),
323            input: Vec::new()
324        };
325        let signed = unsigned.sign::<ClassicSignaturePatch>(&secret_key);
326
327        assert_eq!(signed.signature.chain_id(), Some(61));
328        assert!(signed.is_basic_valid::<ClassicSignaturePatch, HomesteadValidationPatch>());
329        assert_eq!(signed.caller(), address);
330    }
331}