Skip to content

Commit

Permalink
feat: add EIP2930 transactions (#138)
Browse files Browse the repository at this point in the history
**Motivation**

Add support for EIP2930 transaction

**Description**


Implements EIP2930Transaction  + required methods & traits
<!-- A clear and concise general description of the changes this PR
introduces -->

<!-- Link to issues: Resolves #111, Resolves #222 -->

Closes None, but will enable #135 to also close #24
  • Loading branch information
fmoletta authored Jul 11, 2024
1 parent c63e1ad commit b906eb0
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
8 changes: 6 additions & 2 deletions crates/core/src/types/engine/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use crate::rlp::decode::RLPDecode;
use crate::{rlp::error::RLPDecodeError, serde_utils};

use crate::types::{
compute_withdrawals_root, BlockBody, BlockHeader, EIP1559Transaction, LegacyTransaction,
Transaction, Withdrawal, DEFAULT_OMMERS_HASH,
compute_withdrawals_root, BlockBody, BlockHeader, EIP1559Transaction, EIP2930Transaction,
LegacyTransaction, Transaction, Withdrawal, DEFAULT_OMMERS_HASH,
};

#[allow(unused)]
Expand Down Expand Up @@ -73,6 +73,10 @@ impl EncodedTransaction {
match *tx_type {
// Legacy
0x0 => LegacyTransaction::decode(tx_bytes).map(Transaction::LegacyTransaction), // TODO: check if this is a real case scenario
// EIP2930
0x1 => {
EIP2930Transaction::decode(tx_bytes).map(Transaction::EIP2930Transaction)
}
// EIP1559
0x2 => {
EIP1559Transaction::decode(tx_bytes).map(Transaction::EIP1559Transaction)
Expand Down
98 changes: 98 additions & 0 deletions crates/core/src/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::rlp::{
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Transaction {
LegacyTransaction(LegacyTransaction),
EIP2930Transaction(EIP2930Transaction),
EIP1559Transaction(EIP1559Transaction),
}

Expand All @@ -32,6 +33,21 @@ pub struct LegacyTransaction {
pub s: U256,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EIP2930Transaction {
pub chain_id: u64,
pub nonce: u64,
pub gas_price: u64,
pub gas_limit: u64,
pub to: TxKind,
pub value: U256,
pub data: Bytes,
pub access_list: Vec<(Address, Vec<H256>)>,
pub signature_y_parity: bool,
pub signature_r: U256,
pub signature_s: U256,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EIP1559Transaction {
pub chain_id: u64,
Expand Down Expand Up @@ -72,6 +88,7 @@ impl Transaction {
pub fn tx_type(&self) -> TxType {
match self {
Transaction::LegacyTransaction(_) => TxType::Legacy,
Transaction::EIP2930Transaction(_) => TxType::EIP2930,
Transaction::EIP1559Transaction(_) => TxType::EIP1559,
}
}
Expand All @@ -81,6 +98,7 @@ impl RLPEncode for Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
match self {
Transaction::LegacyTransaction(t) => t.encode(buf),
Transaction::EIP2930Transaction(t) => t.encode(buf),
Transaction::EIP1559Transaction(t) => t.encode(buf),
};
}
Expand Down Expand Up @@ -128,6 +146,24 @@ impl RLPEncode for LegacyTransaction {
}
}

impl RLPEncode for EIP2930Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
Encoder::new(buf)
.encode_field(&self.chain_id)
.encode_field(&self.nonce)
.encode_field(&self.gas_price)
.encode_field(&self.gas_limit)
.encode_field(&self.to)
.encode_field(&self.value)
.encode_field(&self.data)
.encode_field(&self.access_list)
.encode_field(&self.signature_y_parity)
.encode_field(&self.signature_r)
.encode_field(&self.signature_s)
.finish();
}
}

impl RLPEncode for EIP1559Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
Encoder::new(buf)
Expand Down Expand Up @@ -175,6 +211,38 @@ impl RLPDecode for LegacyTransaction {
}
}

impl RLPDecode for EIP2930Transaction {
fn decode_unfinished(rlp: &[u8]) -> Result<(EIP2930Transaction, &[u8]), RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
let (chain_id, decoder) = decoder.decode_field("chain_id")?;
let (nonce, decoder) = decoder.decode_field("nonce")?;
let (gas_price, decoder) = decoder.decode_field("gas_price")?;
let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
let (to, decoder) = decoder.decode_field("to")?;
let (value, decoder) = decoder.decode_field("value")?;
let (data, decoder) = decoder.decode_field("data")?;
let (access_list, decoder) = decoder.decode_field("access_list")?;
let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
let (signature_r, decoder) = decoder.decode_field("signature_r")?;
let (signature_s, decoder) = decoder.decode_field("signature_s")?;

let tx = EIP2930Transaction {
chain_id,
nonce,
gas_price,
gas_limit,
to,
value,
data,
access_list,
signature_y_parity,
signature_r,
signature_s,
};
Ok((tx, decoder.finish()?))
}
}

impl RLPDecode for EIP1559Transaction {
fn decode_unfinished(rlp: &[u8]) -> Result<(EIP1559Transaction, &[u8]), RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
Expand Down Expand Up @@ -229,6 +297,27 @@ impl Transaction {
.finish();
recover_address(&tx.r, &tx.s, signature_y_parity, &Bytes::from(buf))
}
Transaction::EIP2930Transaction(tx) => {
let mut buf = vec![self.tx_type() as u8];
Encoder::new(&mut buf)
.encode_field(&tx.nonce)
.encode_field(&tx.gas_price)
.encode_field(&tx.gas_limit)
.encode_field(&tx.to)
.encode_field(&tx.value)
.encode_field(&tx.data)
.encode_field(&tx.access_list)
.encode_field(&tx.signature_y_parity)
.encode_field(&tx.signature_r)
.encode_field(&tx.signature_s)
.finish();
recover_address(
&tx.signature_r,
&tx.signature_s,
tx.signature_y_parity,
&Bytes::from(buf),
)
}
Transaction::EIP1559Transaction(tx) => {
let mut buf = vec![self.tx_type() as u8];
Encoder::new(&mut buf)
Expand All @@ -255,62 +344,71 @@ impl Transaction {
pub fn gas_limit(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.gas,
Transaction::EIP2930Transaction(tx) => tx.gas_limit,
Transaction::EIP1559Transaction(tx) => tx.gas_limit,
}
}

pub fn gas_price(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.gas_price,
Transaction::EIP2930Transaction(tx) => tx.gas_price,
Transaction::EIP1559Transaction(tx) => tx.max_fee_per_gas,
}
}

pub fn to(&self) -> TxKind {
match self {
Transaction::LegacyTransaction(tx) => tx.to.clone(),
Transaction::EIP2930Transaction(tx) => tx.to.clone(),
Transaction::EIP1559Transaction(tx) => TxKind::Call(tx.destination),
}
}

pub fn value(&self) -> U256 {
match self {
Transaction::LegacyTransaction(tx) => tx.value,
Transaction::EIP2930Transaction(tx) => tx.value,
Transaction::EIP1559Transaction(tx) => tx.amount,
}
}

pub fn max_priority_fee(&self) -> Option<u64> {
match self {
Transaction::LegacyTransaction(_tx) => None,
Transaction::EIP2930Transaction(_tx) => None,
Transaction::EIP1559Transaction(tx) => Some(tx.max_priority_fee_per_gas),
}
}

pub fn chain_id(&self) -> Option<u64> {
match self {
Transaction::LegacyTransaction(_tx) => None,
Transaction::EIP2930Transaction(tx) => Some(tx.chain_id),
Transaction::EIP1559Transaction(tx) => Some(tx.chain_id),
}
}

pub fn access_list(&self) -> Vec<(Address, Vec<H256>)> {
match self {
Transaction::LegacyTransaction(_tx) => Vec::new(),
Transaction::EIP2930Transaction(tx) => tx.access_list.clone(),
Transaction::EIP1559Transaction(tx) => tx.access_list.clone(),
}
}

pub fn nonce(&self) -> u64 {
match self {
Transaction::LegacyTransaction(tx) => tx.nonce,
Transaction::EIP2930Transaction(tx) => tx.nonce,
Transaction::EIP1559Transaction(tx) => tx.signer_nonce,
}
}

pub fn data(&self) -> &Bytes {
match self {
Transaction::LegacyTransaction(tx) => &tx.data,
Transaction::EIP2930Transaction(tx) => &tx.data,
Transaction::EIP1559Transaction(tx) => &tx.payload,
}
}
Expand Down

0 comments on commit b906eb0

Please sign in to comment.