primitives/transaction/
mod.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5// TODO(7702): refactor this file
6
7mod authorization;
8pub mod eth_transaction;
9pub mod native_transaction;
10
11pub use authorization::{
12    extract_7702_payload, AuthorizationList, AuthorizationListItem, AUTH_MAGIC,
13    CODE_PREFIX_7702,
14};
15pub use eth_transaction::{
16    Eip1559Transaction, Eip155Transaction, Eip2930Transaction,
17    Eip7702Transaction, EthereumTransaction,
18};
19pub use native_transaction::{
20    Cip1559Transaction, Cip2930Transaction, NativeTransaction,
21    TypedNativeTransaction,
22};
23use rlp_derive::{RlpDecodable, RlpEncodable};
24
25use crate::{
26    bytes::Bytes,
27    hash::keccak,
28    keylib::{
29        self, public_to_address, recover, verify_public, Public, Secret,
30        Signature,
31    },
32};
33use cfx_types::{
34    cal_contract_address_with_space, Address, AddressSpaceUtil,
35    AddressWithSpace, BigEndianHash, CreateContractAddressType, Space, H160,
36    H256, U256,
37};
38use eth_transaction::eip155_signature;
39use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
40use rlp::{self, Decodable, DecoderError, Encodable, Rlp, RlpStream};
41use serde::{Deserialize, Serialize};
42use std::{
43    error, fmt,
44    ops::{Deref, DerefMut},
45};
46use unexpected::OutOfBounds;
47
48/// Fake address for unsigned transactions.
49pub const UNSIGNED_SENDER: Address = H160([0xff; 20]);
50
51pub const TYPED_NATIVE_TX_PREFIX: &[u8; 3] = b"cfx";
52pub const TYPED_NATIVE_TX_PREFIX_BYTE: u8 = TYPED_NATIVE_TX_PREFIX[0];
53pub const LEGACY_TX_TYPE: u8 = 0x00;
54pub const EIP2930_TYPE: u8 = 0x01;
55pub const EIP1559_TYPE: u8 = 0x02;
56pub const EIP7702_TYPE: u8 = 0x04;
57pub const CIP2930_TYPE: u8 = 0x01;
58pub const CIP1559_TYPE: u8 = 0x02;
59
60/// Shorter id for transactions in compact blocks
61// TODO should be u48
62pub type TxShortId = u64;
63
64pub type TxPropagateId = u32;
65
66// FIXME: Most errors here are bounded for TransactionPool and intended for rpc,
67// FIXME: however these are unused, they are not errors for transaction itself.
68// FIXME: Transaction verification and consensus related error can be separated.
69#[derive(Debug, PartialEq, Clone, Eq)]
70/// Errors concerning transaction processing.
71pub enum TransactionError {
72    /// Transaction is already imported to the queue
73    AlreadyImported,
74    /// Chain id in the transaction doesn't match the chain id of the network.
75    ChainIdMismatch {
76        expected: u32,
77        got: u32,
78        space: Space,
79    },
80    /// Epoch height out of bound.
81    EpochHeightOutOfBound {
82        block_height: u64,
83        set: u64,
84        transaction_epoch_bound: u64,
85    },
86    /// The gas paid for transaction is lower than base gas.
87    NotEnoughBaseGas {
88        /// Absolute minimum gas required.
89        required: U256,
90        /// Gas provided.
91        got: U256,
92    },
93    /// Transaction is not valid anymore (state already has higher nonce)
94    Stale,
95    /// Transaction has too low fee
96    /// (there is already a transaction with the same sender-nonce but higher
97    /// gas price)
98    TooCheapToReplace,
99    /// Transaction was not imported to the queue because limit has been
100    /// reached.
101    LimitReached,
102    /// Transaction's gas price is below threshold.
103    InsufficientGasPrice {
104        /// Minimal expected gas price
105        minimal: U256,
106        /// Transaction gas price
107        got: U256,
108    },
109    /// Transaction's gas is below currently set minimal gas requirement.
110    InsufficientGas {
111        /// Minimal expected gas
112        minimal: U256,
113        /// Transaction gas
114        got: U256,
115    },
116    /// Sender doesn't have enough funds to pay for this transaction
117    InsufficientBalance {
118        /// Senders balance
119        balance: U256,
120        /// Transaction cost
121        cost: U256,
122    },
123    /// Transactions gas is higher then current gas limit
124    GasLimitExceeded {
125        /// Current gas limit
126        limit: U256,
127        /// Declared transaction gas
128        got: U256,
129    },
130    /// Transaction's gas limit (aka gas) is invalid.
131    InvalidGasLimit(OutOfBounds<U256>),
132    /// Signature error
133    InvalidSignature(String),
134    /// Transaction too big
135    TooBig,
136    /// Invalid RLP encoding
137    InvalidRlp(String),
138    ZeroGasPrice,
139    /// Transaction types have not been activated
140    FutureTransactionType {
141        tx_type: u8,
142        enable_height: u64,
143        current_height: u64,
144    },
145    /// Create transaction with too large init code size,
146    CreateInitCodeSizeLimit,
147    /// Receiver with invalid type bit.
148    InvalidReceiver,
149    /// Transaction nonce exceeds local limit.
150    TooLargeNonce,
151    /// Empty authorization list (EIP-7702)
152    EmptyAuthorizationList,
153    /// Max priority fee greater than max fee (EIP-1559)
154    PriortyGreaterThanMaxFee,
155}
156
157impl From<keylib::Error> for TransactionError {
158    fn from(err: keylib::Error) -> Self {
159        TransactionError::InvalidSignature(format!("{}", err))
160    }
161}
162
163impl From<rlp::DecoderError> for TransactionError {
164    fn from(err: rlp::DecoderError) -> Self {
165        TransactionError::InvalidRlp(format!("{}", err))
166    }
167}
168
169impl fmt::Display for TransactionError {
170    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171        use self::TransactionError::*;
172        let msg = match *self {
173            AlreadyImported => "Already imported".into(),
174            ChainIdMismatch { expected, got, space } => {
175                format!("Chain id mismatch, expected {}, got {}, space {:?}", expected, got, space)
176            }
177            EpochHeightOutOfBound {
178                block_height,
179                set,
180                transaction_epoch_bound,
181            } => format!(
182                "EpochHeight out of bound:\
183                 block_height {}, transaction epoch_height {}, transaction_epoch_bound {}",
184                block_height, set, transaction_epoch_bound
185            ),
186            NotEnoughBaseGas { got, required } => format!(
187                "Transaction gas {} less than intrinsic gas {}",
188                got, required
189            ),
190            Stale => "No longer valid".into(),
191            TooCheapToReplace => "Gas price too low to replace".into(),
192            LimitReached => "Transaction limit reached".into(),
193            InsufficientGasPrice { minimal, got } => format!(
194                "Insufficient gas price. Min={}, Given={}",
195                minimal, got
196            ),
197            InsufficientGas { minimal, got } => {
198                format!("Insufficient gas. Min={}, Given={}", minimal, got)
199            }
200            InsufficientBalance { balance, cost } => format!(
201                "Insufficient balance for transaction. Balance={}, Cost={}",
202                balance, cost
203            ),
204            GasLimitExceeded { limit, got } => {
205                format!("Gas limit exceeded. Limit={}, Given={}", limit, got)
206            }
207            InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
208            InvalidSignature(ref err) => {
209                format!("Transaction has invalid signature: {}.", err)
210            }
211            TooBig => "Transaction too big".into(),
212            InvalidRlp(ref err) => {
213                format!("Transaction has invalid RLP structure: {}.", err)
214            }
215            ZeroGasPrice => "Zero gas price is not allowed".into(),
216            FutureTransactionType {tx_type, current_height, enable_height} => format!("Transaction type {tx_type} is not enabled, current height {current_height}, enable height {enable_height}"),
217            InvalidReceiver => "Sending transaction to invalid address. The first four bits of address must be 0x0, 0x1, or 0x8.".into(),
218            TooLargeNonce => "Transaction nonce is too large.".into(),
219            CreateInitCodeSizeLimit => "Transaction initcode is too large.".into(),
220            EmptyAuthorizationList => "Empty authorization list".into(),
221            PriortyGreaterThanMaxFee => "Max priority fee greater than max fee".into(),
222        };
223
224        f.write_fmt(format_args!("Transaction error ({})", msg))
225    }
226}
227
228impl error::Error for TransactionError {
229    fn description(&self) -> &str { "Transaction error" }
230}
231
232#[derive(
233    Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default,
234)]
235pub enum Action {
236    /// Create creates new contract.
237    #[default]
238    Create,
239    /// Calls contract at given address.
240    /// In the case of a transfer, this is the receiver's address.'
241    Call(Address),
242}
243
244impl Decodable for Action {
245    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
246        if rlp.is_empty() {
247            Ok(Action::Create)
248        } else {
249            Ok(Action::Call(rlp.as_val()?))
250        }
251    }
252}
253
254impl Encodable for Action {
255    fn rlp_append(&self, stream: &mut RlpStream) {
256        match *self {
257            Action::Create => stream.append_internal(&""),
258            Action::Call(ref address) => stream.append_internal(address),
259        };
260    }
261}
262
263#[derive(
264    Debug,
265    Clone,
266    PartialEq,
267    Eq,
268    Serialize,
269    Deserialize,
270    RlpEncodable,
271    RlpDecodable,
272)]
273#[serde(rename_all = "camelCase")]
274pub struct AccessListItem {
275    pub address: Address,
276    pub storage_keys: Vec<H256>,
277}
278
279pub type AccessList = Vec<AccessListItem>;
280
281#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
282pub enum Transaction {
283    Native(TypedNativeTransaction),
284    Ethereum(EthereumTransaction),
285}
286
287impl Default for Transaction {
288    fn default() -> Self {
289        Transaction::Native(TypedNativeTransaction::Cip155(Default::default()))
290    }
291}
292
293impl From<NativeTransaction> for Transaction {
294    fn from(tx: NativeTransaction) -> Self {
295        Self::Native(TypedNativeTransaction::Cip155(tx))
296    }
297}
298
299impl From<Eip155Transaction> for Transaction {
300    fn from(tx: Eip155Transaction) -> Self {
301        Self::Ethereum(EthereumTransaction::Eip155(tx))
302    }
303}
304
305macro_rules! access_common_ref {
306    ($field:ident, $ty:ty) => {
307        pub fn $field(&self) -> &$ty {
308            match self {
309                Transaction::Native(tx) => tx.$field(),
310                Transaction::Ethereum(tx) => tx.$field(),
311            }
312        }
313    };
314}
315
316macro_rules! access_common {
317    ($field:ident, $ty:ident) => {
318        pub fn $field(&self) -> $ty {
319            match self {
320                Transaction::Native(tx) => tx.$field(),
321                Transaction::Ethereum(tx) => tx.$field(),
322            }
323        }
324    };
325}
326
327impl Transaction {
328    access_common_ref!(gas, U256);
329
330    access_common_ref!(gas_price, U256);
331
332    access_common_ref!(max_priority_gas_price, U256);
333
334    access_common_ref!(data, Bytes);
335
336    access_common_ref!(nonce, U256);
337
338    access_common!(action, Action);
339
340    access_common_ref!(value, U256);
341
342    pub fn chain_id(&self) -> Option<u32> {
343        match self {
344            Transaction::Native(tx) => Some(*tx.chain_id()),
345            Transaction::Ethereum(tx) => tx.chain_id(),
346        }
347    }
348
349    pub fn storage_limit(&self) -> Option<u64> {
350        match self {
351            Transaction::Native(tx) => Some(*tx.storage_limit()),
352            Transaction::Ethereum(_tx) => None,
353        }
354    }
355
356    pub fn nonce_mut(&mut self) -> &mut U256 {
357        match self {
358            Transaction::Native(tx) => tx.nonce_mut(),
359            Transaction::Ethereum(tx) => tx.nonce_mut(),
360        }
361    }
362
363    pub fn data_mut(&mut self) -> &mut Vec<u8> {
364        match self {
365            Transaction::Native(tx) => tx.data_mut(),
366            Transaction::Ethereum(tx) => tx.data_mut(),
367        }
368    }
369
370    pub fn type_id(&self) -> u8 {
371        match self {
372            Transaction::Native(TypedNativeTransaction::Cip155(_))
373            | Transaction::Ethereum(EthereumTransaction::Eip155(_)) => 0,
374
375            Transaction::Native(TypedNativeTransaction::Cip2930(_))
376            | Transaction::Ethereum(EthereumTransaction::Eip2930(_)) => 1,
377
378            Transaction::Native(TypedNativeTransaction::Cip1559(_))
379            | Transaction::Ethereum(EthereumTransaction::Eip1559(_)) => 2,
380
381            Transaction::Ethereum(EthereumTransaction::Eip7702(_)) => 4,
382        }
383    }
384
385    pub fn is_legacy(&self) -> bool {
386        matches!(
387            self,
388            Transaction::Native(TypedNativeTransaction::Cip155(_))
389                | Transaction::Ethereum(EthereumTransaction::Eip155(_))
390        )
391    }
392
393    pub fn is_2718(&self) -> bool { !self.is_legacy() }
394
395    pub fn after_1559(&self) -> bool {
396        use EthereumTransaction::*;
397        use TypedNativeTransaction::*;
398        matches!(
399            self,
400            Transaction::Native(Cip1559(_))
401                | Transaction::Ethereum(Eip1559(_) | Eip7702(_))
402        )
403    }
404
405    pub fn after_7702(&self) -> bool {
406        matches!(self, Transaction::Ethereum(EthereumTransaction::Eip7702(_)))
407    }
408
409    pub fn access_list(&self) -> Option<&AccessList> {
410        match self {
411            Transaction::Native(tx) => tx.access_list(),
412            Transaction::Ethereum(tx) => tx.access_list(),
413        }
414    }
415
416    pub fn authorization_list(&self) -> Option<&AuthorizationList> {
417        match self {
418            Transaction::Native(_tx) => None,
419            Transaction::Ethereum(tx) => tx.authorization_list(),
420        }
421    }
422
423    pub fn authorization_len(&self) -> usize {
424        self.authorization_list().map_or(0, Vec::len)
425    }
426}
427
428impl Transaction {
429    pub fn priority_gas_price(&self, base_price: &U256) -> U256 {
430        std::cmp::min(
431            *self.max_priority_gas_price(),
432            self.gas_price() - base_price,
433        )
434    }
435
436    pub fn effective_gas_price(&self, base_price: &U256) -> U256 {
437        base_price + self.priority_gas_price(base_price)
438    }
439
440    // This function returns the hash value used in calculating the transaction
441    // signature. It is different from transaction hash. The transaction
442    // hash also contains signatures.
443    pub fn hash_for_compute_signature(&self) -> H256 {
444        let mut s = RlpStream::new();
445        let mut type_prefix = vec![];
446        match self {
447            Transaction::Native(TypedNativeTransaction::Cip155(tx)) => {
448                s.append(tx);
449            }
450            Transaction::Native(TypedNativeTransaction::Cip1559(tx)) => {
451                s.append(tx);
452                type_prefix.extend_from_slice(TYPED_NATIVE_TX_PREFIX);
453                type_prefix.push(CIP1559_TYPE);
454            }
455            Transaction::Native(TypedNativeTransaction::Cip2930(tx)) => {
456                s.append(tx);
457                type_prefix.extend_from_slice(TYPED_NATIVE_TX_PREFIX);
458                type_prefix.push(CIP2930_TYPE);
459            }
460            Transaction::Ethereum(EthereumTransaction::Eip155(tx)) => {
461                s.append(tx);
462            }
463            Transaction::Ethereum(EthereumTransaction::Eip1559(tx)) => {
464                s.append(tx);
465                type_prefix.push(EIP1559_TYPE);
466            }
467            Transaction::Ethereum(EthereumTransaction::Eip2930(tx)) => {
468                s.append(tx);
469                type_prefix.push(EIP2930_TYPE);
470            }
471            Transaction::Ethereum(EthereumTransaction::Eip7702(tx)) => {
472                s.append(tx);
473                type_prefix.push(EIP7702_TYPE);
474            }
475        };
476        let encoded = s.as_raw();
477        let mut out = vec![0; type_prefix.len() + encoded.len()];
478        out[0..type_prefix.len()].copy_from_slice(&type_prefix);
479        out[type_prefix.len()..].copy_from_slice(encoded);
480        keccak(&out)
481    }
482
483    pub fn space(&self) -> Space {
484        match self {
485            Transaction::Native(_) => Space::Native,
486            Transaction::Ethereum(_) => Space::Ethereum,
487        }
488    }
489
490    pub fn sign(self, secret: &Secret) -> SignedTransaction {
491        let sig =
492            crate::keylib::sign(secret, &self.hash_for_compute_signature())
493                .expect(
494                    "data is valid and context has signing capabilities; qed",
495                );
496        let tx_with_sig = self.with_signature(sig);
497        let public = tx_with_sig
498            .recover_public()
499            .expect("secret is valid so it's recoverable");
500        SignedTransaction::new(public, tx_with_sig)
501    }
502
503    /// Signs the transaction with signature.
504    pub fn with_signature(self, sig: Signature) -> TransactionWithSignature {
505        TransactionWithSignature {
506            transaction: TransactionWithSignatureSerializePart {
507                unsigned: self,
508                r: U256::from_big_endian(sig.r()),
509                s: U256::from_big_endian(sig.s()),
510                v: sig.v(),
511            },
512            hash: H256::zero(),
513            rlp_size: None,
514        }
515        .compute_hash()
516    }
517}
518
519impl MallocSizeOf for Transaction {
520    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
521        self.data().size_of(ops)
522    }
523}
524
525/// Signed transaction information without verified signature.
526#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
527pub struct TransactionWithSignatureSerializePart {
528    /// Plain Transaction.
529    pub unsigned: Transaction,
530    /// The V field of the signature; helps describe which half of the curve
531    /// our point falls in.
532    pub v: u8,
533    /// The R field of the signature; helps describe the point on the curve.
534    pub r: U256,
535    /// The S field of the signature; helps describe the point on the curve.
536    pub s: U256,
537}
538
539impl Encodable for TransactionWithSignatureSerializePart {
540    fn rlp_append(&self, s: &mut RlpStream) {
541        match self.unsigned {
542            Transaction::Native(TypedNativeTransaction::Cip155(ref tx)) => {
543                s.begin_list(4);
544                s.append(tx);
545                s.append(&self.v);
546                s.append(&self.r);
547                s.append(&self.s);
548            }
549            Transaction::Ethereum(EthereumTransaction::Eip155(ref tx)) => {
550                let Eip155Transaction {
551                    nonce,
552                    gas_price,
553                    gas,
554                    action,
555                    value,
556                    data,
557                    chain_id,
558                } = tx;
559                let legacy_v = eip155_signature::add_chain_replay_protection(
560                    self.v,
561                    chain_id.map(|x| x as u64),
562                );
563                s.begin_list(9);
564                s.append(nonce);
565                s.append(gas_price);
566                s.append(gas);
567                s.append(action);
568                s.append(value);
569                s.append(data);
570                s.append(&legacy_v);
571                s.append(&self.r);
572                s.append(&self.s);
573            }
574            Transaction::Ethereum(EthereumTransaction::Eip2930(ref tx)) => {
575                s.append_raw(&[EIP2930_TYPE], 0);
576                s.begin_list(11);
577                s.append(&tx.chain_id);
578                s.append(&tx.nonce);
579                s.append(&tx.gas_price);
580                s.append(&tx.gas);
581                s.append(&tx.action);
582                s.append(&tx.value);
583                s.append(&tx.data);
584                s.append_list(&tx.access_list);
585                s.append(&self.v);
586                s.append(&self.r);
587                s.append(&self.s);
588            }
589            Transaction::Ethereum(EthereumTransaction::Eip1559(ref tx)) => {
590                s.append_raw(&[EIP1559_TYPE], 0);
591                s.begin_list(12);
592                s.append(&tx.chain_id);
593                s.append(&tx.nonce);
594                s.append(&tx.max_priority_fee_per_gas);
595                s.append(&tx.max_fee_per_gas);
596                s.append(&tx.gas);
597                s.append(&tx.action);
598                s.append(&tx.value);
599                s.append(&tx.data);
600                s.append_list(&tx.access_list);
601                s.append(&self.v);
602                s.append(&self.r);
603                s.append(&self.s);
604            }
605            Transaction::Ethereum(EthereumTransaction::Eip7702(ref tx)) => {
606                s.append_raw(&[EIP7702_TYPE], 0);
607                s.begin_list(13);
608                s.append(&tx.chain_id);
609                s.append(&tx.nonce);
610                s.append(&tx.max_priority_fee_per_gas);
611                s.append(&tx.max_fee_per_gas);
612                s.append(&tx.gas);
613                s.append(&tx.destination);
614                s.append(&tx.value);
615                s.append(&tx.data);
616                s.append_list(&tx.access_list);
617                s.append_list(&tx.authorization_list);
618                s.append(&self.v);
619                s.append(&self.r);
620                s.append(&self.s);
621            }
622            Transaction::Native(TypedNativeTransaction::Cip2930(ref tx)) => {
623                s.append_raw(TYPED_NATIVE_TX_PREFIX, 0);
624                s.append_raw(&[CIP2930_TYPE], 0);
625                s.begin_list(4);
626                s.append(tx);
627                s.append(&self.v);
628                s.append(&self.r);
629                s.append(&self.s);
630            }
631            Transaction::Native(TypedNativeTransaction::Cip1559(ref tx)) => {
632                s.append_raw(TYPED_NATIVE_TX_PREFIX, 0);
633                s.append_raw(&[CIP1559_TYPE], 0);
634                s.begin_list(4);
635                s.append(tx);
636                s.append(&self.v);
637                s.append(&self.r);
638                s.append(&self.s);
639            } /* Transaction::Native(TypedNativeTransaction::Cip7702(ref tx))
640               * => {     s.append_raw(TYPED_NATIVE_TX_PREFIX,
641               * 0);     s.append_raw(&[CIP7702_TYPE], 0);
642               *     s.begin_list(4);
643               *     s.append(tx);
644               *     s.append(&self.v);
645               *     s.append(&self.r);
646               *     s.append(&self.s);
647               * } */
648        }
649    }
650}
651
652// TODO(7702): refactor this implementation.
653impl Decodable for TransactionWithSignatureSerializePart {
654    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
655        if rlp.as_raw().is_empty() {
656            return Err(DecoderError::RlpInvalidLength);
657        }
658        if rlp.is_list() {
659            match rlp.item_count()? {
660                4 => {
661                    let unsigned: NativeTransaction = rlp.val_at(0)?;
662                    let v: u8 = rlp.val_at(1)?;
663                    let r: U256 = rlp.val_at(2)?;
664                    let s: U256 = rlp.val_at(3)?;
665                    Ok(TransactionWithSignatureSerializePart {
666                        unsigned: Transaction::Native(
667                            TypedNativeTransaction::Cip155(unsigned),
668                        ),
669                        v,
670                        r,
671                        s,
672                    })
673                }
674                9 => {
675                    let nonce: U256 = rlp.val_at(0)?;
676                    let gas_price: U256 = rlp.val_at(1)?;
677                    let gas: U256 = rlp.val_at(2)?;
678                    let action: Action = rlp.val_at(3)?;
679                    let value: U256 = rlp.val_at(4)?;
680                    let data: Vec<u8> = rlp.val_at(5)?;
681                    let legacy_v: u64 = rlp.val_at(6)?;
682                    let r: U256 = rlp.val_at(7)?;
683                    let s: U256 = rlp.val_at(8)?;
684
685                    let v = eip155_signature::extract_standard_v(legacy_v);
686                    let chain_id =
687                        match eip155_signature::extract_chain_id_from_legacy_v(
688                            legacy_v,
689                        ) {
690                            Some(chain_id) if chain_id > (u32::MAX as u64) => {
691                                return Err(DecoderError::Custom(
692                                    "Does not support chain_id >= 2^32",
693                                ));
694                            }
695                            chain_id => chain_id.map(|x| x as u32),
696                        };
697
698                    Ok(TransactionWithSignatureSerializePart {
699                        unsigned: Transaction::Ethereum(
700                            EthereumTransaction::Eip155(Eip155Transaction {
701                                nonce,
702                                gas_price,
703                                gas,
704                                action,
705                                value,
706                                chain_id,
707                                data,
708                            }),
709                        ),
710                        v,
711                        r,
712                        s,
713                    })
714                }
715                _ => Err(DecoderError::RlpInvalidLength),
716            }
717        } else {
718            match rlp.as_raw()[0] {
719                TYPED_NATIVE_TX_PREFIX_BYTE => {
720                    if rlp.as_raw().len() <= 4
721                        || rlp.as_raw()[0..3] != *TYPED_NATIVE_TX_PREFIX
722                    {
723                        return Err(DecoderError::RlpInvalidLength);
724                    }
725                    match rlp.as_raw()[3] {
726                        CIP2930_TYPE => {
727                            let rlp = Rlp::new(&rlp.as_raw()[4..]);
728                            if rlp.item_count()? != 4 {
729                                return Err(DecoderError::RlpIncorrectListLen);
730                            }
731
732                            let tx = rlp.val_at(0)?;
733                            let v = rlp.val_at(1)?;
734                            let r = rlp.val_at(2)?;
735                            let s = rlp.val_at(3)?;
736                            Ok(TransactionWithSignatureSerializePart {
737                                unsigned: Transaction::Native(
738                                    TypedNativeTransaction::Cip2930(tx),
739                                ),
740                                v,
741                                r,
742                                s,
743                            })
744                        }
745                        CIP1559_TYPE => {
746                            let rlp = Rlp::new(&rlp.as_raw()[4..]);
747                            if rlp.item_count()? != 4 {
748                                return Err(DecoderError::RlpIncorrectListLen);
749                            }
750
751                            let tx = rlp.val_at(0)?;
752                            let v = rlp.val_at(1)?;
753                            let r = rlp.val_at(2)?;
754                            let s = rlp.val_at(3)?;
755                            Ok(TransactionWithSignatureSerializePart {
756                                unsigned: Transaction::Native(
757                                    TypedNativeTransaction::Cip1559(tx),
758                                ),
759                                v,
760                                r,
761                                s,
762                            })
763                        }
764                        _ => Err(DecoderError::RlpInvalidLength),
765                    }
766                }
767                EIP2930_TYPE => {
768                    let rlp = Rlp::new(&rlp.as_raw()[1..]);
769                    if rlp.item_count()? != 11 {
770                        return Err(DecoderError::RlpIncorrectListLen);
771                    }
772
773                    let tx = Eip2930Transaction {
774                        chain_id: rlp.val_at(0)?,
775                        nonce: rlp.val_at(1)?,
776                        gas_price: rlp.val_at(2)?,
777                        gas: rlp.val_at(3)?,
778                        action: rlp.val_at(4)?,
779                        value: rlp.val_at(5)?,
780                        data: rlp.val_at(6)?,
781                        access_list: rlp.list_at(7)?,
782                    };
783                    let v = rlp.val_at(8)?;
784                    let r = rlp.val_at(9)?;
785                    let s = rlp.val_at(10)?;
786                    Ok(TransactionWithSignatureSerializePart {
787                        unsigned: Transaction::Ethereum(
788                            EthereumTransaction::Eip2930(tx),
789                        ),
790                        v,
791                        r,
792                        s,
793                    })
794                }
795                EIP1559_TYPE => {
796                    let rlp = Rlp::new(&rlp.as_raw()[1..]);
797                    if rlp.item_count()? != 12 {
798                        return Err(DecoderError::RlpIncorrectListLen);
799                    }
800
801                    let tx = Eip1559Transaction {
802                        chain_id: rlp.val_at(0)?,
803                        nonce: rlp.val_at(1)?,
804                        max_priority_fee_per_gas: rlp.val_at(2)?,
805                        max_fee_per_gas: rlp.val_at(3)?,
806                        gas: rlp.val_at(4)?,
807                        action: rlp.val_at(5)?,
808                        value: rlp.val_at(6)?,
809                        data: rlp.val_at(7)?,
810                        access_list: rlp.list_at(8)?,
811                    };
812                    let v = rlp.val_at(9)?;
813                    let r = rlp.val_at(10)?;
814                    let s = rlp.val_at(11)?;
815                    Ok(TransactionWithSignatureSerializePart {
816                        unsigned: Transaction::Ethereum(
817                            EthereumTransaction::Eip1559(tx),
818                        ),
819                        v,
820                        r,
821                        s,
822                    })
823                }
824                EIP7702_TYPE => {
825                    let rlp = Rlp::new(&rlp.as_raw()[1..]);
826                    if rlp.item_count()? != 13 {
827                        return Err(DecoderError::RlpIncorrectListLen);
828                    }
829
830                    let tx = Eip7702Transaction {
831                        chain_id: rlp.val_at(0)?,
832                        nonce: rlp.val_at(1)?,
833                        max_priority_fee_per_gas: rlp.val_at(2)?,
834                        max_fee_per_gas: rlp.val_at(3)?,
835                        gas: rlp.val_at(4)?,
836                        destination: rlp.val_at(5)?,
837                        value: rlp.val_at(6)?,
838                        data: rlp.val_at(7)?,
839                        access_list: rlp.list_at(8)?,
840                        authorization_list: rlp.list_at(9)?,
841                    };
842                    let v = rlp.val_at(10)?;
843                    let r = rlp.val_at(11)?;
844                    let s = rlp.val_at(12)?;
845                    Ok(TransactionWithSignatureSerializePart {
846                        unsigned: Transaction::Ethereum(
847                            EthereumTransaction::Eip7702(tx),
848                        ),
849                        v,
850                        r,
851                        s,
852                    })
853                }
854                _ => Err(DecoderError::RlpInvalidLength),
855            }
856        }
857    }
858}
859
860impl Deref for TransactionWithSignatureSerializePart {
861    type Target = Transaction;
862
863    fn deref(&self) -> &Self::Target { &self.unsigned }
864}
865
866impl DerefMut for TransactionWithSignatureSerializePart {
867    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.unsigned }
868}
869
870/// Signed transaction information without verified signature.
871#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
872pub struct TransactionWithSignature {
873    /// Serialize part.
874    pub transaction: TransactionWithSignatureSerializePart,
875    /// Hash of the transaction
876    #[serde(skip)]
877    pub hash: H256,
878    /// The transaction size when serialized in rlp
879    #[serde(skip)]
880    pub rlp_size: Option<usize>,
881}
882
883impl Deref for TransactionWithSignature {
884    type Target = TransactionWithSignatureSerializePart;
885
886    fn deref(&self) -> &Self::Target { &self.transaction }
887}
888
889impl DerefMut for TransactionWithSignature {
890    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.transaction }
891}
892
893impl Decodable for TransactionWithSignature {
894    fn decode(tx_rlp: &Rlp) -> Result<Self, DecoderError> {
895        let rlp_size = Some(tx_rlp.as_raw().len());
896        // The item count of TransactionWithSignatureSerializePart is checked in
897        // its decoding.
898        let hash;
899        let transaction;
900        if tx_rlp.is_list() {
901            hash = keccak(tx_rlp.as_raw());
902            // Vanilla tx encoding.
903            transaction = tx_rlp.as_val()?;
904        } else {
905            // Typed tx encoding is wrapped as an RLP string.
906            let b: Vec<u8> = tx_rlp.as_val()?;
907            hash = keccak(&b);
908            transaction = rlp::decode(&b)?;
909        };
910        Ok(TransactionWithSignature {
911            transaction,
912            hash,
913            rlp_size,
914        })
915    }
916}
917
918impl Encodable for TransactionWithSignature {
919    fn rlp_append(&self, s: &mut RlpStream) {
920        match &self.transaction.unsigned {
921            Transaction::Native(TypedNativeTransaction::Cip155(_))
922            | Transaction::Ethereum(EthereumTransaction::Eip155(_)) => {
923                s.append_internal(&self.transaction);
924            }
925            _ => {
926                // Typed tx encoding is wrapped as an RLP string.
927                s.append_internal(&rlp::encode(&self.transaction));
928            }
929        }
930    }
931}
932
933impl TransactionWithSignature {
934    pub fn new_unsigned(tx: Transaction) -> Self {
935        TransactionWithSignature {
936            transaction: TransactionWithSignatureSerializePart {
937                unsigned: tx,
938                s: 0.into(),
939                r: 0.into(),
940                v: 0,
941            },
942            hash: Default::default(),
943            rlp_size: None,
944        }
945    }
946
947    /// keccak of the canonical RLP re-encoding — unlike `hash`, which is over
948    /// the (possibly non-canonical) bytes the tx was decoded from.
949    pub fn canonical_hash(&self) -> H256 {
950        keccak(&*self.transaction.rlp_bytes())
951    }
952
953    fn compute_hash(mut self) -> TransactionWithSignature {
954        self.hash = self.canonical_hash();
955        self
956    }
957
958    /// Checks whether signature is empty.
959    pub fn is_unsigned(&self) -> bool { self.r.is_zero() && self.s.is_zero() }
960
961    /// Construct a signature object from the sig.
962    pub fn signature(&self) -> Signature {
963        let r: H256 = BigEndianHash::from_uint(&self.r);
964        let s: H256 = BigEndianHash::from_uint(&self.s);
965        Signature::from_rsv(&r, &s, self.v)
966    }
967
968    /// Checks whether the signature has a low 's' value.
969    pub fn check_low_s(&self) -> Result<(), keylib::Error> {
970        if !self.signature().is_low_s() {
971            Err(keylib::Error::InvalidSignature)
972        } else {
973            Ok(())
974        }
975    }
976
977    pub fn check_y_parity(&self) -> Result<(), keylib::Error> {
978        if self.is_2718() && self.v > 1 {
979            // In Typed transactions (EIP-2718), v means y_parity, which must be
980            // 0 or 1
981            Err(keylib::Error::InvalidYParity)
982        } else {
983            Ok(())
984        }
985    }
986
987    pub fn hash(&self) -> H256 { self.hash }
988
989    /// False when the lenient decoder accepted a non-canonical encoding (e.g. a
990    /// trailing partial item): same fields, different cached hash.
991    pub fn is_canonical_rlp(&self) -> bool {
992        self.hash == self.canonical_hash()
993    }
994
995    /// Recovers the public key of the sender.
996    pub fn recover_public(&self) -> Result<Public, keylib::Error> {
997        recover(
998            &self.signature(),
999            &self.unsigned.hash_for_compute_signature(),
1000        )
1001    }
1002
1003    pub fn rlp_size(&self) -> usize {
1004        self.rlp_size.unwrap_or_else(|| self.rlp_bytes().len())
1005    }
1006
1007    pub fn from_raw(raw: &[u8]) -> Result<Self, DecoderError> {
1008        Ok(TransactionWithSignature {
1009            transaction: Rlp::new(raw).as_val()?,
1010            hash: keccak(raw),
1011            rlp_size: Some(raw.len()),
1012        })
1013    }
1014}
1015
1016impl MallocSizeOf for TransactionWithSignature {
1017    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1018        self.unsigned.size_of(ops)
1019    }
1020}
1021
1022/// A signed transaction with successfully recovered `sender`.
1023#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1024pub struct SignedTransaction {
1025    pub transaction: TransactionWithSignature,
1026    pub sender: Address,
1027    pub public: Option<Public>,
1028}
1029
1030// The default encoder for local storage.
1031impl Encodable for SignedTransaction {
1032    fn rlp_append(&self, s: &mut RlpStream) {
1033        s.begin_list(3);
1034        s.append(&self.transaction);
1035        s.append(&self.sender);
1036        s.append(&self.public);
1037    }
1038}
1039
1040impl Decodable for SignedTransaction {
1041    fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
1042        Ok(SignedTransaction {
1043            transaction: rlp.val_at(0)?,
1044            sender: rlp.val_at(1)?,
1045            public: rlp.val_at(2)?,
1046        })
1047    }
1048}
1049
1050impl Deref for SignedTransaction {
1051    type Target = TransactionWithSignature;
1052
1053    fn deref(&self) -> &Self::Target { &self.transaction }
1054}
1055
1056impl DerefMut for SignedTransaction {
1057    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.transaction }
1058}
1059
1060impl From<SignedTransaction> for TransactionWithSignature {
1061    fn from(tx: SignedTransaction) -> Self { tx.transaction }
1062}
1063
1064impl SignedTransaction {
1065    /// Try to verify transaction and recover sender.
1066    pub fn new(public: Public, transaction: TransactionWithSignature) -> Self {
1067        if transaction.is_unsigned() {
1068            SignedTransaction {
1069                transaction,
1070                sender: UNSIGNED_SENDER,
1071                public: None,
1072            }
1073        } else {
1074            let sender = public_to_address(
1075                &public,
1076                transaction.space() == Space::Native,
1077            );
1078            SignedTransaction {
1079                transaction,
1080                sender,
1081                public: Some(public),
1082            }
1083        }
1084    }
1085
1086    pub fn new_unsigned(transaction: TransactionWithSignature) -> Self {
1087        SignedTransaction {
1088            transaction,
1089            sender: UNSIGNED_SENDER,
1090            public: None,
1091        }
1092    }
1093
1094    pub fn set_public(&mut self, public: Public) {
1095        let type_nibble = self.unsigned.space() == Space::Native;
1096        self.sender = public_to_address(&public, type_nibble);
1097        self.public = Some(public);
1098    }
1099
1100    /// Returns transaction sender.
1101    pub fn sender(&self) -> AddressWithSpace {
1102        self.sender.with_space(self.space())
1103    }
1104
1105    pub fn nonce(&self) -> &U256 { self.transaction.nonce() }
1106
1107    /// Checks if signature is empty.
1108    pub fn is_unsigned(&self) -> bool { self.transaction.is_unsigned() }
1109
1110    pub fn hash(&self) -> H256 { self.transaction.hash() }
1111
1112    pub fn gas(&self) -> &U256 { self.transaction.gas() }
1113
1114    pub fn gas_price(&self) -> &U256 { self.transaction.gas_price() }
1115
1116    pub fn gas_limit(&self) -> &U256 { self.transaction.gas() }
1117
1118    pub fn storage_limit(&self) -> Option<u64> {
1119        self.transaction.storage_limit()
1120    }
1121
1122    pub fn rlp_size(&self) -> usize { self.transaction.rlp_size() }
1123
1124    pub fn public(&self) -> &Option<Public> { &self.public }
1125
1126    pub fn verify_public(&self, skip: bool) -> Result<bool, keylib::Error> {
1127        if self.public.is_none() {
1128            return Ok(false);
1129        }
1130
1131        if !skip {
1132            let public = self.public.unwrap();
1133            Ok(verify_public(
1134                &public,
1135                &self.signature(),
1136                &self.unsigned.hash_for_compute_signature(),
1137            )?)
1138        } else {
1139            Ok(true)
1140        }
1141    }
1142
1143    // Calculates the created contract address if the transaction is a contract
1144    // creation.
1145    pub fn cal_created_address(&self) -> Option<AddressWithSpace> {
1146        if let Action::Create = self.action() {
1147            let from = self.sender();
1148            let nonce = self.nonce();
1149            let space = self.space();
1150            let create_type = match space {
1151                Space::Native => {
1152                    CreateContractAddressType::FromSenderNonceAndCodeHash
1153                }
1154                Space::Ethereum => CreateContractAddressType::FromSenderNonce,
1155            };
1156            let code = self.data().as_slice();
1157            let (created_address, _) = cal_contract_address_with_space(
1158                create_type,
1159                &from,
1160                nonce,
1161                code,
1162            );
1163            Some(created_address)
1164        } else {
1165            None
1166        }
1167    }
1168}
1169
1170impl MallocSizeOf for SignedTransaction {
1171    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1172        self.transaction.size_of(ops)
1173    }
1174}
1175
1176#[cfg(test)]
1177mod canonical_rlp_tests {
1178    use super::*;
1179    use EthereumTransaction::*;
1180    use TypedNativeTransaction::*;
1181
1182    fn part(unsigned: Transaction) -> TransactionWithSignatureSerializePart {
1183        TransactionWithSignatureSerializePart {
1184            unsigned,
1185            v: 1,
1186            r: U256::from(0x1234u64),
1187            s: U256::from(0x5678u64),
1188        }
1189    }
1190
1191    fn is_list_form(p: &TransactionWithSignatureSerializePart) -> bool {
1192        matches!(
1193            p.unsigned,
1194            Transaction::Native(Cip155(_)) | Transaction::Ethereum(Eip155(_))
1195        )
1196    }
1197
1198    // `decode` takes a bare list (legacy) or an RLP-string-wrapped
1199    // `type||list` (typed).
1200    fn wire(p: &TransactionWithSignatureSerializePart) -> Vec<u8> {
1201        let s = rlp::encode(p).to_vec();
1202        if is_list_form(p) {
1203            s
1204        } else {
1205            rlp::encode(&s).to_vec()
1206        }
1207    }
1208
1209    // Non-canonical, same fields: a trailing partial item (0xb8) the decoder
1210    // tolerates; for a list, bump the header length so it stays inside.
1211    fn malleate(p: &TransactionWithSignatureSerializePart) -> Vec<u8> {
1212        let mut s = rlp::encode(p).to_vec();
1213        if is_list_form(p) {
1214            // Only short-form list headers (payload <= 55 bytes) — the
1215            // single-byte length can be bumped. Keep test variants small.
1216            assert!(
1217                (0xc0..=0xf7).contains(&s[0]),
1218                "malleate: long-form list header not supported"
1219            );
1220            s[0] += 1;
1221            s.push(0xb8);
1222            s
1223        } else {
1224            s.push(0xb8);
1225            rlp::encode(&s).to_vec()
1226        }
1227    }
1228
1229    fn assert_predicate(p: TransactionWithSignatureSerializePart) {
1230        let canon: TransactionWithSignature = rlp::decode(&wire(&p)).unwrap();
1231        assert_eq!(canon.transaction, p);
1232        assert!(canon.is_canonical_rlp());
1233
1234        let mall: TransactionWithSignature =
1235            rlp::decode(&malleate(&p)).unwrap();
1236        assert_eq!(mall.transaction, p);
1237        assert!(!mall.is_canonical_rlp());
1238
1239        let raw = rlp::encode(&p).to_vec();
1240        assert!(TransactionWithSignature::from_raw(&raw)
1241            .unwrap()
1242            .is_canonical_rlp());
1243    }
1244
1245    // One case per encoded form: list vs typed-string, Ethereum vs native.
1246    #[test]
1247    fn is_canonical_rlp_all_variants() {
1248        let variants = [
1249            Transaction::Ethereum(Eip155(Eip155Transaction {
1250                chain_id: Some(1),
1251                ..Default::default()
1252            })),
1253            // pre-155: chain_id None -> v = 27/28.
1254            Transaction::Ethereum(Eip155(Eip155Transaction {
1255                chain_id: None,
1256                ..Default::default()
1257            })),
1258            Transaction::Native(Cip155(NativeTransaction {
1259                chain_id: 1,
1260                ..Default::default()
1261            })),
1262            Transaction::Ethereum(Eip2930(Eip2930Transaction {
1263                chain_id: 1,
1264                ..Default::default()
1265            })),
1266            Transaction::Ethereum(Eip1559(Eip1559Transaction {
1267                chain_id: 1,
1268                ..Default::default()
1269            })),
1270            Transaction::Ethereum(Eip7702(Eip7702Transaction {
1271                chain_id: 1,
1272                ..Default::default()
1273            })),
1274            Transaction::Native(Cip2930(Cip2930Transaction {
1275                chain_id: 1,
1276                ..Default::default()
1277            })),
1278            Transaction::Native(Cip1559(Cip1559Transaction {
1279                chain_id: 1,
1280                ..Default::default()
1281            })),
1282        ];
1283        for unsigned in variants {
1284            assert_predicate(part(unsigned));
1285        }
1286    }
1287}