Skip to content

Commit

Permalink
[feat] Synchronous filling (alloy-rs#841)
Browse files Browse the repository at this point in the history
* fix: sync fill before async fill

* docs: improve em

* fix: fill provider behavior

* feat: more info in panic for filler loops
  • Loading branch information
prestwich authored and ben186 committed Jul 27, 2024
1 parent e24af22 commit 268add4
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 33 deletions.
2 changes: 2 additions & 0 deletions crates/provider/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ where
FillerControlFlow::Finished
}

fn fill_sync(&self, _tx: &mut SendableTx<N>) {}

async fn prepare<P, T>(
&self,
_provider: &P,
Expand Down
21 changes: 13 additions & 8 deletions crates/provider/src/fillers/chain_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ impl<N: Network> TxFiller<N> for ChainIdFiller {
}
}

fn fill_sync(&self, tx: &mut SendableTx<N>) {
if let Some(chain_id) = self.0.get() {
if let Some(builder) = tx.as_mut_builder() {
if builder.chain_id().is_none() {
builder.set_chain_id(*chain_id)
}
};
}
}

async fn prepare<P, T>(
&self,
provider: &P,
Expand All @@ -76,22 +86,17 @@ impl<N: Network> TxFiller<N> for ChainIdFiller {
Some(chain_id) => Ok(chain_id),
None => {
let chain_id = provider.get_chain_id().await?;
let chain_id = *self.0.get_or_init(|| chain_id);
Ok(chain_id)
Ok(*self.0.get_or_init(|| chain_id))
}
}
}

async fn fill(
&self,
fillable: Self::Fillable,
_fillable: Self::Fillable,
mut tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
if let Some(builder) = tx.as_mut_builder() {
if builder.chain_id().is_none() {
builder.set_chain_id(fillable)
}
};
self.fill_sync(&mut tx);
Ok(tx)
}
}
2 changes: 2 additions & 0 deletions crates/provider/src/fillers/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ impl<N: Network> TxFiller<N> for GasFiller {
FillerControlFlow::Ready
}

fn fill_sync(&self, _tx: &mut SendableTx<N>) {}

async fn prepare<P, T>(
&self,
provider: &P,
Expand Down
5 changes: 5 additions & 0 deletions crates/provider/src/fillers/join_fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ where
self.left.status(tx).absorb(self.right.status(tx))
}

fn fill_sync(&self, tx: &mut SendableTx<N>) {
self.left.fill_sync(tx);
self.right.fill_sync(tx);
}

async fn prepare<P, T>(
&self,
provider: &P,
Expand Down
46 changes: 29 additions & 17 deletions crates/provider/src/fillers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use gas::GasFiller;

mod join_fill;
pub use join_fill::JoinFill;
use tracing::error;

use crate::{
provider::SendableTx, Identity, PendingTransactionBuilder, Provider, ProviderLayer,
Expand Down Expand Up @@ -160,6 +161,11 @@ pub trait TxFiller<N: Network = Ethereum>: Clone + Send + Sync + std::fmt::Debug
self.status(tx).is_finished()
}

/// Performs any synchoronous filling. This should be called before
/// [`TxFiller::prepare`] and [`TxFiller::fill`] to fill in any properties
/// that can be filled synchronously.
fn fill_sync(&self, tx: &mut SendableTx<N>);

/// Prepares fillable properties, potentially by making an RPC request.
fn prepare<P, T>(
&self,
Expand Down Expand Up @@ -244,12 +250,29 @@ where
self.filler.join_with(other).layer(self.inner)
}

async fn fill_inner(&self, mut tx: SendableTx<N>) -> TransportResult<SendableTx<N>> {
let mut count = 0;

while self.filler.continue_filling(&tx) {
self.filler.fill_sync(&mut tx);
tx = self.filler.prepare_and_fill(&self.inner, tx).await?;

count += 1;
if count >= 20 {
const ERROR: &str = "Tx filler loop detected. This indicates a bug in some filler implementation. Please file an issue containing this message.";
error!(
?tx, ?self.filler,
ERROR
);
panic!("{}, {:?}, {:?}", ERROR, &tx, &self.filler);
}
}
Ok(tx)
}

/// Fills the transaction request, using the configured fillers
pub async fn fill(&self, tx: N::TransactionRequest) -> TransportResult<SendableTx<N>>
where
N::TxEnvelope: Clone,
{
self.filler.prepare_and_fill(self, SendableTx::Builder(tx)).await
pub async fn fill(&self, tx: N::TransactionRequest) -> TransportResult<SendableTx<N>> {
self.fill_inner(SendableTx::Builder(tx)).await
}
}

Expand All @@ -270,18 +293,7 @@ where
&self,
mut tx: SendableTx<N>,
) -> TransportResult<PendingTransactionBuilder<'_, T, N>> {
let mut count = 0;

while self.filler.continue_filling(&tx) {
tx = self.filler.prepare_and_fill(&self.inner, tx).await?;

count += 1;
if count >= 20 {
panic!(
"Tx filler loop detected. This indicates a bug in some filler implementation. Please file an issue containing your tx filler set."
);
}
}
tx = self.fill_inner(tx).await?;

if let Some(builder) = tx.as_builder() {
if let FillerControlFlow::Missing(missing) = self.filler.status(builder) {
Expand Down
2 changes: 2 additions & 0 deletions crates/provider/src/fillers/nonce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ impl<N: Network> TxFiller<N> for NonceFiller {
FillerControlFlow::Ready
}

fn fill_sync(&self, _tx: &mut SendableTx<N>) {}

async fn prepare<P, T>(
&self,
provider: &P,
Expand Down
17 changes: 9 additions & 8 deletions crates/provider/src/fillers/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ where
}
}

fn fill_sync(&self, tx: &mut SendableTx<N>) {
if let Some(builder) = tx.as_mut_builder() {
if builder.from().is_none() {
builder.set_from(self.signer.default_signer_address());
}
}
}

async fn prepare<P, T>(
&self,
_provider: &P,
Expand All @@ -85,18 +93,11 @@ where
_fillable: Self::Fillable,
tx: SendableTx<N>,
) -> TransportResult<SendableTx<N>> {
let mut builder = match tx {
let builder = match tx {
SendableTx::Builder(builder) => builder,
_ => return Ok(tx),
};

if builder.from().is_none() {
builder.set_from(self.signer.default_signer_address());
if !builder.can_build() {
return Ok(SendableTx::Builder(builder));
}
}

let envelope = builder.build(&self.signer).await.map_err(RpcError::local_usage)?;

Ok(SendableTx::Envelope(envelope))
Expand Down

0 comments on commit 268add4

Please sign in to comment.