mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
feat: start implementing OpTransaction (#12529)
Co-authored-by: Emilia Hane <elsaemiliaevahane@gmail.com>
This commit is contained in:
@ -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 = [
|
||||
|
||||
@ -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;
|
||||
|
||||
173
crates/optimism/primitives/src/transaction/mod.rs
Normal file
173
crates/optimism/primitives/src/transaction/mod.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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> =
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user