1mod 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
48pub 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
60pub type TxShortId = u64;
63
64pub type TxPropagateId = u32;
65
66#[derive(Debug, PartialEq, Clone, Eq)]
70pub enum TransactionError {
72 AlreadyImported,
74 ChainIdMismatch {
76 expected: u32,
77 got: u32,
78 space: Space,
79 },
80 EpochHeightOutOfBound {
82 block_height: u64,
83 set: u64,
84 transaction_epoch_bound: u64,
85 },
86 NotEnoughBaseGas {
88 required: U256,
90 got: U256,
92 },
93 Stale,
95 TooCheapToReplace,
99 LimitReached,
102 InsufficientGasPrice {
104 minimal: U256,
106 got: U256,
108 },
109 InsufficientGas {
111 minimal: U256,
113 got: U256,
115 },
116 InsufficientBalance {
118 balance: U256,
120 cost: U256,
122 },
123 GasLimitExceeded {
125 limit: U256,
127 got: U256,
129 },
130 InvalidGasLimit(OutOfBounds<U256>),
132 InvalidSignature(String),
134 TooBig,
136 InvalidRlp(String),
138 ZeroGasPrice,
139 FutureTransactionType {
141 tx_type: u8,
142 enable_height: u64,
143 current_height: u64,
144 },
145 CreateInitCodeSizeLimit,
147 InvalidReceiver,
149 TooLargeNonce,
151 EmptyAuthorizationList,
153 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 #[default]
238 Create,
239 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 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 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#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
527pub struct TransactionWithSignatureSerializePart {
528 pub unsigned: Transaction,
530 pub v: u8,
533 pub r: U256,
535 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 } }
649 }
650}
651
652impl 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#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
872pub struct TransactionWithSignature {
873 pub transaction: TransactionWithSignatureSerializePart,
875 #[serde(skip)]
877 pub hash: H256,
878 #[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 let hash;
899 let transaction;
900 if tx_rlp.is_list() {
901 hash = keccak(tx_rlp.as_raw());
902 transaction = tx_rlp.as_val()?;
904 } else {
905 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 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 fn compute_hash(mut self) -> TransactionWithSignature {
949 let hash = keccak(&*self.transaction.rlp_bytes());
950 self.hash = hash;
951 self
952 }
953
954 pub fn is_unsigned(&self) -> bool { self.r.is_zero() && self.s.is_zero() }
956
957 pub fn signature(&self) -> Signature {
959 let r: H256 = BigEndianHash::from_uint(&self.r);
960 let s: H256 = BigEndianHash::from_uint(&self.s);
961 Signature::from_rsv(&r, &s, self.v)
962 }
963
964 pub fn check_low_s(&self) -> Result<(), keylib::Error> {
966 if !self.signature().is_low_s() {
967 Err(keylib::Error::InvalidSignature)
968 } else {
969 Ok(())
970 }
971 }
972
973 pub fn check_y_parity(&self) -> Result<(), keylib::Error> {
974 if self.is_2718() && self.v > 1 {
975 Err(keylib::Error::InvalidYParity)
978 } else {
979 Ok(())
980 }
981 }
982
983 pub fn hash(&self) -> H256 { self.hash }
984
985 pub fn recover_public(&self) -> Result<Public, keylib::Error> {
987 recover(
988 &self.signature(),
989 &self.unsigned.hash_for_compute_signature(),
990 )
991 }
992
993 pub fn rlp_size(&self) -> usize {
994 self.rlp_size.unwrap_or_else(|| self.rlp_bytes().len())
995 }
996
997 pub fn from_raw(raw: &[u8]) -> Result<Self, DecoderError> {
998 Ok(TransactionWithSignature {
999 transaction: Rlp::new(raw).as_val()?,
1000 hash: keccak(raw),
1001 rlp_size: Some(raw.len()),
1002 })
1003 }
1004}
1005
1006impl MallocSizeOf for TransactionWithSignature {
1007 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1008 self.unsigned.size_of(ops)
1009 }
1010}
1011
1012#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1014pub struct SignedTransaction {
1015 pub transaction: TransactionWithSignature,
1016 pub sender: Address,
1017 pub public: Option<Public>,
1018}
1019
1020impl Encodable for SignedTransaction {
1022 fn rlp_append(&self, s: &mut RlpStream) {
1023 s.begin_list(3);
1024 s.append(&self.transaction);
1025 s.append(&self.sender);
1026 s.append(&self.public);
1027 }
1028}
1029
1030impl Decodable for SignedTransaction {
1031 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
1032 Ok(SignedTransaction {
1033 transaction: rlp.val_at(0)?,
1034 sender: rlp.val_at(1)?,
1035 public: rlp.val_at(2)?,
1036 })
1037 }
1038}
1039
1040impl Deref for SignedTransaction {
1041 type Target = TransactionWithSignature;
1042
1043 fn deref(&self) -> &Self::Target { &self.transaction }
1044}
1045
1046impl DerefMut for SignedTransaction {
1047 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.transaction }
1048}
1049
1050impl From<SignedTransaction> for TransactionWithSignature {
1051 fn from(tx: SignedTransaction) -> Self { tx.transaction }
1052}
1053
1054impl SignedTransaction {
1055 pub fn new(public: Public, transaction: TransactionWithSignature) -> Self {
1057 if transaction.is_unsigned() {
1058 SignedTransaction {
1059 transaction,
1060 sender: UNSIGNED_SENDER,
1061 public: None,
1062 }
1063 } else {
1064 let sender = public_to_address(
1065 &public,
1066 transaction.space() == Space::Native,
1067 );
1068 SignedTransaction {
1069 transaction,
1070 sender,
1071 public: Some(public),
1072 }
1073 }
1074 }
1075
1076 pub fn new_unsigned(transaction: TransactionWithSignature) -> Self {
1077 SignedTransaction {
1078 transaction,
1079 sender: UNSIGNED_SENDER,
1080 public: None,
1081 }
1082 }
1083
1084 pub fn set_public(&mut self, public: Public) {
1085 let type_nibble = self.unsigned.space() == Space::Native;
1086 self.sender = public_to_address(&public, type_nibble);
1087 self.public = Some(public);
1088 }
1089
1090 pub fn sender(&self) -> AddressWithSpace {
1092 self.sender.with_space(self.space())
1093 }
1094
1095 pub fn nonce(&self) -> &U256 { self.transaction.nonce() }
1096
1097 pub fn is_unsigned(&self) -> bool { self.transaction.is_unsigned() }
1099
1100 pub fn hash(&self) -> H256 { self.transaction.hash() }
1101
1102 pub fn gas(&self) -> &U256 { self.transaction.gas() }
1103
1104 pub fn gas_price(&self) -> &U256 { self.transaction.gas_price() }
1105
1106 pub fn gas_limit(&self) -> &U256 { self.transaction.gas() }
1107
1108 pub fn storage_limit(&self) -> Option<u64> {
1109 self.transaction.storage_limit()
1110 }
1111
1112 pub fn rlp_size(&self) -> usize { self.transaction.rlp_size() }
1113
1114 pub fn public(&self) -> &Option<Public> { &self.public }
1115
1116 pub fn verify_public(&self, skip: bool) -> Result<bool, keylib::Error> {
1117 if self.public.is_none() {
1118 return Ok(false);
1119 }
1120
1121 if !skip {
1122 let public = self.public.unwrap();
1123 Ok(verify_public(
1124 &public,
1125 &self.signature(),
1126 &self.unsigned.hash_for_compute_signature(),
1127 )?)
1128 } else {
1129 Ok(true)
1130 }
1131 }
1132
1133 pub fn cal_created_address(&self) -> Option<AddressWithSpace> {
1136 if let Action::Create = self.action() {
1137 let from = self.sender();
1138 let nonce = self.nonce();
1139 let space = self.space();
1140 let create_type = match space {
1141 Space::Native => {
1142 CreateContractAddressType::FromSenderNonceAndCodeHash
1143 }
1144 Space::Ethereum => CreateContractAddressType::FromSenderNonce,
1145 };
1146 let code = self.data().as_slice();
1147 let (created_address, _) = cal_contract_address_with_space(
1148 create_type,
1149 &from,
1150 nonce,
1151 code,
1152 );
1153 Some(created_address)
1154 } else {
1155 None
1156 }
1157 }
1158}
1159
1160impl MallocSizeOf for SignedTransaction {
1161 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1162 self.transaction.size_of(ops)
1163 }
1164}