Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(bolt-sidecar): PooledTransactionsElement -> PooledTransaction #571

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions bolt-sidecar/src/builder/template.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::collections::HashMap;

use alloy::{
consensus::Transaction,
primitives::{Address, TxHash, U256},
Expand All @@ -9,6 +7,7 @@ use ethereum_consensus::{
deneb::mainnet::{Blob, BlobsBundle},
};
use reth_primitives::TransactionSigned;
use std::collections::HashMap;
use tracing::warn;

use crate::{
Expand Down Expand Up @@ -51,9 +50,7 @@ impl BlockTemplate {
pub fn as_signed_transactions(&self) -> Vec<TransactionSigned> {
self.signed_constraints_list
.iter()
.flat_map(|sc| {
sc.message.transactions.iter().map(|c| c.clone().into_inner().into_transaction())
})
.flat_map(|sc| sc.message.transactions.iter().map(|c| c.clone().into_signed()))
.collect()
}

Expand Down
10 changes: 6 additions & 4 deletions bolt-sidecar/src/common/transactions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use alloy::{consensus::Transaction, primitives::U256};
use reth_primitives::PooledTransactionsElement;
use alloy::{
consensus::{transaction::PooledTransaction, Transaction},
primitives::U256,
};

use crate::{primitives::AccountState, state::ValidationError};

Expand Down Expand Up @@ -34,7 +36,7 @@ pub fn calculate_max_basefee(current: u128, block_diff: u64) -> Option<u128> {
/// - For legacy transactions: `gas_price * gas_limit + tx_value`.
/// - For EIP-4844 blob transactions: `max_fee_per_gas * gas_limit + tx_value + max_blob_fee_per_gas
/// * blob_gas_used`.
pub fn max_transaction_cost(transaction: &PooledTransactionsElement) -> U256 {
pub fn max_transaction_cost(transaction: &PooledTransaction) -> U256 {
let gas_limit = transaction.gas_limit() as u128;

let mut fee_cap = transaction.max_fee_per_gas();
Expand All @@ -53,7 +55,7 @@ pub fn max_transaction_cost(transaction: &PooledTransactionsElement) -> U256 {
/// 2. The balance of the account must be higher than the transaction's max cost.
pub fn validate_transaction(
account_state: &AccountState,
transaction: &PooledTransactionsElement,
transaction: &PooledTransaction,
) -> Result<(), ValidationError> {
// Check if the nonce is correct (should be the same as the transaction count)
if transaction.nonce() < account_state.transaction_count {
Expand Down
2 changes: 1 addition & 1 deletion bolt-sidecar/src/primitives/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl InclusionRequest {
/// Recovers the signer of all transactions in the request.
pub fn recover_signers(&mut self) -> Result<(), SignatureError> {
for tx in &mut self.txs {
let signer = tx.recover_signer().ok_or(SignatureError)?;
let signer = tx.recover_signer().map_err(|_| SignatureError)?;
tx.sender = Some(signer);
}

Expand Down
93 changes: 58 additions & 35 deletions bolt-sidecar/src/primitives/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use std::{borrow::Cow, fmt};

use alloy::{
consensus::{BlobTransactionSidecar, Transaction, TxType},
consensus::{
transaction::PooledTransaction, BlobTransactionSidecar, Signed, Transaction, TxType,
Typed2718,
},
eips::eip2718::{Decodable2718, Encodable2718},
hex,
primitives::{Address, U256},
};
use reth_primitives::PooledTransactionsElement;
use reth_primitives::TransactionSigned;
use serde::{de, ser::SerializeSeq};
use std::{borrow::Cow, fmt};

/// Trait that exposes additional information on transaction types that don't already do it
/// by themselves (e.g. [`PooledTransactionsElement`]).
/// by themselves (e.g. [`PooledTransaction`]).
pub trait TransactionExt {
/// Returns the value of the transaction.
fn value(&self) -> U256;
Expand All @@ -22,31 +24,31 @@ pub trait TransactionExt {
fn size(&self) -> usize;
}

impl TransactionExt for PooledTransactionsElement {
impl TransactionExt for PooledTransaction {
fn value(&self) -> U256 {
match self {
Self::Legacy(transaction) => transaction.tx().value,
Self::Eip2930(transaction) => transaction.tx().value,
Self::Eip1559(transaction) => transaction.tx().value,
Self::BlobTransaction(blob_tx) => blob_tx.tx().tx.value,
_ => unimplemented!(),
Self::Eip2930(transaction) => transaction.tx().value,
Self::Eip4844(transaction) => transaction.tx().tx().value,
Self::Eip7702(transaction) => transaction.tx().value,
}
}

fn blob_sidecar(&self) -> Option<&BlobTransactionSidecar> {
match self {
Self::BlobTransaction(blob_tx) => Some(&blob_tx.tx().sidecar),
Self::Eip4844(transaction) => Some(&transaction.tx().sidecar),
_ => None,
}
}

fn size(&self) -> usize {
match self {
Self::Legacy(transaction) => transaction.tx().size(),
Self::Eip2930(transaction) => transaction.tx().size(),
Self::Eip1559(transaction) => transaction.tx().size(),
Self::BlobTransaction(blob_tx) => blob_tx.tx().tx.size(),
_ => unimplemented!(),
Self::Eip2930(transaction) => transaction.tx().size(),
Self::Eip4844(blob_tx) => blob_tx.tx().tx().size(),
Self::Eip7702(transaction) => transaction.tx().size(),
}
}
}
Expand All @@ -66,13 +68,13 @@ pub const fn tx_type_str(tx_type: TxType) -> &'static str {
#[derive(Clone, PartialEq, Eq)]
pub struct FullTransaction {
/// The transaction itself.
pub tx: PooledTransactionsElement,
pub tx: PooledTransaction,
/// The sender of the transaction, if recovered.
pub sender: Option<Address>,
}

impl From<PooledTransactionsElement> for FullTransaction {
fn from(tx: PooledTransactionsElement) -> Self {
impl From<PooledTransaction> for FullTransaction {
fn from(tx: PooledTransaction) -> Self {
Self { tx, sender: None }
}
}
Expand All @@ -81,33 +83,38 @@ impl fmt::Debug for FullTransaction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug_struct = f.debug_struct("FullTransaction");

match &self.tx {
PooledTransactionsElement::BlobTransaction(blob_tx) => {
if self.tx.is_eip4844() {
if let Some(tx) = self.tx.as_eip4844_with_sidecar() {
let sidecar = tx.sidecar();

let shortened_blobs: Vec<String> =
// Use alternative `Display` to print trimmed blob
blob_tx.tx().sidecar.blobs.iter().map(|blob| format!("{blob:#}")).collect();

debug_struct.field("tx", &"BlobTransaction");
debug_struct.field("hash", &blob_tx.hash());
debug_struct.field("transaction", &blob_tx.tx());
debug_struct.field("signature", &blob_tx.signature());

debug_struct.field("sidecar_blobs", &shortened_blobs);
debug_struct.field("sidecar_commitments", &blob_tx.tx().sidecar().commitments);
debug_struct.field("sidecar_proofs", &blob_tx.tx().sidecar.proofs);
}
other => {
debug_struct.field("tx", other);
sidecar.blobs.iter().map(|blob| format!("{blob:#}")).collect();

debug_struct
.field("tx", &"BlobTransaction")
.field("hash", self.tx.hash())
.field("transaction", &tx.tx())
.field("signature", &self.tx.signature())
.field("sidecar_blobs", &shortened_blobs)
.field("sidecar_commitments", &sidecar.commitments)
.field("sidecar_proofs", &sidecar.proofs);
} else {
// Blob transaction without sidecar
debug_struct
.field("tx", &"EIP-4844 Transaction (no sidecar)")
.field("hash", self.tx.hash());
}
}

// Non-blob transactions, just for debug
debug_struct.field("sender", &self.sender);
debug_struct.finish()
}
}

impl std::ops::Deref for FullTransaction {
type Target = PooledTransactionsElement;
type Target = PooledTransaction;

fn deref(&self) -> &Self::Target {
&self.tx
Expand All @@ -123,15 +130,31 @@ impl std::ops::DerefMut for FullTransaction {
impl FullTransaction {
/// Convenience method to parse a raw transaction into a `FullTransaction`.
pub fn decode_enveloped(data: impl AsRef<[u8]>) -> eyre::Result<Self> {
let tx = PooledTransactionsElement::decode_2718(&mut data.as_ref())?;
let tx = PooledTransaction::decode_2718(&mut data.as_ref())?;
Ok(Self { tx, sender: None })
}

/// Returns the inner transaction.
pub fn into_inner(self) -> PooledTransactionsElement {
pub fn into_inner(self) -> PooledTransaction {
self.tx
}

/// Returns the signed transaction.
pub fn into_signed(self) -> TransactionSigned {
match self.tx {
PooledTransaction::Legacy(tx) => tx.into(),
PooledTransaction::Eip1559(tx) => tx.into(),
PooledTransaction::Eip2930(tx) => tx.into(),
PooledTransaction::Eip4844(tx) => {
let sig = *tx.signature();
let hash = *tx.hash();
let inner_tx = tx.into_parts().0.into_parts().0;
Signed::new_unchecked(inner_tx, sig, hash).into()
}
PooledTransaction::Eip7702(tx) => tx.into(),
}
}

/// Returns the sender of the transaction, if recovered.
pub fn sender(&self) -> Option<&Address> {
self.sender.as_ref()
Expand Down Expand Up @@ -184,7 +207,7 @@ where

for s in hex_strings {
let data = hex::decode(s.trim_start_matches("0x")).map_err(de::Error::custom)?;
let tx = PooledTransactionsElement::decode_2718(&mut data.as_slice())
let tx = PooledTransaction::decode_2718(&mut data.as_slice())
.map_err(de::Error::custom)
.map(|tx| FullTransaction { tx, sender: None })?;
txs.push(tx);
Expand Down
21 changes: 8 additions & 13 deletions bolt-sidecar/src/state/execution.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use alloy::consensus::Transaction;
use alloy::{
consensus::{BlobTransactionValidationError, EnvKzgSettings, Transaction},
consensus::{BlobTransactionValidationError, EnvKzgSettings},
eips::eip4844::MAX_BLOBS_PER_BLOCK,
primitives::{Address, U256},
primitives::Address,
primitives::U256,
transports::TransportError,
};
use reth_primitives::PooledTransactionsElement;
use std::{collections::HashMap, ops::Deref};
use std::collections::HashMap;
use thiserror::Error;
use tracing::{debug, error, trace, warn};

Expand Down Expand Up @@ -382,32 +383,26 @@ impl<C: StateFetcher> ExecutionState<C> {
validate_transaction(&account_state_with_diffs, tx)?;

// Check EIP-4844-specific limits
if let Some(transaction) = tx.as_eip4844() {
if let Some(transaction) = tx.as_eip4844_with_sidecar() {
if let Some(template) = self.block_templates.get(&target_slot) {
if template.blob_count() >= MAX_BLOBS_PER_BLOCK {
return Err(ValidationError::Eip4844Limit);
}
}

let PooledTransactionsElement::BlobTransaction(ref blob_transaction) = tx.deref()
else {
unreachable!("EIP-4844 transaction should be a blob transaction")
};

// Calculate max possible increase in blob basefee
let max_blob_basefee = calculate_max_basefee(self.blob_basefee, slot_diff)
.ok_or(ValidationError::MaxBaseFeeCalcOverflow)?;

let blob_basefee = blob_transaction.0.tx().max_fee_per_blob_gas().unwrap_or(0);
let blob_basefee = transaction.max_fee_per_blob_gas().unwrap_or(0);

debug!(%max_blob_basefee, %blob_basefee, "Validating blob basefee");
if blob_basefee < max_blob_basefee {
return Err(ValidationError::BlobBaseFeeTooLow(max_blob_basefee));
}

// Validate blob against KZG settings
let sidecar = blob_transaction.0.tx().sidecar();
transaction.validate_blob(sidecar, self.kzg_settings.get())?;
transaction.validate_blob(self.kzg_settings.get())?;
}

// Increase the bundle nonce and balance diffs for this sender for the next iteration
Expand Down
Loading