1pub mod eth_transaction;
8pub mod native_transaction;
9
10pub use eth_transaction::{
11 Eip1559Transaction, Eip155Transaction, Eip2930Transaction,
12 Eip7702Transaction, EthereumTransaction,
13};
14pub use native_transaction::{
15 Cip1559Transaction, Cip2930Transaction, NativeTransaction,
16 TypedNativeTransaction,
17};
18use rlp_derive::{RlpDecodable, RlpEncodable};
19
20use crate::{
21 bytes::Bytes,
22 hash::keccak,
23 keylib::{
24 self, public_to_address, recover, verify_public, Public, Secret,
25 Signature,
26 },
27};
28use cfx_types::{
29 Address, AddressSpaceUtil, AddressWithSpace, BigEndianHash, Space, H160,
30 H256, U256,
31};
32use eth_transaction::eip155_signature;
33use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
34use rlp::{self, Decodable, DecoderError, Encodable, Rlp, RlpStream};
35use serde::{Deserialize, Serialize};
36use std::{
37 error, fmt,
38 ops::{Deref, DerefMut},
39};
40use unexpected::OutOfBounds;
41
42pub const UNSIGNED_SENDER: Address = H160([0xff; 20]);
44
45pub const TYPED_NATIVE_TX_PREFIX: &[u8; 3] = b"cfx";
46pub const TYPED_NATIVE_TX_PREFIX_BYTE: u8 = TYPED_NATIVE_TX_PREFIX[0];
47pub const LEGACY_TX_TYPE: u8 = 0x00;
48pub const EIP2930_TYPE: u8 = 0x01;
49pub const EIP1559_TYPE: u8 = 0x02;
50pub const EIP7702_TYPE: u8 = 0x04;
51pub const CIP2930_TYPE: u8 = 0x01;
52pub const CIP1559_TYPE: u8 = 0x02;
53
54pub type TxShortId = u64;
57
58pub type TxPropagateId = u32;
59
60#[derive(Debug, PartialEq, Clone, Eq)]
64pub enum TransactionError {
66 AlreadyImported,
68 ChainIdMismatch {
70 expected: u32,
71 got: u32,
72 space: Space,
73 },
74 EpochHeightOutOfBound {
76 block_height: u64,
77 set: u64,
78 transaction_epoch_bound: u64,
79 },
80 NotEnoughBaseGas {
82 required: U256,
84 got: U256,
86 },
87 Stale,
89 TooCheapToReplace,
93 LimitReached,
96 InsufficientGasPrice {
98 minimal: U256,
100 got: U256,
102 },
103 InsufficientGas {
105 minimal: U256,
107 got: U256,
109 },
110 InsufficientBalance {
112 balance: U256,
114 cost: U256,
116 },
117 GasLimitExceeded {
119 limit: U256,
121 got: U256,
123 },
124 InvalidGasLimit(OutOfBounds<U256>),
126 InvalidSignature(String),
128 TooBig,
130 InvalidRlp(String),
132 ZeroGasPrice,
133 FutureTransactionType {
135 tx_type: u8,
136 enable_height: u64,
137 current_height: u64,
138 },
139 CreateInitCodeSizeLimit,
141 InvalidReceiver,
143 TooLargeNonce,
145 EmptyAuthorizationList,
147 PriortyGreaterThanMaxFee,
149}
150
151impl From<keylib::Error> for TransactionError {
152 fn from(err: keylib::Error) -> Self {
153 TransactionError::InvalidSignature(format!("{}", err))
154 }
155}
156
157impl From<rlp::DecoderError> for TransactionError {
158 fn from(err: rlp::DecoderError) -> Self {
159 TransactionError::InvalidRlp(format!("{}", err))
160 }
161}
162
163impl fmt::Display for TransactionError {
164 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165 use self::TransactionError::*;
166 let msg = match *self {
167 AlreadyImported => "Already imported".into(),
168 ChainIdMismatch { expected, got, space } => {
169 format!("Chain id mismatch, expected {}, got {}, space {:?}", expected, got, space)
170 }
171 EpochHeightOutOfBound {
172 block_height,
173 set,
174 transaction_epoch_bound,
175 } => format!(
176 "EpochHeight out of bound:\
177 block_height {}, transaction epoch_height {}, transaction_epoch_bound {}",
178 block_height, set, transaction_epoch_bound
179 ),
180 NotEnoughBaseGas { got, required } => format!(
181 "Transaction gas {} less than intrinsic gas {}",
182 got, required
183 ),
184 Stale => "No longer valid".into(),
185 TooCheapToReplace => "Gas price too low to replace".into(),
186 LimitReached => "Transaction limit reached".into(),
187 InsufficientGasPrice { minimal, got } => format!(
188 "Insufficient gas price. Min={}, Given={}",
189 minimal, got
190 ),
191 InsufficientGas { minimal, got } => {
192 format!("Insufficient gas. Min={}, Given={}", minimal, got)
193 }
194 InsufficientBalance { balance, cost } => format!(
195 "Insufficient balance for transaction. Balance={}, Cost={}",
196 balance, cost
197 ),
198 GasLimitExceeded { limit, got } => {
199 format!("Gas limit exceeded. Limit={}, Given={}", limit, got)
200 }
201 InvalidGasLimit(ref err) => format!("Invalid gas limit. {}", err),
202 InvalidSignature(ref err) => {
203 format!("Transaction has invalid signature: {}.", err)
204 }
205 TooBig => "Transaction too big".into(),
206 InvalidRlp(ref err) => {
207 format!("Transaction has invalid RLP structure: {}.", err)
208 }
209 ZeroGasPrice => "Zero gas price is not allowed".into(),
210 FutureTransactionType {tx_type, current_height, enable_height} => format!("Transaction type {tx_type} is not enabled, current height {current_height}, enable height {enable_height}"),
211 InvalidReceiver => "Sending transaction to invalid address. The first four bits of address must be 0x0, 0x1, or 0x8.".into(),
212 TooLargeNonce => "Transaction nonce is too large.".into(),
213 CreateInitCodeSizeLimit => "Transaction initcode is too large.".into(),
214 EmptyAuthorizationList => "Empty authorization list".into(),
215 PriortyGreaterThanMaxFee => "Max priority fee greater than max fee".into(),
216 };
217
218 f.write_fmt(format_args!("Transaction error ({})", msg))
219 }
220}
221
222impl error::Error for TransactionError {
223 fn description(&self) -> &str { "Transaction error" }
224}
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
227pub enum Action {
228 Create,
230 Call(Address),
233}
234
235impl Default for Action {
236 fn default() -> Action { Action::Create }
237}
238
239impl Decodable for Action {
240 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
241 if rlp.is_empty() {
242 Ok(Action::Create)
243 } else {
244 Ok(Action::Call(rlp.as_val()?))
245 }
246 }
247}
248
249impl Encodable for Action {
250 fn rlp_append(&self, stream: &mut RlpStream) {
251 match *self {
252 Action::Create => stream.append_internal(&""),
253 Action::Call(ref address) => stream.append_internal(address),
254 };
255 }
256}
257
258#[derive(
259 Debug,
260 Clone,
261 PartialEq,
262 Eq,
263 Serialize,
264 Deserialize,
265 RlpEncodable,
266 RlpDecodable,
267)]
268#[serde(rename_all = "camelCase")]
269pub struct AccessListItem {
270 pub address: Address,
271 pub storage_keys: Vec<H256>,
272}
273
274pub type AccessList = Vec<AccessListItem>;
275
276#[derive(
277 Debug,
278 Clone,
279 PartialEq,
280 Eq,
281 Serialize,
282 Deserialize,
283 RlpEncodable,
284 RlpDecodable,
285)]
286#[serde(rename_all = "camelCase")]
287pub struct AuthorizationListItem {
288 pub chain_id: U256,
289 pub address: Address,
290 pub nonce: u64,
291 pub y_parity: u8,
292 pub r: U256,
293 pub s: U256,
294}
295
296pub type AuthorizationList = Vec<AuthorizationListItem>;
297
298#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
299pub enum Transaction {
300 Native(TypedNativeTransaction),
301 Ethereum(EthereumTransaction),
302}
303
304impl Default for Transaction {
305 fn default() -> Self {
306 Transaction::Native(TypedNativeTransaction::Cip155(Default::default()))
307 }
308}
309
310impl From<NativeTransaction> for Transaction {
311 fn from(tx: NativeTransaction) -> Self {
312 Self::Native(TypedNativeTransaction::Cip155(tx))
313 }
314}
315
316impl From<Eip155Transaction> for Transaction {
317 fn from(tx: Eip155Transaction) -> Self {
318 Self::Ethereum(EthereumTransaction::Eip155(tx))
319 }
320}
321
322macro_rules! access_common_ref {
323 ($field:ident, $ty:ty) => {
324 pub fn $field(&self) -> &$ty {
325 match self {
326 Transaction::Native(tx) => tx.$field(),
327 Transaction::Ethereum(tx) => tx.$field(),
328 }
329 }
330 };
331}
332
333macro_rules! access_common {
334 ($field:ident, $ty:ident) => {
335 pub fn $field(&self) -> $ty {
336 match self {
337 Transaction::Native(tx) => tx.$field(),
338 Transaction::Ethereum(tx) => tx.$field(),
339 }
340 }
341 };
342}
343
344impl Transaction {
345 access_common_ref!(gas, U256);
346
347 access_common_ref!(gas_price, U256);
348
349 access_common_ref!(max_priority_gas_price, U256);
350
351 access_common_ref!(data, Bytes);
352
353 access_common_ref!(nonce, U256);
354
355 access_common!(action, Action);
356
357 access_common_ref!(value, U256);
358
359 pub fn chain_id(&self) -> Option<u32> {
360 match self {
361 Transaction::Native(tx) => Some(*tx.chain_id()),
362 Transaction::Ethereum(tx) => tx.chain_id().clone(),
363 }
364 }
365
366 pub fn storage_limit(&self) -> Option<u64> {
367 match self {
368 Transaction::Native(tx) => Some(*tx.storage_limit()),
369 Transaction::Ethereum(_tx) => None,
370 }
371 }
372
373 pub fn nonce_mut(&mut self) -> &mut U256 {
374 match self {
375 Transaction::Native(tx) => tx.nonce_mut(),
376 Transaction::Ethereum(tx) => tx.nonce_mut(),
377 }
378 }
379
380 pub fn data_mut(&mut self) -> &mut Vec<u8> {
381 match self {
382 Transaction::Native(tx) => tx.data_mut(),
383 Transaction::Ethereum(tx) => tx.data_mut(),
384 }
385 }
386
387 pub fn type_id(&self) -> u8 {
388 match self {
389 Transaction::Native(TypedNativeTransaction::Cip155(_))
390 | Transaction::Ethereum(EthereumTransaction::Eip155(_)) => 0,
391
392 Transaction::Native(TypedNativeTransaction::Cip2930(_))
393 | Transaction::Ethereum(EthereumTransaction::Eip2930(_)) => 1,
394
395 Transaction::Native(TypedNativeTransaction::Cip1559(_))
396 | Transaction::Ethereum(EthereumTransaction::Eip1559(_)) => 2,
397
398 Transaction::Ethereum(EthereumTransaction::Eip7702(_)) => 4,
399 }
400 }
401
402 pub fn is_legacy(&self) -> bool {
403 matches!(
404 self,
405 Transaction::Native(TypedNativeTransaction::Cip155(_))
406 | Transaction::Ethereum(EthereumTransaction::Eip155(_))
407 )
408 }
409
410 pub fn is_2718(&self) -> bool { !self.is_legacy() }
411
412 pub fn after_1559(&self) -> bool {
413 use EthereumTransaction::*;
414 use TypedNativeTransaction::*;
415 matches!(
416 self,
417 Transaction::Native(Cip1559(_))
418 | Transaction::Ethereum(Eip1559(_) | Eip7702(_))
419 )
420 }
421
422 pub fn after_7702(&self) -> bool {
423 matches!(self, Transaction::Ethereum(EthereumTransaction::Eip7702(_)))
424 }
425
426 pub fn access_list(&self) -> Option<&AccessList> {
427 match self {
428 Transaction::Native(tx) => tx.access_list(),
429 Transaction::Ethereum(tx) => tx.access_list(),
430 }
431 }
432
433 pub fn authorization_list(&self) -> Option<&AuthorizationList> {
434 match self {
435 Transaction::Native(_tx) => None,
436 Transaction::Ethereum(tx) => tx.authorization_list(),
437 }
438 }
439
440 pub fn authorization_len(&self) -> usize {
441 self.authorization_list().map_or(0, Vec::len)
442 }
443}
444
445impl Transaction {
446 pub fn priority_gas_price(&self, base_price: &U256) -> U256 {
447 std::cmp::min(
448 *self.max_priority_gas_price(),
449 self.gas_price() - base_price,
450 )
451 }
452
453 pub fn effective_gas_price(&self, base_price: &U256) -> U256 {
454 base_price + self.priority_gas_price(base_price)
455 }
456
457 pub fn hash_for_compute_signature(&self) -> H256 {
461 let mut s = RlpStream::new();
462 let mut type_prefix = vec![];
463 match self {
464 Transaction::Native(TypedNativeTransaction::Cip155(tx)) => {
465 s.append(tx);
466 }
467 Transaction::Native(TypedNativeTransaction::Cip1559(tx)) => {
468 s.append(tx);
469 type_prefix.extend_from_slice(TYPED_NATIVE_TX_PREFIX);
470 type_prefix.push(CIP1559_TYPE);
471 }
472 Transaction::Native(TypedNativeTransaction::Cip2930(tx)) => {
473 s.append(tx);
474 type_prefix.extend_from_slice(TYPED_NATIVE_TX_PREFIX);
475 type_prefix.push(CIP2930_TYPE);
476 }
477 Transaction::Ethereum(EthereumTransaction::Eip155(tx)) => {
478 s.append(tx);
479 }
480 Transaction::Ethereum(EthereumTransaction::Eip1559(tx)) => {
481 s.append(tx);
482 type_prefix.push(EIP1559_TYPE);
483 }
484 Transaction::Ethereum(EthereumTransaction::Eip2930(tx)) => {
485 s.append(tx);
486 type_prefix.push(EIP2930_TYPE);
487 }
488 Transaction::Ethereum(EthereumTransaction::Eip7702(tx)) => {
489 s.append(tx);
490 type_prefix.push(EIP7702_TYPE);
491 }
492 };
493 let encoded = s.as_raw();
494 let mut out = vec![0; type_prefix.len() + encoded.len()];
495 out[0..type_prefix.len()].copy_from_slice(&type_prefix);
496 out[type_prefix.len()..].copy_from_slice(&encoded);
497 keccak(&out)
498 }
499
500 pub fn space(&self) -> Space {
501 match self {
502 Transaction::Native(_) => Space::Native,
503 Transaction::Ethereum(_) => Space::Ethereum,
504 }
505 }
506
507 pub fn sign(self, secret: &Secret) -> SignedTransaction {
508 let sig =
509 crate::keylib::sign(secret, &self.hash_for_compute_signature())
510 .expect(
511 "data is valid and context has signing capabilities; qed",
512 );
513 let tx_with_sig = self.with_signature(sig);
514 let public = tx_with_sig
515 .recover_public()
516 .expect("secret is valid so it's recoverable");
517 SignedTransaction::new(public, tx_with_sig)
518 }
519
520 pub fn with_signature(self, sig: Signature) -> TransactionWithSignature {
522 TransactionWithSignature {
523 transaction: TransactionWithSignatureSerializePart {
524 unsigned: self,
525 r: sig.r().into(),
526 s: sig.s().into(),
527 v: sig.v(),
528 },
529 hash: H256::zero(),
530 rlp_size: None,
531 }
532 .compute_hash()
533 }
534}
535
536impl MallocSizeOf for Transaction {
537 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
538 self.data().size_of(ops)
539 }
540}
541
542#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
544pub struct TransactionWithSignatureSerializePart {
545 pub unsigned: Transaction,
547 pub v: u8,
550 pub r: U256,
552 pub s: U256,
554}
555
556impl Encodable for TransactionWithSignatureSerializePart {
557 fn rlp_append(&self, s: &mut RlpStream) {
558 match self.unsigned {
559 Transaction::Native(TypedNativeTransaction::Cip155(ref tx)) => {
560 s.begin_list(4);
561 s.append(tx);
562 s.append(&self.v);
563 s.append(&self.r);
564 s.append(&self.s);
565 }
566 Transaction::Ethereum(EthereumTransaction::Eip155(ref tx)) => {
567 let Eip155Transaction {
568 nonce,
569 gas_price,
570 gas,
571 action,
572 value,
573 data,
574 chain_id,
575 } = tx;
576 let legacy_v = eip155_signature::add_chain_replay_protection(
577 self.v,
578 chain_id.map(|x| x as u64),
579 );
580 s.begin_list(9);
581 s.append(nonce);
582 s.append(gas_price);
583 s.append(gas);
584 s.append(action);
585 s.append(value);
586 s.append(data);
587 s.append(&legacy_v);
588 s.append(&self.r);
589 s.append(&self.s);
590 }
591 Transaction::Ethereum(EthereumTransaction::Eip2930(ref tx)) => {
592 s.append_raw(&[EIP2930_TYPE], 0);
593 s.begin_list(11);
594 s.append(&tx.chain_id);
595 s.append(&tx.nonce);
596 s.append(&tx.gas_price);
597 s.append(&tx.gas);
598 s.append(&tx.action);
599 s.append(&tx.value);
600 s.append(&tx.data);
601 s.append_list(&tx.access_list);
602 s.append(&self.v);
603 s.append(&self.r);
604 s.append(&self.s);
605 }
606 Transaction::Ethereum(EthereumTransaction::Eip1559(ref tx)) => {
607 s.append_raw(&[EIP1559_TYPE], 0);
608 s.begin_list(12);
609 s.append(&tx.chain_id);
610 s.append(&tx.nonce);
611 s.append(&tx.max_priority_fee_per_gas);
612 s.append(&tx.max_fee_per_gas);
613 s.append(&tx.gas);
614 s.append(&tx.action);
615 s.append(&tx.value);
616 s.append(&tx.data);
617 s.append_list(&tx.access_list);
618 s.append(&self.v);
619 s.append(&self.r);
620 s.append(&self.s);
621 }
622 Transaction::Ethereum(EthereumTransaction::Eip7702(ref tx)) => {
623 s.append_raw(&[EIP7702_TYPE], 0);
624 s.begin_list(13);
625 s.append(&tx.chain_id);
626 s.append(&tx.nonce);
627 s.append(&tx.max_priority_fee_per_gas);
628 s.append(&tx.max_fee_per_gas);
629 s.append(&tx.gas);
630 s.append(&tx.destination);
631 s.append(&tx.value);
632 s.append(&tx.data);
633 s.append_list(&tx.access_list);
634 s.append_list(&tx.authorization_list);
635 s.append(&self.v);
636 s.append(&self.r);
637 s.append(&self.s);
638 }
639 Transaction::Native(TypedNativeTransaction::Cip2930(ref tx)) => {
640 s.append_raw(TYPED_NATIVE_TX_PREFIX, 0);
641 s.append_raw(&[CIP2930_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 Transaction::Native(TypedNativeTransaction::Cip1559(ref tx)) => {
649 s.append_raw(TYPED_NATIVE_TX_PREFIX, 0);
650 s.append_raw(&[CIP1559_TYPE], 0);
651 s.begin_list(4);
652 s.append(tx);
653 s.append(&self.v);
654 s.append(&self.r);
655 s.append(&self.s);
656 } }
666 }
667}
668
669impl Decodable for TransactionWithSignatureSerializePart {
671 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
672 if rlp.as_raw().len() == 0 {
673 return Err(DecoderError::RlpInvalidLength);
674 }
675 if rlp.is_list() {
676 match rlp.item_count()? {
677 4 => {
678 let unsigned: NativeTransaction = rlp.val_at(0)?;
679 let v: u8 = rlp.val_at(1)?;
680 let r: U256 = rlp.val_at(2)?;
681 let s: U256 = rlp.val_at(3)?;
682 Ok(TransactionWithSignatureSerializePart {
683 unsigned: Transaction::Native(
684 TypedNativeTransaction::Cip155(unsigned),
685 ),
686 v,
687 r,
688 s,
689 })
690 }
691 9 => {
692 let nonce: U256 = rlp.val_at(0)?;
693 let gas_price: U256 = rlp.val_at(1)?;
694 let gas: U256 = rlp.val_at(2)?;
695 let action: Action = rlp.val_at(3)?;
696 let value: U256 = rlp.val_at(4)?;
697 let data: Vec<u8> = rlp.val_at(5)?;
698 let legacy_v: u64 = rlp.val_at(6)?;
699 let r: U256 = rlp.val_at(7)?;
700 let s: U256 = rlp.val_at(8)?;
701
702 let v = eip155_signature::extract_standard_v(legacy_v);
703 let chain_id =
704 match eip155_signature::extract_chain_id_from_legacy_v(
705 legacy_v,
706 ) {
707 Some(chain_id) if chain_id > (u32::MAX as u64) => {
708 return Err(DecoderError::Custom(
709 "Does not support chain_id >= 2^32",
710 ));
711 }
712 chain_id => chain_id.map(|x| x as u32),
713 };
714
715 Ok(TransactionWithSignatureSerializePart {
716 unsigned: Transaction::Ethereum(
717 EthereumTransaction::Eip155(Eip155Transaction {
718 nonce,
719 gas_price,
720 gas,
721 action,
722 value,
723 chain_id,
724 data,
725 }),
726 ),
727 v,
728 r,
729 s,
730 })
731 }
732 _ => Err(DecoderError::RlpInvalidLength),
733 }
734 } else {
735 match rlp.as_raw()[0] {
736 TYPED_NATIVE_TX_PREFIX_BYTE => {
737 if rlp.as_raw().len() <= 4
738 || rlp.as_raw()[0..3] != *TYPED_NATIVE_TX_PREFIX
739 {
740 return Err(DecoderError::RlpInvalidLength);
741 }
742 match rlp.as_raw()[3] {
743 CIP2930_TYPE => {
744 let rlp = Rlp::new(&rlp.as_raw()[4..]);
745 if rlp.item_count()? != 4 {
746 return Err(DecoderError::RlpIncorrectListLen);
747 }
748
749 let tx = rlp.val_at(0)?;
750 let v = rlp.val_at(1)?;
751 let r = rlp.val_at(2)?;
752 let s = rlp.val_at(3)?;
753 Ok(TransactionWithSignatureSerializePart {
754 unsigned: Transaction::Native(
755 TypedNativeTransaction::Cip2930(tx),
756 ),
757 v,
758 r,
759 s,
760 })
761 }
762 CIP1559_TYPE => {
763 let rlp = Rlp::new(&rlp.as_raw()[4..]);
764 if rlp.item_count()? != 4 {
765 return Err(DecoderError::RlpIncorrectListLen);
766 }
767
768 let tx = rlp.val_at(0)?;
769 let v = rlp.val_at(1)?;
770 let r = rlp.val_at(2)?;
771 let s = rlp.val_at(3)?;
772 Ok(TransactionWithSignatureSerializePart {
773 unsigned: Transaction::Native(
774 TypedNativeTransaction::Cip1559(tx),
775 ),
776 v,
777 r,
778 s,
779 })
780 }
781 _ => Err(DecoderError::RlpInvalidLength),
782 }
783 }
784 EIP2930_TYPE => {
785 let rlp = Rlp::new(&rlp.as_raw()[1..]);
786 if rlp.item_count()? != 11 {
787 return Err(DecoderError::RlpIncorrectListLen);
788 }
789
790 let tx = Eip2930Transaction {
791 chain_id: rlp.val_at(0)?,
792 nonce: rlp.val_at(1)?,
793 gas_price: rlp.val_at(2)?,
794 gas: rlp.val_at(3)?,
795 action: rlp.val_at(4)?,
796 value: rlp.val_at(5)?,
797 data: rlp.val_at(6)?,
798 access_list: rlp.list_at(7)?,
799 };
800 let v = rlp.val_at(8)?;
801 let r = rlp.val_at(9)?;
802 let s = rlp.val_at(10)?;
803 Ok(TransactionWithSignatureSerializePart {
804 unsigned: Transaction::Ethereum(
805 EthereumTransaction::Eip2930(tx),
806 ),
807 v,
808 r,
809 s,
810 })
811 }
812 EIP1559_TYPE => {
813 let rlp = Rlp::new(&rlp.as_raw()[1..]);
814 if rlp.item_count()? != 12 {
815 return Err(DecoderError::RlpIncorrectListLen);
816 }
817
818 let tx = Eip1559Transaction {
819 chain_id: rlp.val_at(0)?,
820 nonce: rlp.val_at(1)?,
821 max_priority_fee_per_gas: rlp.val_at(2)?,
822 max_fee_per_gas: rlp.val_at(3)?,
823 gas: rlp.val_at(4)?,
824 action: rlp.val_at(5)?,
825 value: rlp.val_at(6)?,
826 data: rlp.val_at(7)?,
827 access_list: rlp.list_at(8)?,
828 };
829 let v = rlp.val_at(9)?;
830 let r = rlp.val_at(10)?;
831 let s = rlp.val_at(11)?;
832 Ok(TransactionWithSignatureSerializePart {
833 unsigned: Transaction::Ethereum(
834 EthereumTransaction::Eip1559(tx),
835 ),
836 v,
837 r,
838 s,
839 })
840 }
841 EIP7702_TYPE => {
842 let rlp = Rlp::new(&rlp.as_raw()[1..]);
843 if rlp.item_count()? != 13 {
844 return Err(DecoderError::RlpIncorrectListLen);
845 }
846
847 let tx = Eip7702Transaction {
848 chain_id: rlp.val_at(0)?,
849 nonce: rlp.val_at(1)?,
850 max_priority_fee_per_gas: rlp.val_at(2)?,
851 max_fee_per_gas: rlp.val_at(3)?,
852 gas: rlp.val_at(4)?,
853 destination: rlp.val_at(5)?,
854 value: rlp.val_at(6)?,
855 data: rlp.val_at(7)?,
856 access_list: rlp.list_at(8)?,
857 authorization_list: rlp.list_at(9)?,
858 };
859 let v = rlp.val_at(10)?;
860 let r = rlp.val_at(11)?;
861 let s = rlp.val_at(12)?;
862 Ok(TransactionWithSignatureSerializePart {
863 unsigned: Transaction::Ethereum(
864 EthereumTransaction::Eip7702(tx),
865 ),
866 v,
867 r,
868 s,
869 })
870 }
871 _ => Err(DecoderError::RlpInvalidLength),
872 }
873 }
874 }
875}
876
877impl Deref for TransactionWithSignatureSerializePart {
878 type Target = Transaction;
879
880 fn deref(&self) -> &Self::Target { &self.unsigned }
881}
882
883impl DerefMut for TransactionWithSignatureSerializePart {
884 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.unsigned }
885}
886
887#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
889pub struct TransactionWithSignature {
890 pub transaction: TransactionWithSignatureSerializePart,
892 #[serde(skip)]
894 pub hash: H256,
895 #[serde(skip)]
897 pub rlp_size: Option<usize>,
898}
899
900impl Deref for TransactionWithSignature {
901 type Target = TransactionWithSignatureSerializePart;
902
903 fn deref(&self) -> &Self::Target { &self.transaction }
904}
905
906impl DerefMut for TransactionWithSignature {
907 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.transaction }
908}
909
910impl Decodable for TransactionWithSignature {
911 fn decode(tx_rlp: &Rlp) -> Result<Self, DecoderError> {
912 let rlp_size = Some(tx_rlp.as_raw().len());
913 let hash;
916 let transaction;
917 if tx_rlp.is_list() {
918 hash = keccak(tx_rlp.as_raw());
919 transaction = tx_rlp.as_val()?;
921 } else {
922 let b: Vec<u8> = tx_rlp.as_val()?;
924 hash = keccak(&b);
925 transaction = rlp::decode(&b)?;
926 };
927 Ok(TransactionWithSignature {
928 transaction,
929 hash,
930 rlp_size,
931 })
932 }
933}
934
935impl Encodable for TransactionWithSignature {
936 fn rlp_append(&self, s: &mut RlpStream) {
937 match &self.transaction.unsigned {
938 Transaction::Native(TypedNativeTransaction::Cip155(_))
939 | Transaction::Ethereum(EthereumTransaction::Eip155(_)) => {
940 s.append_internal(&self.transaction);
941 }
942 _ => {
943 s.append_internal(&rlp::encode(&self.transaction));
945 }
946 }
947 }
948}
949
950impl TransactionWithSignature {
951 pub fn new_unsigned(tx: Transaction) -> Self {
952 TransactionWithSignature {
953 transaction: TransactionWithSignatureSerializePart {
954 unsigned: tx,
955 s: 0.into(),
956 r: 0.into(),
957 v: 0,
958 },
959 hash: Default::default(),
960 rlp_size: None,
961 }
962 }
963
964 fn compute_hash(mut self) -> TransactionWithSignature {
966 let hash = keccak(&*self.transaction.rlp_bytes());
967 self.hash = hash;
968 self
969 }
970
971 pub fn is_unsigned(&self) -> bool { self.r.is_zero() && self.s.is_zero() }
973
974 pub fn signature(&self) -> Signature {
976 let r: H256 = BigEndianHash::from_uint(&self.r);
977 let s: H256 = BigEndianHash::from_uint(&self.s);
978 Signature::from_rsv(&r, &s, self.v)
979 }
980
981 pub fn check_low_s(&self) -> Result<(), keylib::Error> {
983 if !self.signature().is_low_s() {
984 Err(keylib::Error::InvalidSignature)
985 } else {
986 Ok(())
987 }
988 }
989
990 pub fn check_y_parity(&self) -> Result<(), keylib::Error> {
991 if self.is_2718() && self.v > 1 {
992 Err(keylib::Error::InvalidYParity)
995 } else {
996 Ok(())
997 }
998 }
999
1000 pub fn hash(&self) -> H256 { self.hash }
1001
1002 pub fn recover_public(&self) -> Result<Public, keylib::Error> {
1004 Ok(recover(
1005 &self.signature(),
1006 &self.unsigned.hash_for_compute_signature(),
1007 )?)
1008 }
1009
1010 pub fn rlp_size(&self) -> usize {
1011 self.rlp_size.unwrap_or_else(|| self.rlp_bytes().len())
1012 }
1013
1014 pub fn from_raw(raw: &[u8]) -> Result<Self, DecoderError> {
1015 Ok(TransactionWithSignature {
1016 transaction: Rlp::new(raw).as_val()?,
1017 hash: keccak(raw),
1018 rlp_size: Some(raw.len()),
1019 })
1020 }
1021}
1022
1023impl MallocSizeOf for TransactionWithSignature {
1024 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1025 self.unsigned.size_of(ops)
1026 }
1027}
1028
1029#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1031pub struct SignedTransaction {
1032 pub transaction: TransactionWithSignature,
1033 pub sender: Address,
1034 pub public: Option<Public>,
1035}
1036
1037impl Encodable for SignedTransaction {
1039 fn rlp_append(&self, s: &mut RlpStream) {
1040 s.begin_list(3);
1041 s.append(&self.transaction);
1042 s.append(&self.sender);
1043 s.append(&self.public);
1044 }
1045}
1046
1047impl Decodable for SignedTransaction {
1048 fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
1049 Ok(SignedTransaction {
1050 transaction: rlp.val_at(0)?,
1051 sender: rlp.val_at(1)?,
1052 public: rlp.val_at(2)?,
1053 })
1054 }
1055}
1056
1057impl Deref for SignedTransaction {
1058 type Target = TransactionWithSignature;
1059
1060 fn deref(&self) -> &Self::Target { &self.transaction }
1061}
1062
1063impl DerefMut for SignedTransaction {
1064 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.transaction }
1065}
1066
1067impl From<SignedTransaction> for TransactionWithSignature {
1068 fn from(tx: SignedTransaction) -> Self { tx.transaction }
1069}
1070
1071impl SignedTransaction {
1072 pub fn new(public: Public, transaction: TransactionWithSignature) -> Self {
1074 if transaction.is_unsigned() {
1075 SignedTransaction {
1076 transaction,
1077 sender: UNSIGNED_SENDER,
1078 public: None,
1079 }
1080 } else {
1081 let sender = public_to_address(
1082 &public,
1083 transaction.space() == Space::Native,
1084 );
1085 SignedTransaction {
1086 transaction,
1087 sender,
1088 public: Some(public),
1089 }
1090 }
1091 }
1092
1093 pub fn new_unsigned(transaction: TransactionWithSignature) -> Self {
1094 SignedTransaction {
1095 transaction,
1096 sender: UNSIGNED_SENDER,
1097 public: None,
1098 }
1099 }
1100
1101 pub fn set_public(&mut self, public: Public) {
1102 let type_nibble = self.unsigned.space() == Space::Native;
1103 self.sender = public_to_address(&public, type_nibble);
1104 self.public = Some(public);
1105 }
1106
1107 pub fn sender(&self) -> AddressWithSpace {
1109 self.sender.with_space(self.space())
1110 }
1111
1112 pub fn nonce(&self) -> &U256 { self.transaction.nonce() }
1113
1114 pub fn is_unsigned(&self) -> bool { self.transaction.is_unsigned() }
1116
1117 pub fn hash(&self) -> H256 { self.transaction.hash() }
1118
1119 pub fn gas(&self) -> &U256 { &self.transaction.gas() }
1120
1121 pub fn gas_price(&self) -> &U256 { &self.transaction.gas_price() }
1122
1123 pub fn gas_limit(&self) -> &U256 { &self.transaction.gas() }
1124
1125 pub fn storage_limit(&self) -> Option<u64> {
1126 self.transaction.storage_limit()
1127 }
1128
1129 pub fn rlp_size(&self) -> usize { self.transaction.rlp_size() }
1130
1131 pub fn public(&self) -> &Option<Public> { &self.public }
1132
1133 pub fn verify_public(&self, skip: bool) -> Result<bool, keylib::Error> {
1134 if self.public.is_none() {
1135 return Ok(false);
1136 }
1137
1138 if !skip {
1139 let public = self.public.unwrap();
1140 Ok(verify_public(
1141 &public,
1142 &self.signature(),
1143 &self.unsigned.hash_for_compute_signature(),
1144 )?)
1145 } else {
1146 Ok(true)
1147 }
1148 }
1149}
1150
1151impl MallocSizeOf for SignedTransaction {
1152 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
1153 self.transaction.size_of(ops)
1154 }
1155}