feat: start implementing OpTransaction (#12529)

Co-authored-by: Emilia Hane <elsaemiliaevahane@gmail.com>
This commit is contained in:
tedison
2024-11-24 04:08:36 -05:00
committed by GitHub
parent a552b1ffc9
commit 21bc75df39
6 changed files with 204 additions and 7 deletions

View File

@ -16,7 +16,7 @@ workspace = true
reth-node-types.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-codecs = { workspace = true, optional = true }
reth-codecs = { workspace = true, optional = true, features = ["optimism"] }
# ethereum
alloy-primitives.workspace = true
@ -34,7 +34,7 @@ serde = { workspace = true, optional = true }
# misc
derive_more.workspace = true
# test-utils
# test
arbitrary = { workspace = true, features = ["derive"], optional = true }
[dev-dependencies]
@ -66,7 +66,7 @@ serde = [
"alloy-consensus/serde",
"alloy-eips/serde",
"bytes/serde",
"reth-codecs/serde",
"reth-codecs?/serde",
"op-alloy-consensus/serde",
]
arbitrary = [
@ -78,4 +78,4 @@ arbitrary = [
"alloy-consensus/arbitrary",
"alloy-eips/arbitrary",
"alloy-primitives/arbitrary",
]
]

View File

@ -9,9 +9,9 @@
#![cfg_attr(not(feature = "std"), no_std)]
pub mod bedrock;
pub mod tx_type;
pub mod transaction;
pub use tx_type::OpTxType;
pub use transaction::{tx_type::OpTxType, OpTransaction};
use alloy_consensus::Header;
use reth_node_types::NodePrimitives;

View File

@ -0,0 +1,173 @@
//! Wrapper of [`OpTypedTransaction`], that implements reth database encoding [`Compact`].
pub mod tx_type;
use alloy_primitives::{bytes, Bytes, TxKind, Uint, B256};
use alloy_consensus::{constants::EIP7702_TX_TYPE_ID, TxLegacy};
use alloy_eips::{eip2930::AccessList, eip7702::SignedAuthorization};
use derive_more::{Deref, From};
use op_alloy_consensus::{OpTypedTransaction, DEPOSIT_TX_TYPE_ID};
use reth_codecs::Compact;
use reth_primitives::transaction::{
COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
COMPACT_IDENTIFIER_LEGACY,
};
use reth_primitives_traits::InMemorySize;
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Deref, Hash, From)]
/// Optimistic transaction.
pub struct OpTransaction(OpTypedTransaction);
impl Default for OpTransaction {
fn default() -> Self {
Self(OpTypedTransaction::Legacy(TxLegacy::default()))
}
}
impl Compact for OpTransaction {
fn to_compact<B>(&self, out: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
match &self.0 {
OpTypedTransaction::Legacy(tx) => tx.to_compact(out),
OpTypedTransaction::Eip2930(tx) => tx.to_compact(out),
OpTypedTransaction::Eip1559(tx) => tx.to_compact(out),
OpTypedTransaction::Eip7702(tx) => tx.to_compact(out),
OpTypedTransaction::Deposit(tx) => tx.to_compact(out),
}
}
fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) {
use bytes::Buf;
match identifier {
COMPACT_IDENTIFIER_LEGACY => {
let (tx, buf) = TxLegacy::from_compact(buf, buf.len());
(Self(OpTypedTransaction::Legacy(tx)), buf)
}
COMPACT_IDENTIFIER_EIP2930 => {
let (tx, buf) =
alloy_consensus::transaction::TxEip2930::from_compact(buf, buf.len());
(Self(OpTypedTransaction::Eip2930(tx)), buf)
}
COMPACT_IDENTIFIER_EIP1559 => {
let (tx, buf) =
alloy_consensus::transaction::TxEip1559::from_compact(buf, buf.len());
(Self(OpTypedTransaction::Eip1559(tx)), buf)
}
COMPACT_EXTENDED_IDENTIFIER_FLAG => {
// An identifier of 3 indicates that the transaction type did not fit into
// the backwards compatible 2 bit identifier, their transaction types are
// larger than 2 bits (eg. 4844 and Deposit Transactions). In this case,
// we need to read the concrete transaction type from the buffer by
// reading the full 8 bits (single byte) and match on this transaction type.
let identifier = buf.get_u8();
match identifier {
EIP7702_TX_TYPE_ID => {
let (tx, buf) =
alloy_consensus::transaction::TxEip7702::from_compact(buf, buf.len());
(Self(OpTypedTransaction::Eip7702(tx)), buf)
}
DEPOSIT_TX_TYPE_ID => {
let (tx, buf) = op_alloy_consensus::TxDeposit::from_compact(buf, buf.len());
(Self(OpTypedTransaction::Deposit(tx)), buf)
}
_ => unreachable!(
"Junk data in database: unknown Transaction variant: {identifier}"
),
}
}
_ => unreachable!("Junk data in database: unknown Transaction variant: {identifier}"),
}
}
}
impl alloy_consensus::Transaction for OpTransaction {
fn chain_id(&self) -> Option<u64> {
self.0.chain_id()
}
fn nonce(&self) -> u64 {
self.0.nonce()
}
fn gas_limit(&self) -> u64 {
self.0.gas_limit()
}
fn gas_price(&self) -> Option<u128> {
self.0.gas_price()
}
fn max_fee_per_gas(&self) -> u128 {
self.0.max_fee_per_gas()
}
fn max_priority_fee_per_gas(&self) -> Option<u128> {
self.0.max_priority_fee_per_gas()
}
fn max_fee_per_blob_gas(&self) -> Option<u128> {
self.0.max_fee_per_blob_gas()
}
fn priority_fee_or_price(&self) -> u128 {
self.0.priority_fee_or_price()
}
fn kind(&self) -> TxKind {
self.0.kind()
}
fn value(&self) -> Uint<256, 4> {
self.0.value()
}
fn input(&self) -> &Bytes {
self.0.input()
}
fn ty(&self) -> u8 {
self.0.ty()
}
fn access_list(&self) -> Option<&AccessList> {
self.0.access_list()
}
fn blob_versioned_hashes(&self) -> Option<&[B256]> {
self.0.blob_versioned_hashes()
}
fn authorization_list(&self) -> Option<&[SignedAuthorization]> {
self.0.authorization_list()
}
fn is_dynamic_fee(&self) -> bool {
self.0.is_dynamic_fee()
}
fn effective_gas_price(&self, base_fee: Option<u64>) -> u128 {
self.0.effective_gas_price(base_fee)
}
fn effective_tip_per_gas(&self, base_fee: u64) -> Option<u128> {
self.0.effective_tip_per_gas(base_fee)
}
}
impl InMemorySize for OpTransaction {
fn size(&self) -> usize {
match &self.0 {
OpTypedTransaction::Legacy(tx) => tx.size(),
OpTypedTransaction::Eip2930(tx) => tx.size(),
OpTypedTransaction::Eip1559(tx) => tx.size(),
OpTypedTransaction::Eip7702(tx) => tx.size(),
OpTypedTransaction::Deposit(tx) => tx.size(),
}
}
}

View File

@ -56,6 +56,12 @@ pub mod signature;
pub(crate) mod util;
#[cfg(any(test, feature = "reth-codec"))]
pub use tx_type::{
COMPACT_EXTENDED_IDENTIFIER_FLAG, COMPACT_IDENTIFIER_EIP1559, COMPACT_IDENTIFIER_EIP2930,
COMPACT_IDENTIFIER_LEGACY,
};
/// Expected number of transactions where we can expect a speed-up by recovering the senders in
/// parallel.
pub static PARALLEL_SENDER_RECOVERY_THRESHOLD: LazyLock<usize> =

View File

@ -8,6 +8,24 @@ use derive_more::Display;
use reth_primitives_traits::InMemorySize;
use serde::{Deserialize, Serialize};
/// Identifier parameter for legacy transaction
#[cfg(any(test, feature = "reth-codec"))]
pub const COMPACT_IDENTIFIER_LEGACY: usize = 0;
/// Identifier parameter for EIP-2930 transaction
#[cfg(any(test, feature = "reth-codec"))]
pub const COMPACT_IDENTIFIER_EIP2930: usize = 1;
/// Identifier parameter for EIP-1559 transaction
#[cfg(any(test, feature = "reth-codec"))]
pub const COMPACT_IDENTIFIER_EIP1559: usize = 2;
/// For backwards compatibility purposes only 2 bits of the type are encoded in the identifier
/// parameter. In the case of a [`COMPACT_EXTENDED_IDENTIFIER_FLAG`], the full transaction type is
/// read from the buffer as a single byte.
#[cfg(any(test, feature = "reth-codec"))]
pub const COMPACT_EXTENDED_IDENTIFIER_FLAG: usize = 3;
/// Transaction Type
///
/// Currently being used as 2-bit type when encoding it to `reth_codecs::Compact` on
@ -256,7 +274,7 @@ impl Decodable for TxType {
mod tests {
use super::*;
use alloy_primitives::hex;
use reth_codecs::{txtype::*, Compact};
use reth_codecs::Compact;
use reth_primitives_traits::TxType as _;
use rstest::rstest;