Skip to content

Commit

Permalink
wip: tests
Browse files Browse the repository at this point in the history
  • Loading branch information
prestwich committed Apr 5, 2024
1 parent bc3bc80 commit 8022cc8
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 69 deletions.
12 changes: 12 additions & 0 deletions crates/eips/src/eip2930.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ pub struct AccessList(
pub Vec<AccessListItem>,
);

impl From<Vec<AccessListItem>> for AccessList {
fn from(list: Vec<AccessListItem>) -> Self {
Self(list)
}
}

impl From<AccessList> for Vec<AccessListItem> {
fn from(this: AccessList) -> Self {
this.0
}
}

impl AccessList {
/// Converts the list into a vec, expected by revm
pub fn flattened(&self) -> Vec<(Address, Vec<U256>)> {
Expand Down
8 changes: 8 additions & 0 deletions crates/network/src/any/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ impl TransactionBuilder<AnyNetwork> for WithOtherFields<TransactionRequest> {
self.deref_mut().set_blob_sidecar(sidecar)
}

fn can_build(&self) -> bool {
self.deref().can_build()
}

fn can_submit(&self) -> bool {
self.deref().can_submit()
}

fn build_unsigned(self) -> BuilderResult<<AnyNetwork as Network>::UnsignedTx> {
build_unsigned::<AnyNetwork>(self.inner)
}
Expand Down
32 changes: 28 additions & 4 deletions crates/network/src/ethereum/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
};
use alloy_consensus::{
BlobTransactionSidecar, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxLegacy,
TypedTransaction,
};
use alloy_primitives::{Address, TxKind, U256, Bytes, ChainId};
use alloy_rpc_types::{request::TransactionRequest, AccessList};
Expand Down Expand Up @@ -99,10 +100,6 @@ impl TransactionBuilder<Ethereum> for TransactionRequest {
self.gas = Some(gas_limit);
}

fn build_unsigned(self) -> BuilderResult<<Ethereum as Network>::UnsignedTx> {
build_unsigned::<Ethereum>(self)
}

fn access_list(&self) -> Option<&AccessList> {
self.access_list.as_ref()
}
Expand All @@ -120,6 +117,33 @@ impl TransactionBuilder<Ethereum> for TransactionRequest {
self.sidecar = Some(sidecar);
}

fn can_submit(&self) -> bool {
// value and data may be None. If they are, they will be set to default.
// gas fields and nonce may be None, if they are, they will be populated
// with default values by the RPC server
self.to.is_some() && self.from.is_some()
}

fn can_build(&self) -> bool {
// value and data may be none. If they are, they will be set to default
// values.

// chain_id and from may be none.
let common = self.to.is_some() && self.gas.is_some() && self.nonce.is_some();

let legacy = self.gas_price.is_some();
let eip2930 = legacy && self.access_list().is_some();

let eip1559 = self.max_fee_per_gas.is_some() && self.max_priority_fee_per_gas.is_some();

let eip4844 = eip1559 && self.sidecar.is_some();
common && (legacy || eip2930 || eip1559 || eip4844)
}

fn build_unsigned(self) -> BuilderResult<TypedTransaction> {
build_unsigned::<Ethereum>(self)
}

async fn build<S: NetworkSigner<Ethereum>>(
self,
signer: &S,
Expand Down
10 changes: 5 additions & 5 deletions crates/network/src/ethereum/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl EthereumSigner {
Self(Arc::new(signer))
}

async fn sign_transaction(
async fn sign_transaction_inner(
&self,
tx: &mut dyn SignableTransaction<Signature>,
) -> alloy_signer::Result<Signature> {
Expand All @@ -47,19 +47,19 @@ impl NetworkSigner<Ethereum> for EthereumSigner {
async fn sign_transaction(&self, tx: TypedTransaction) -> alloy_signer::Result<TxEnvelope> {
match tx {
TypedTransaction::Legacy(mut t) => {
let sig = self.sign_transaction(&mut t).await?;
let sig = self.sign_transaction_inner(&mut t).await?;
Ok(t.into_signed(sig).into())
}
TypedTransaction::Eip2930(mut t) => {
let sig = self.sign_transaction(&mut t).await?;
let sig = self.sign_transaction_inner(&mut t).await?;
Ok(t.into_signed(sig).into())
}
TypedTransaction::Eip1559(mut t) => {
let sig = self.sign_transaction(&mut t).await?;
let sig = self.sign_transaction_inner(&mut t).await?;
Ok(t.into_signed(sig).into())
}
TypedTransaction::Eip4844(mut t) => {
let sig = self.sign_transaction(&mut t).await?;
let sig = self.sign_transaction_inner(&mut t).await?;
Ok(t.into_signed(sig).into())
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ pub trait ReceiptResponse {
/// Networks are only containers for types, so it is recommended to use ZSTs for their definition.
// todo: block responses are ethereum only, so we need to include this in here too, or make `Block`
// generic over tx/header type
pub trait Network: Clone + Copy + Sized + Send + Sync + 'static {
pub trait Network: std::fmt::Debug + Clone + Copy + Sized + Send + Sync + 'static {
// -- Consensus types --

/// The network transaction envelope type.
type TxEnvelope: Eip2718Envelope;
type TxEnvelope: Eip2718Envelope + std::fmt::Debug;

/// An enum over the various transaction types.
type UnsignedTx;
Expand Down
8 changes: 8 additions & 0 deletions crates/network/src/transaction/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ pub trait TransactionBuilder<N: Network>: Default + Sized + Send + Sync + 'stati
self
}

/// True if the builder contains all necessary information to be submitted
/// to the `eth_sendTransaction` endpoint.
fn can_submit(&self) -> bool;

/// True if the builder contains all necessary information to be built into
/// a valid transaction.
fn can_build(&self) -> bool;

/// Build an unsigned, but typed, transaction.
fn build_unsigned(self) -> BuilderResult<N::UnsignedTx>;

Expand Down
13 changes: 11 additions & 2 deletions crates/network/src/transaction/signer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::Network;
use crate::{Network, TransactionBuilder};
use alloy_consensus::SignableTransaction;
use async_trait::async_trait;

Expand All @@ -9,9 +9,18 @@ use async_trait::async_trait;
/// [`TxSigner`] to signify signing capability for specific signature types.
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait NetworkSigner<N: Network>: Send + Sync {
pub trait NetworkSigner<N: Network>: std::fmt::Debug + Send + Sync {
/// Asynchronously sign an unsigned transaction.
async fn sign_transaction(&self, tx: N::UnsignedTx) -> alloy_signer::Result<N::TxEnvelope>;

/// Asynchronously sign a transaction request.
async fn sign_request(
&self,
request: N::TransactionRequest,
) -> alloy_signer::Result<N::TxEnvelope> {
let tx = request.build_unsigned().map_err(alloy_signer::Error::other)?;
self.sign_transaction(tx).await
}
}

/// Asynchronous transaction signer, capable of signing any [`SignableTransaction`] for the given
Expand Down
8 changes: 6 additions & 2 deletions crates/provider/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ where
Ok(())
}

fn fill(&self, _to_fill: Self::Fillable, _tx: &mut SendableTx<N>) {
// Do nothing
async fn fill(
&self,
_to_fill: Self::Fillable,
tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
Ok(tx)
}
}

Expand Down
20 changes: 11 additions & 9 deletions crates/provider/src/fillers/chain_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,16 @@ impl<N: Network> TxFiller<N> for ChainIdFiller {
}
}

fn fill(&self, fillable: Self::Fillable, tx: &mut SendableTx<N>) {
let tx = match tx {
SendableTx::Builder(tx) => tx,
_ => return,
};

if tx.chain_id().is_none() {
tx.set_chain_id(fillable);
}
async fn fill(
&self,
fillable: Self::Fillable,
mut tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
tx.as_mut_builder().map(|tx| {
if tx.chain_id().is_none() {
tx.set_chain_id(fillable)
}
});
Ok(tx)
}
}
24 changes: 14 additions & 10 deletions crates/provider/src/fillers/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,23 @@ impl<N: Network> TxFiller<N> for GasFiller {
if tx.gas_price().is_some() && tx.gas_limit().is_some() {
return FillerControlFlow::Finished;
}

// 4844
if tx.max_fee_per_blob_gas().is_some()
&& tx.max_fee_per_gas().is_some()
&& tx.max_priority_fee_per_gas().is_some()
{
return FillerControlFlow::Finished;
}

// eip1559
if tx.blob_sidecar().is_none()
&& tx.max_fee_per_gas().is_some()
&& tx.max_priority_fee_per_gas().is_some()
{
return FillerControlFlow::Finished;
}

FillerControlFlow::Ready
}

Expand All @@ -213,13 +216,12 @@ impl<N: Network> TxFiller<N> for GasFiller {
}
}

fn fill(&self, fillable: Self::Fillable, tx: &mut SendableTx<N>) {
let tx = match tx {
SendableTx::Builder(tx) => tx,
_ => return,
};

match fillable {
async fn fill(
&self,
fillable: Self::Fillable,
mut tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
tx.as_mut_builder().map(|tx| match fillable {
GasFillable::Legacy { gas_limit, gas_price } => {
tx.set_gas_limit(gas_limit);
tx.set_gas_price(gas_price);
Expand All @@ -235,7 +237,8 @@ impl<N: Network> TxFiller<N> for GasFiller {
tx.set_max_priority_fee_per_gas(estimate.max_priority_fee_per_gas);
tx.set_max_fee_per_blob_gas(max_fee_per_blob_gas);
}
}
});
Ok(tx)
}
}

Expand All @@ -245,7 +248,7 @@ mod tests {
use super::*;
use crate::ProviderBuilder;
use alloy_primitives::address;
use alloy_rpc_types::TransactionRequest;
use alloy_rpc_types::{AccessListItem, TransactionRequest};

#[tokio::test]
async fn no_gas_price_or_limit() {
Expand Down Expand Up @@ -299,7 +302,8 @@ mod tests {
from: Some(anvil.addresses()[0]),
value: Some(U256::from(100)),
to: address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045").into(),
// chain_id: Some(31337), Not required as this will fallback to legacy_tx
access_list: Some(vec![Default::default()].into()),
// chain_id: Some(31337), Not required as access list causes legacy gassing
..Default::default()
};

Expand Down
34 changes: 25 additions & 9 deletions crates/provider/src/fillers/join_fill.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
provider::SendableTx, PendingTransactionBuilder, Provider, ProviderLayer, RootProvider,
};
use alloy_json_rpc::RpcError;
use alloy_network::{Ethereum, Network};
use alloy_transport::{Transport, TransportResult};
use async_trait::async_trait;
Expand Down Expand Up @@ -98,7 +99,7 @@ impl FillerControlFlow {
/// [`TxFiller::status`] should return [`FillerControlFlow::Ready`].
/// - **Finished**: The filler has filled in all properties that it can fill.
/// [`TxFiller::status`] should return [`FillerControlFlow::Finished`].
pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync {
pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync + std::fmt::Debug {
/// The properties that this filler retrieves from the RPC. to fill in the
/// TransactionRequest.
type Fillable: Send + Sync + 'static;
Expand Down Expand Up @@ -142,13 +143,17 @@ pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync {
T: Transport + Clone;

/// Fills in the transaction request with the fillable properties.
fn fill(&self, fillable: Self::Fillable, tx: &mut SendableTx<N>);
fn fill(
&self,
fillable: Self::Fillable,
tx: SendableTx<N>,
) -> impl_future!(<Output = TransportResult<SendableTx<N>>>);

/// Prepares and fills the transaction request with the fillable properties.
fn prepare_and_fill<P, T>(
&self,
provider: &P,
mut tx: SendableTx<N>,
tx: SendableTx<N>,
) -> impl_future!(<Output = TransportResult<SendableTx<N>>>)
where
P: Provider<T, N>,
Expand All @@ -161,9 +166,7 @@ pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync {

let fillable = self.prepare(provider, tx.as_builder().unwrap()).await?;

self.fill(fillable, &mut tx);

Ok(tx)
self.fill(fillable, tx).await
}
}
}
Expand Down Expand Up @@ -250,13 +253,18 @@ where
try_join!(self.prepare_left(provider, tx), self.prepare_right(provider, tx))
}

fn fill(&self, to_fill: Self::Fillable, tx: &mut SendableTx<N>) {
async fn fill(
&self,
to_fill: Self::Fillable,
mut tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
if let Some(to_fill) = to_fill.0 {
self.left.fill(to_fill, tx);
tx = self.left.fill(to_fill, tx).await?;
};
if let Some(to_fill) = to_fill.1 {
self.right.fill(to_fill, tx);
tx = self.right.fill(to_fill, tx).await?;
};
Ok(tx)
}
}

Expand Down Expand Up @@ -350,6 +358,14 @@ where
}
}

if let Some(builder) = tx.as_builder() {
if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
// TODO: improve this.
let message = format!("missing properties: {:?}", missing);
return Err(RpcError::make_err_resp(-42069, message));
}
}

// Errors in tx building happen further down the stack.
self.inner.send_transaction_internal(tx).await
}
Expand Down
Loading

0 comments on commit 8022cc8

Please sign in to comment.