mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add recovered wrapper type and eth pool conversions (#4267)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
@ -92,10 +92,10 @@ pub use transaction::{
|
||||
util::secp256k1::{public_key_to_address, recover_signer, sign_message},
|
||||
AccessList, AccessListItem, AccessListWithGasUsed, BlobTransaction, BlobTransactionSidecar,
|
||||
FromRecoveredTransaction, IntoRecoveredTransaction, InvalidTransactionError,
|
||||
PooledTransactionsElement, Signature, Transaction, TransactionKind, TransactionMeta,
|
||||
TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxEip1559, TxEip2930,
|
||||
TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID,
|
||||
LEGACY_TX_TYPE_ID,
|
||||
PooledTransactionsElement, PooledTransactionsElementEcRecovered, Signature, Transaction,
|
||||
TransactionKind, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered,
|
||||
TransactionSignedNoHash, TxEip1559, TxEip2930, TxEip4844, TxLegacy, TxType, EIP1559_TX_TYPE_ID,
|
||||
EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
|
||||
};
|
||||
pub use withdrawal::Withdrawal;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use super::access_list::AccessList;
|
||||
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
|
||||
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
|
||||
use bytes::BytesMut;
|
||||
use reth_codecs::{main_codec, Compact};
|
||||
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
|
||||
use std::mem;
|
||||
@ -188,6 +189,28 @@ impl TxEip1559 {
|
||||
self.access_list.size() + // access_list
|
||||
self.input.len() // input
|
||||
}
|
||||
|
||||
/// Encodes the legacy transaction in RLP for signing.
|
||||
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the signature RLP encoding for the transaction.
|
||||
pub(crate) fn payload_len_for_signature(&self) -> usize {
|
||||
let payload_length = self.fields_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Outputs the signature hash of the transaction by first encoding without a signature, then
|
||||
/// hashing.
|
||||
pub(crate) fn signature_hash(&self) -> H256 {
|
||||
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
|
||||
self.encode_for_signing(&mut buf);
|
||||
keccak256(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use super::access_list::AccessList;
|
||||
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
|
||||
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
|
||||
use bytes::BytesMut;
|
||||
use reth_codecs::{main_codec, Compact};
|
||||
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
|
||||
use std::mem;
|
||||
@ -153,6 +154,28 @@ impl TxEip2930 {
|
||||
pub(crate) fn tx_type(&self) -> TxType {
|
||||
TxType::EIP2930
|
||||
}
|
||||
|
||||
/// Encodes the legacy transaction in RLP for signing.
|
||||
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the signature RLP encoding for the transaction.
|
||||
pub(crate) fn payload_len_for_signature(&self) -> usize {
|
||||
let payload_length = self.fields_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Outputs the signature hash of the transaction by first encoding without a signature, then
|
||||
/// hashing.
|
||||
pub(crate) fn signature_hash(&self) -> H256 {
|
||||
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
|
||||
self.encode_for_signing(&mut buf);
|
||||
keccak256(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -9,6 +9,7 @@ use crate::{
|
||||
kzg_to_versioned_hash, Bytes, ChainId, Signature, Transaction, TransactionKind,
|
||||
TransactionSigned, TxHash, TxType, EIP4844_TX_TYPE_ID, H256,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use reth_codecs::{main_codec, Compact};
|
||||
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -226,6 +227,28 @@ impl TxEip4844 {
|
||||
pub(crate) fn tx_type(&self) -> TxType {
|
||||
TxType::EIP4844
|
||||
}
|
||||
|
||||
/// Encodes the legacy transaction in RLP for signing.
|
||||
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the signature RLP encoding for the transaction.
|
||||
pub(crate) fn payload_len_for_signature(&self) -> usize {
|
||||
let payload_length = self.fields_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Outputs the signature hash of the transaction by first encoding without a signature, then
|
||||
/// hashing.
|
||||
pub(crate) fn signature_hash(&self) -> H256 {
|
||||
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
|
||||
self.encode_for_signing(&mut buf);
|
||||
keccak256(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can occur when validating a [BlobTransaction].
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use crate::{Bytes, ChainId, Signature, TransactionKind, TxType};
|
||||
use crate::{keccak256, Bytes, ChainId, Signature, TransactionKind, TxType, H256};
|
||||
use bytes::BytesMut;
|
||||
use reth_codecs::{main_codec, Compact};
|
||||
use reth_rlp::{length_of_length, Encodable, Header};
|
||||
use std::mem;
|
||||
@ -105,6 +106,59 @@ impl TxLegacy {
|
||||
pub(crate) fn tx_type(&self) -> TxType {
|
||||
TxType::Legacy
|
||||
}
|
||||
|
||||
/// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy
|
||||
/// transactions.
|
||||
pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) {
|
||||
// if this is a legacy transaction without a chain ID, it must be pre-EIP-155
|
||||
// and does not need to encode the chain ID for the signature hash encoding
|
||||
if let Some(id) = self.chain_id {
|
||||
// EIP-155 encodes the chain ID and two zeroes
|
||||
id.encode(out);
|
||||
0x00u8.encode(out);
|
||||
0x00u8.encode(out);
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy
|
||||
/// transactions.
|
||||
pub(crate) fn eip155_fields_len(&self) -> usize {
|
||||
if let Some(id) = self.chain_id {
|
||||
// EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain
|
||||
// ID to get the length of all 3 fields
|
||||
// len(chain_id) + (0x00) + (0x00)
|
||||
id.length() + 2
|
||||
} else {
|
||||
// this is either a pre-EIP-155 legacy transaction or a typed transaction
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the legacy transaction in RLP for signing, including the EIP-155 fields if possible.
|
||||
pub(crate) fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
|
||||
.encode(out);
|
||||
self.encode_fields(out);
|
||||
self.encode_eip155_fields(out);
|
||||
}
|
||||
|
||||
/// Outputs the length of the signature RLP encoding for the transaction, including the length
|
||||
/// of the EIP-155 fields if possible.
|
||||
pub(crate) fn payload_len_for_signature(&self) -> usize {
|
||||
let payload_length = self.fields_len() + self.eip155_fields_len();
|
||||
// 'header length' + 'payload length'
|
||||
length_of_length(payload_length) + payload_length
|
||||
}
|
||||
|
||||
/// Outputs the signature hash of the transaction by first encoding without a signature, then
|
||||
/// hashing.
|
||||
///
|
||||
/// See [Self::encode_for_signing] for more information on the encoding format.
|
||||
pub(crate) fn signature_hash(&self) -> H256 {
|
||||
let mut buf = BytesMut::with_capacity(self.payload_len_for_signature());
|
||||
self.encode_for_signing(&mut buf);
|
||||
keccak256(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -10,9 +10,7 @@ pub use meta::TransactionMeta;
|
||||
use once_cell::sync::Lazy;
|
||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use reth_codecs::{add_arbitrary_tests, derive_arbitrary, Compact};
|
||||
use reth_rlp::{
|
||||
length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE,
|
||||
};
|
||||
use reth_rlp::{Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use signature::Signature;
|
||||
use std::mem;
|
||||
@ -24,7 +22,7 @@ pub use eip1559::TxEip1559;
|
||||
pub use eip2930::TxEip2930;
|
||||
pub use eip4844::{BlobTransaction, BlobTransactionSidecar, TxEip4844};
|
||||
pub use legacy::TxLegacy;
|
||||
pub use pooled::PooledTransactionsElement;
|
||||
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};
|
||||
|
||||
mod access_list;
|
||||
mod eip1559;
|
||||
@ -100,9 +98,12 @@ impl Transaction {
|
||||
/// Heavy operation that return signature hash over rlp encoded transaction.
|
||||
/// It is only for signature signing or signer recovery.
|
||||
pub fn signature_hash(&self) -> H256 {
|
||||
let mut buf = BytesMut::new();
|
||||
self.encode(&mut buf);
|
||||
keccak256(&buf)
|
||||
match self {
|
||||
Transaction::Legacy(tx) => tx.signature_hash(),
|
||||
Transaction::Eip2930(tx) => tx.signature_hash(),
|
||||
Transaction::Eip1559(tx) => tx.signature_hash(),
|
||||
Transaction::Eip4844(tx) => tx.signature_hash(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get chain_id.
|
||||
@ -316,54 +317,6 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes EIP-155 arguments into the desired buffer. Only encodes values for legacy
|
||||
/// transactions.
|
||||
pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) {
|
||||
// if this is a legacy transaction without a chain ID, it must be pre-EIP-155
|
||||
// and does not need to encode the chain ID for the signature hash encoding
|
||||
if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self {
|
||||
// EIP-155 encodes the chain ID and two zeroes
|
||||
id.encode(out);
|
||||
0x00u8.encode(out);
|
||||
0x00u8.encode(out);
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy
|
||||
/// transactions.
|
||||
pub(crate) fn eip155_fields_len(&self) -> usize {
|
||||
if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self {
|
||||
// EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain
|
||||
// ID to get the length of all 3 fields
|
||||
// len(chain_id) + (0x00) + (0x00)
|
||||
id.length() + 2
|
||||
} else {
|
||||
// this is either a pre-EIP-155 legacy transaction or a typed transaction
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs the length of the transaction's fields, without a RLP header or length of the
|
||||
/// eip155 fields.
|
||||
pub(crate) fn fields_len(&self) -> usize {
|
||||
match self {
|
||||
Transaction::Legacy(legacy_tx) => legacy_tx.fields_len(),
|
||||
Transaction::Eip2930(access_list_tx) => access_list_tx.fields_len(),
|
||||
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.fields_len(),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.fields_len(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes only the transaction's fields into the desired buffer, without a RLP header.
|
||||
pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) {
|
||||
match self {
|
||||
Transaction::Legacy(legacy_tx) => legacy_tx.encode_fields(out),
|
||||
Transaction::Eip2930(access_list_tx) => access_list_tx.encode_fields(out),
|
||||
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.encode_fields(out),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.encode_fields(out),
|
||||
}
|
||||
}
|
||||
|
||||
/// This encodes the transaction _without_ the signature, and is only suitable for creating a
|
||||
/// hash intended for signing.
|
||||
pub fn encode_without_signature(&self, out: &mut dyn bytes::BufMut) {
|
||||
@ -496,32 +449,27 @@ impl Default for Transaction {
|
||||
impl Encodable for Transaction {
|
||||
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||
match self {
|
||||
Transaction::Legacy { .. } => {
|
||||
Header { list: true, payload_length: self.fields_len() + self.eip155_fields_len() }
|
||||
.encode(out);
|
||||
self.encode_fields(out);
|
||||
self.encode_eip155_fields(out);
|
||||
Transaction::Legacy(legacy_tx) => {
|
||||
legacy_tx.encode_for_signing(out);
|
||||
}
|
||||
_ => {
|
||||
out.put_u8(self.tx_type() as u8);
|
||||
Header { list: true, payload_length: self.fields_len() }.encode(out);
|
||||
self.encode_fields(out);
|
||||
Transaction::Eip2930(access_list_tx) => {
|
||||
access_list_tx.encode_for_signing(out);
|
||||
}
|
||||
Transaction::Eip1559(dynamic_fee_tx) => {
|
||||
dynamic_fee_tx.encode_for_signing(out);
|
||||
}
|
||||
Transaction::Eip4844(blob_tx) => {
|
||||
blob_tx.encode_for_signing(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
match self {
|
||||
Transaction::Legacy { .. } => {
|
||||
let payload_length = self.fields_len() + self.eip155_fields_len();
|
||||
// 'header length' + 'payload length'
|
||||
length_of_length(payload_length) + payload_length
|
||||
}
|
||||
_ => {
|
||||
let payload_length = self.fields_len();
|
||||
// 'transaction type byte length' + 'header length' + 'payload length'
|
||||
1 + length_of_length(payload_length) + payload_length
|
||||
}
|
||||
Transaction::Legacy(legacy_tx) => legacy_tx.payload_len_for_signature(),
|
||||
Transaction::Eip2930(access_list_tx) => access_list_tx.payload_len_for_signature(),
|
||||
Transaction::Eip1559(dynamic_fee_tx) => dynamic_fee_tx.payload_len_for_signature(),
|
||||
Transaction::Eip4844(blob_tx) => blob_tx.payload_len_for_signature(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
//! Defines the types for blob transactions, legacy, and other EIP-2718 transactions included in a
|
||||
//! response to `GetPooledTransactions`.
|
||||
use crate::{
|
||||
BlobTransaction, Bytes, Signature, Transaction, TransactionSigned, TxEip1559, TxEip2930,
|
||||
TxHash, TxLegacy, EIP4844_TX_TYPE_ID,
|
||||
Address, BlobTransaction, Bytes, Signature, Transaction, TransactionSigned,
|
||||
TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxHash, TxLegacy, EIP4844_TX_TYPE_ID, H256,
|
||||
};
|
||||
use bytes::Buf;
|
||||
use derive_more::{AsRef, Deref};
|
||||
use reth_rlp::{Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -45,6 +46,46 @@ pub enum PooledTransactionsElement {
|
||||
}
|
||||
|
||||
impl PooledTransactionsElement {
|
||||
/// Heavy operation that return signature hash over rlp encoded transaction.
|
||||
/// It is only for signature signing or signer recovery.
|
||||
pub fn signature_hash(&self) -> H256 {
|
||||
match self {
|
||||
Self::Legacy { transaction, .. } => transaction.signature_hash(),
|
||||
Self::Eip2930 { transaction, .. } => transaction.signature_hash(),
|
||||
Self::Eip1559 { transaction, .. } => transaction.signature_hash(),
|
||||
Self::BlobTransaction(blob_tx) => blob_tx.transaction.signature_hash(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the signature of the transaction.
|
||||
pub fn signature(&self) -> &Signature {
|
||||
match self {
|
||||
Self::Legacy { signature, .. } => signature,
|
||||
Self::Eip2930 { signature, .. } => signature,
|
||||
Self::Eip1559 { signature, .. } => signature,
|
||||
Self::BlobTransaction(blob_tx) => &blob_tx.signature,
|
||||
}
|
||||
}
|
||||
|
||||
/// Recover signer from signature and hash.
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid, see also [Self::recover_signer].
|
||||
pub fn recover_signer(&self) -> Option<Address> {
|
||||
let signature_hash = self.signature_hash();
|
||||
self.signature().recover_signer(signature_hash)
|
||||
}
|
||||
|
||||
/// Tries to recover signer and return [`PooledTransactionsElementEcRecovered`].
|
||||
///
|
||||
/// Returns `Err(Self)` if the transaction's signature is invalid, see also
|
||||
/// [Self::recover_signer].
|
||||
pub fn try_into_ecrecovered(self) -> Result<PooledTransactionsElementEcRecovered, Self> {
|
||||
match self.recover_signer() {
|
||||
None => Err(self),
|
||||
Some(signer) => Ok(PooledTransactionsElementEcRecovered { transaction: self, signer }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the "raw" format of transaction (e.g. `eth_sendRawTransaction`).
|
||||
///
|
||||
/// The raw transaction is either a legacy transaction or EIP-2718 typed transaction
|
||||
@ -117,6 +158,12 @@ impl PooledTransactionsElement {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create [`TransactionSignedEcRecovered`] by converting this transaction into
|
||||
/// [`TransactionSigned`] and [`Address`] of the signer.
|
||||
pub fn into_ecrecovered_transaction(self, signer: Address) -> TransactionSignedEcRecovered {
|
||||
TransactionSignedEcRecovered::from_signed_transaction(self.into_transaction(), signer)
|
||||
}
|
||||
|
||||
/// Returns the inner [TransactionSigned].
|
||||
pub fn into_transaction(self) -> TransactionSigned {
|
||||
match self {
|
||||
@ -301,3 +348,42 @@ impl From<TransactionSigned> for PooledTransactionsElement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A signed pooled transaction with recovered signer.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, AsRef, Deref)]
|
||||
pub struct PooledTransactionsElementEcRecovered {
|
||||
/// Signer of the transaction
|
||||
signer: Address,
|
||||
/// Signed transaction
|
||||
#[deref]
|
||||
#[as_ref]
|
||||
transaction: PooledTransactionsElement,
|
||||
}
|
||||
|
||||
// === impl PooledTransactionsElementEcRecovered ===
|
||||
|
||||
impl PooledTransactionsElementEcRecovered {
|
||||
/// Signer of transaction recovered from signature
|
||||
pub fn signer(&self) -> Address {
|
||||
self.signer
|
||||
}
|
||||
|
||||
/// Transform back to [`PooledTransactionsElement`]
|
||||
pub fn into_transaction(self) -> PooledTransactionsElement {
|
||||
self.transaction
|
||||
}
|
||||
|
||||
/// Desolve Self to its component
|
||||
pub fn into_components(self) -> (PooledTransactionsElement, Address) {
|
||||
(self.transaction, self.signer)
|
||||
}
|
||||
|
||||
/// Create [`TransactionSignedEcRecovered`] from [`PooledTransactionsElement`] and [`Address`]
|
||||
/// of the signer.
|
||||
pub fn from_signed_transaction(
|
||||
transaction: PooledTransactionsElement,
|
||||
signer: Address,
|
||||
) -> Self {
|
||||
Self { transaction, signer }
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,9 +6,9 @@ use crate::{
|
||||
};
|
||||
use futures_util::{ready, Stream};
|
||||
use reth_primitives::{
|
||||
Address, FromRecoveredTransaction, IntoRecoveredTransaction, PeerId, Transaction,
|
||||
TransactionKind, TransactionSignedEcRecovered, TxHash, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID,
|
||||
H256, U256,
|
||||
Address, BlobTransactionSidecar, FromRecoveredTransaction, IntoRecoveredTransaction, PeerId,
|
||||
PooledTransactionsElement, PooledTransactionsElementEcRecovered, Transaction, TransactionKind,
|
||||
TransactionSignedEcRecovered, TxHash, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, H256, U256,
|
||||
};
|
||||
use reth_rlp::Encodable;
|
||||
use std::{
|
||||
@ -569,7 +569,7 @@ pub trait PoolTransaction:
|
||||
///
|
||||
/// This type is essentially a wrapper around [TransactionSignedEcRecovered] with additional fields
|
||||
/// derived from the transaction that are frequently used by the pools for ordering.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EthPooledTransaction {
|
||||
/// EcRecovered transaction info
|
||||
pub(crate) transaction: TransactionSignedEcRecovered,
|
||||
@ -577,21 +577,41 @@ pub struct EthPooledTransaction {
|
||||
/// For EIP-1559 transactions: `max_fee_per_gas * gas_limit + tx_value`.
|
||||
/// For legacy transactions: `gas_price * gas_limit + tx_value`.
|
||||
pub(crate) cost: U256,
|
||||
// TODO optional sidecar
|
||||
|
||||
/// The blob side car this transaction
|
||||
pub(crate) blob_sidecar: EthBlobTransactionSidecar,
|
||||
}
|
||||
|
||||
/// Represents the blob sidecar of the [EthPooledTransaction].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum EthBlobTransactionSidecar {
|
||||
/// This transaction does not have a blob sidecar
|
||||
None,
|
||||
/// This transaction has a blob sidecar (EIP-4844) but it is missing
|
||||
///
|
||||
/// It was either extracted after being inserted into the pool or re-injected after reorg
|
||||
/// without the blob sidecar
|
||||
Missing,
|
||||
/// The eip-4844 transaction was pulled from the network and still has its blob sidecar
|
||||
Present(BlobTransactionSidecar),
|
||||
}
|
||||
|
||||
impl EthPooledTransaction {
|
||||
/// Create new instance of [Self].
|
||||
pub fn new(transaction: TransactionSignedEcRecovered) -> Self {
|
||||
let mut blob_sidecar = EthBlobTransactionSidecar::None;
|
||||
let gas_cost = match &transaction.transaction {
|
||||
Transaction::Legacy(t) => U256::from(t.gas_price) * U256::from(t.gas_limit),
|
||||
Transaction::Eip2930(t) => U256::from(t.gas_price) * U256::from(t.gas_limit),
|
||||
Transaction::Eip1559(t) => U256::from(t.max_fee_per_gas) * U256::from(t.gas_limit),
|
||||
Transaction::Eip4844(t) => U256::from(t.max_fee_per_gas) * U256::from(t.gas_limit),
|
||||
Transaction::Eip4844(t) => {
|
||||
blob_sidecar = EthBlobTransactionSidecar::Missing;
|
||||
U256::from(t.max_fee_per_gas) * U256::from(t.gas_limit)
|
||||
}
|
||||
};
|
||||
let cost = gas_cost + U256::from(transaction.value());
|
||||
|
||||
Self { transaction, cost }
|
||||
Self { transaction, cost, blob_sidecar }
|
||||
}
|
||||
|
||||
/// Return the reference to the underlying transaction.
|
||||
@ -600,6 +620,27 @@ impl EthPooledTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Conversion from the network transaction type to the pool transaction type.
|
||||
impl From<PooledTransactionsElementEcRecovered> for EthPooledTransaction {
|
||||
fn from(tx: PooledTransactionsElementEcRecovered) -> Self {
|
||||
let (tx, signer) = tx.into_components();
|
||||
match tx {
|
||||
PooledTransactionsElement::BlobTransaction(tx) => {
|
||||
// include the blob sidecar
|
||||
let (tx, blob) = tx.into_parts();
|
||||
let tx = TransactionSignedEcRecovered::from_signed_transaction(tx, signer);
|
||||
let mut pooled = EthPooledTransaction::new(tx);
|
||||
pooled.blob_sidecar = EthBlobTransactionSidecar::Present(blob);
|
||||
pooled
|
||||
}
|
||||
tx => {
|
||||
// no blob sidecar
|
||||
EthPooledTransaction::new(tx.into_ecrecovered_transaction(signer))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PoolTransaction for EthPooledTransaction {
|
||||
/// Returns hash of the transaction.
|
||||
fn hash(&self) -> &TxHash {
|
||||
|
||||
Reference in New Issue
Block a user