Skip to content

Commit

Permalink
fix(builder): try underpriced bundle txns again
Browse files Browse the repository at this point in the history
  • Loading branch information
dancoombs committed Jan 17, 2024
1 parent 8af970f commit 8927cf5
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 66 deletions.
15 changes: 15 additions & 0 deletions crates/builder/src/bundle_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ where
BuilderMetrics::increment_bundle_txns_nonce_used(self.builder_index);
info!("Nonce used by external transaction")
}
TrackerUpdate::ReplacementUnderpriced => {
BuilderMetrics::increment_bundle_txn_replacement_underpriced(self.builder_index);
info!("Replacement transaction underpriced")
}
};
}

Expand Down Expand Up @@ -318,6 +322,7 @@ where
async fn send_bundle_with_increasing_gas_fees_inner(&self) -> anyhow::Result<SendBundleResult> {
let (nonce, mut required_fees) = self.transaction_tracker.get_nonce_and_required_fees()?;
let mut initial_op_count: Option<usize> = None;

for fee_increase_count in 0..=self.settings.max_fee_increases {
let Some(bundle_tx) = self.get_bundle_tx(nonce, required_fees).await? else {
self.emit(BuilderEvent::formed_bundle(
Expand Down Expand Up @@ -414,6 +419,12 @@ where
BuilderMetrics::increment_bundle_txns_nonce_used(self.builder_index);
bail!("nonce used by external transaction")
}
TrackerUpdate::ReplacementUnderpriced => {
BuilderMetrics::increment_bundle_txn_replacement_underpriced(
self.builder_index,
);
info!("Replacement transaction underpriced, increasing fees")
}
};
info!(
"Bundle transaction failed to mine after {fee_increase_count} fee increases (maxFeePerGas: {}, maxPriorityFeePerGas: {}).",
Expand Down Expand Up @@ -551,6 +562,10 @@ impl BuilderMetrics {
metrics::increment_counter!("builder_bundle_fee_increases", "builder_index" => builder_index.to_string());
}

fn increment_bundle_txn_replacement_underpriced(builder_index: u64) {
metrics::increment_counter!("builder_bundle_replacement_underpriced", "builder_index" => builder_index.to_string());
}

fn set_bundle_gas_stats(gas_limit: Option<U256>, gas_used: Option<U256>) {
if let Some(limit) = gas_limit {
metrics::counter!("builder_bundle_gas_limit", limit.as_u64());
Expand Down
30 changes: 15 additions & 15 deletions crates/builder/src/sender/bloxroute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use serde_json::value::RawValue;
use tokio::time;
use tonic::async_trait;

use crate::sender::{fill_and_sign, SentTxInfo, TransactionSender, TxStatus};
use super::{fill_and_sign, Result, SentTxInfo, TransactionSender, TxStatus};

pub(crate) struct PolygonBloxrouteTransactionSender<C, S>
where
Expand All @@ -57,17 +57,13 @@ where
&self,
tx: TypedTransaction,
_expected_storage: &ExpectedStorage,
) -> anyhow::Result<SentTxInfo> {
) -> Result<SentTxInfo> {
let (raw_tx, nonce) = fill_and_sign(&self.provider, tx).await?;
let tx_hash = self
.client
.send_transaction(raw_tx)
.await
.context("should send bloxroute polygon private tx")?;
let tx_hash = self.client.send_transaction(raw_tx).await?;
Ok(SentTxInfo { nonce, tx_hash })
}

async fn get_transaction_status(&self, tx_hash: H256) -> anyhow::Result<TxStatus> {
async fn get_transaction_status(&self, tx_hash: H256) -> Result<TxStatus> {
let tx = self
.provider
.get_transaction(tx_hash)
Expand All @@ -84,9 +80,13 @@ where
.unwrap_or(TxStatus::Pending))
}

async fn wait_until_mined(&self, tx_hash: H256) -> anyhow::Result<Option<TransactionReceipt>> {
Self::wait_until_mined_no_drop(tx_hash, Arc::clone(&self.raw_provider), self.poll_interval)
.await
async fn wait_until_mined(&self, tx_hash: H256) -> Result<Option<TransactionReceipt>> {
Ok(Self::wait_until_mined_no_drop(
tx_hash,
Arc::clone(&self.raw_provider),
self.poll_interval,
)
.await?)
}

fn address(&self) -> Address {
Expand All @@ -104,7 +104,7 @@ where
signer: S,
poll_interval: Duration,
auth_header: &str,
) -> anyhow::Result<Self> {
) -> Result<Self> {
Ok(Self {
provider: SignerMiddleware::new(Arc::clone(&provider), signer),
raw_provider: provider,
Expand All @@ -117,7 +117,7 @@ where
tx_hash: H256,
provider: Arc<Provider<C>>,
poll_interval: Duration,
) -> anyhow::Result<Option<TransactionReceipt>> {
) -> Result<Option<TransactionReceipt>> {
loop {
let tx = provider
.get_transaction(tx_hash)
Expand Down Expand Up @@ -154,7 +154,7 @@ impl PolygonBloxrouteClient {
Ok(Self { client })
}

async fn send_transaction(&self, raw_tx: Bytes) -> anyhow::Result<TxHash> {
async fn send_transaction(&self, raw_tx: Bytes) -> Result<TxHash> {
let request = BloxrouteRequest {
transaction: hex::encode(raw_tx),
};
Expand All @@ -171,7 +171,7 @@ struct BloxrouteRequest {
}

impl ToRpcParams for BloxrouteRequest {
fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, jsonrpsee::core::Error> {
fn to_rpc_params(self) -> std::result::Result<Option<Box<RawValue>>, jsonrpsee::core::Error> {
let s = String::from_utf8(serde_json::to_vec(&self)?).expect("Valid UTF8 format");
RawValue::from_string(s)
.map(Some)
Expand Down
15 changes: 7 additions & 8 deletions crates/builder/src/sender/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rundler_sim::ExpectedStorage;
use serde_json::json;
use tonic::async_trait;

use crate::sender::{fill_and_sign, SentTxInfo, TransactionSender, TxStatus};
use super::{fill_and_sign, Result, SentTxInfo, TransactionSender, TxStatus};

pub(crate) struct ConditionalTransactionSender<C, S>
where
Expand All @@ -47,7 +47,7 @@ where
&self,
tx: TypedTransaction,
expected_storage: &ExpectedStorage,
) -> anyhow::Result<SentTxInfo> {
) -> Result<SentTxInfo> {
let (raw_tx, nonce) = fill_and_sign(&self.provider, tx).await?;

let tx_hash = self
Expand All @@ -57,13 +57,12 @@ where
"eth_sendRawTransactionConditional",
(raw_tx, json!({ "knownAccounts": expected_storage })),
)
.await
.context("should send conditional raw transaction to node")?;
.await?;

Ok(SentTxInfo { nonce, tx_hash })
}

async fn get_transaction_status(&self, tx_hash: H256) -> anyhow::Result<TxStatus> {
async fn get_transaction_status(&self, tx_hash: H256) -> Result<TxStatus> {
let tx = self
.provider
.get_transaction(tx_hash)
Expand All @@ -80,10 +79,10 @@ where
})
}

async fn wait_until_mined(&self, tx_hash: H256) -> anyhow::Result<Option<TransactionReceipt>> {
PendingTransaction::new(tx_hash, self.provider.inner())
async fn wait_until_mined(&self, tx_hash: H256) -> Result<Option<TransactionReceipt>> {
Ok(PendingTransaction::new(tx_hash, self.provider.inner())
.await
.context("should wait for transaction to be mined or dropped")
.context("should wait for transaction to be mined or dropped")?)
}

fn address(&self) -> Address {
Expand Down
40 changes: 20 additions & 20 deletions crates/builder/src/sender/flashbots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use std::{
task::{Context as TaskContext, Poll},
};

use anyhow::{bail, Context, Result};
use anyhow::{anyhow, Context};
use ethers::{
middleware::SignerMiddleware,
providers::{interval, JsonRpcClient, Middleware, Provider},
Expand All @@ -42,7 +42,9 @@ use serde::{de, Deserialize, Serialize};
use serde_json::{value::RawValue, Value};
use tonic::async_trait;

use super::{fill_and_sign, ExpectedStorage, SentTxInfo, TransactionSender, TxStatus};
use super::{
fill_and_sign, ExpectedStorage, Result, SentTxInfo, TransactionSender, TxSenderError, TxStatus,
};

#[derive(Debug)]
pub(crate) struct FlashbotsTransactionSender<C, S>
Expand All @@ -64,19 +66,15 @@ where
&self,
tx: TypedTransaction,
_expected_storage: &ExpectedStorage,
) -> anyhow::Result<SentTxInfo> {
) -> Result<SentTxInfo> {
let (raw_tx, nonce) = fill_and_sign(&self.provider, tx).await?;

let tx_hash = self
.client
.send_transaction(raw_tx)
.await
.context("should send raw transaction to node")?;
let tx_hash = self.client.send_transaction(raw_tx).await?;

Ok(SentTxInfo { nonce, tx_hash })
}

async fn get_transaction_status(&self, tx_hash: H256) -> anyhow::Result<TxStatus> {
async fn get_transaction_status(&self, tx_hash: H256) -> Result<TxStatus> {
let status = self.client.status(tx_hash).await?;
Ok(match status.status {
FlashbotsAPITransactionStatus::Pending => TxStatus::Pending,
Expand All @@ -99,17 +97,17 @@ where
TxStatus::Pending
}
FlashbotsAPITransactionStatus::Failed | FlashbotsAPITransactionStatus::Unknown => {
bail!(
return Err(TxSenderError::Other(anyhow!(
"Transaction {tx_hash:?} failed in Flashbots with status {:?}",
status.status,
);
)));
}
FlashbotsAPITransactionStatus::Cancelled => TxStatus::Dropped,
})
}

async fn wait_until_mined(&self, tx_hash: H256) -> anyhow::Result<Option<TransactionReceipt>> {
PendingFlashbotsTransaction::new(tx_hash, self.provider.inner(), &self.client).await
async fn wait_until_mined(&self, tx_hash: H256) -> Result<Option<TransactionReceipt>> {
Ok(PendingFlashbotsTransaction::new(tx_hash, self.provider.inner(), &self.client).await?)
}

fn address(&self) -> Address {
Expand Down Expand Up @@ -178,20 +176,20 @@ struct FlashbotsClient {
}

impl FlashbotsClient {
fn new() -> Result<Self> {
fn new() -> anyhow::Result<Self> {
let client = HttpClientBuilder::default().build("https://rpc.flashbots.net")?;
Ok(Self { client })
}

async fn status(&self, tx_hash: H256) -> Result<FlashbotsAPIResponse> {
async fn status(&self, tx_hash: H256) -> anyhow::Result<FlashbotsAPIResponse> {
let url = format!("https://protect.flashbots.net/tx/{:?}", tx_hash);
let resp = reqwest::get(&url).await?;
resp.json::<FlashbotsAPIResponse>()
.await
.context("should deserialize FlashbotsAPIResponse")
}

async fn send_transaction(&self, raw_tx: Bytes) -> anyhow::Result<TxHash> {
async fn send_transaction(&self, raw_tx: Bytes) -> Result<TxHash> {
let response: FlashbotsResponse = self
.client
.request("eth_sendRawTransaction", (raw_tx,))
Expand All @@ -206,7 +204,7 @@ struct FlashbotsRequest {
}

impl ToRpcParams for FlashbotsRequest {
fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, jsonrpsee::core::Error> {
fn to_rpc_params(self) -> std::result::Result<Option<Box<RawValue>>, jsonrpsee::core::Error> {
let s = String::from_utf8(serde_json::to_vec(&self)?).expect("Valid UTF8 format");
RawValue::from_string(s)
.map(Some)
Expand Down Expand Up @@ -332,7 +330,7 @@ impl<'a, P: JsonRpcClient> Future for PendingFlashbotsTransaction<'a, P> {
}
}

fn deserialize_u64<'de, D>(deserializer: D) -> Result<U64, D::Error>
fn deserialize_u64<'de, D>(deserializer: D) -> std::result::Result<U64, D::Error>
where
D: de::Deserializer<'de>,
{
Expand All @@ -354,7 +352,7 @@ where
})
}

fn deserialize_optional_u256<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
fn deserialize_optional_u256<'de, D>(deserializer: D) -> std::result::Result<Option<U256>, D::Error>
where
D: de::Deserializer<'de>,
{
Expand All @@ -379,7 +377,9 @@ where
})
}

fn deserialize_optional_address<'de, D>(deserializer: D) -> Result<Option<Address>, D::Error>
fn deserialize_optional_address<'de, D>(
deserializer: D,
) -> std::result::Result<Option<Address>, D::Error>
where
D: de::Deserializer<'de>,
{
Expand Down
Loading

0 comments on commit 8927cf5

Please sign in to comment.