Skip to content
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
2 changes: 1 addition & 1 deletion crates/node/builder/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ pub struct RpcAddOns<
/// Additional RPC add-ons.
pub hooks: RpcHooks<Node, EthB::EthApi>,
/// Builder for `EthApi`
eth_api_builder: EthB,
pub eth_api_builder: EthB,
/// Engine validator
engine_validator_builder: EV,
/// Builder for `EngineApi`
Expand Down
8 changes: 5 additions & 3 deletions crates/scroll/node/src/addons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use reth_scroll_chainspec::ScrollChainSpec;
use reth_scroll_engine_primitives::ScrollEngineTypes;
use reth_scroll_evm::ScrollNextBlockEnvAttributes;
use reth_scroll_primitives::ScrollPrimitives;
use reth_scroll_rpc::{eth::ScrollEthApiBuilder, ScrollEthApiError};
use reth_scroll_rpc::{
eth::{ScrollEthApiBuilder, DEFAULT_MIN_SUGGESTED_PRIORITY_FEE},
ScrollEthApiError,
};
use revm::context::TxEnv;
use scroll_alloy_evm::ScrollTransactionIntoTxEnv;
use scroll_alloy_network::Scroll;
Expand Down Expand Up @@ -148,8 +151,7 @@ impl<NetworkT> Default for ScrollAddOnsBuilder<NetworkT> {
Self {
sequencer_url: None,
payload_size_limit: SCROLL_DEFAULT_PAYLOAD_SIZE_LIMIT,
// TODO (scroll): update with default values.
min_suggested_priority_fee: 1_000_000,
min_suggested_priority_fee: DEFAULT_MIN_SUGGESTED_PRIORITY_FEE,
_nt: PhantomData,
rpc_middleware: Identity::new(),
}
Expand Down
25 changes: 24 additions & 1 deletion crates/scroll/rpc/src/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ impl<N: RpcNodeCore, Rpc: RpcConvert> ScrollEthApi<N, Rpc> {
sequencer_client: Option<SequencerClient>,
min_suggested_priority_fee: U256,
payload_size_limit: u64,
propagate_local_transactions: bool,
) -> Self {
let inner = Arc::new(ScrollEthApiInner {
eth_api,
min_suggested_priority_fee,
payload_size_limit,
sequencer_client,
propagate_local_transactions,
});
Self { inner }
}
Expand Down Expand Up @@ -277,6 +279,8 @@ pub struct ScrollEthApiInner<N: ScrollNodeCore, Rpc: RpcConvert> {
min_suggested_priority_fee: U256,
/// Maximum payload size
payload_size_limit: u64,
/// whether local transactions should be propagated.
propagate_local_transactions: bool,
}

impl<N: RpcNodeCore, Rpc: RpcConvert> ScrollEthApiInner<N, Rpc> {
Expand Down Expand Up @@ -316,6 +320,8 @@ pub struct ScrollEthApiBuilder<NetworkT = Scroll> {
min_suggested_priority_fee: u64,
/// Maximum payload size
payload_size_limit: u64,
/// whether local transactions should be propagated.
propagate_local_transactions: bool,
/// Marker for network types.
_nt: PhantomData<NetworkT>,
}
Expand All @@ -326,6 +332,7 @@ impl<NetworkT> Default for ScrollEthApiBuilder<NetworkT> {
sequencer_url: None,
min_suggested_priority_fee: DEFAULT_MIN_SUGGESTED_PRIORITY_FEE,
payload_size_limit: DEFAULT_PAYLOAD_SIZE_LIMIT,
propagate_local_transactions: true,
_nt: PhantomData,
}
}
Expand Down Expand Up @@ -354,6 +361,15 @@ impl<NetworkT> ScrollEthApiBuilder<NetworkT> {
self.payload_size_limit = limit;
self
}

/// With whether local transactions should be propagated.
pub const fn with_propagate_local_transactions(
&mut self,
propagate_local_transactions: bool,
) -> &mut Self {
self.propagate_local_transactions = propagate_local_transactions;
self
}
}

impl<N, NetworkT> EthApiBuilder<N> for ScrollEthApiBuilder<NetworkT>
Expand All @@ -367,7 +383,13 @@ where
type EthApi = ScrollEthApi<N, ScrollRpcConvert<N, NetworkT>>;

async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
let Self { min_suggested_priority_fee, payload_size_limit, sequencer_url, .. } = self;
let Self {
min_suggested_priority_fee,
payload_size_limit,
sequencer_url,
propagate_local_transactions,
..
} = self;
let rpc_converter = RpcConverter::new(ScrollReceiptConverter::default())
.with_mapper(ScrollTxInfoMapper::new(ctx.components.provider().clone()));

Expand All @@ -388,6 +410,7 @@ where
sequencer_client,
U256::from(min_suggested_priority_fee),
payload_size_limit,
propagate_local_transactions,
))
}
}
57 changes: 31 additions & 26 deletions crates/scroll/rpc/src/eth/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,40 +34,45 @@ where
let recovered = recover_raw_transaction(&tx)?;
let pool_transaction = <Self::Pool as TransactionPool>::Transaction::from_pooled(recovered);

// submit the transaction to the pool with a `Local` origin
let AddedTransactionOutcome { hash, .. } = self
.pool()
.add_transaction(TransactionOrigin::Local, pool_transaction.clone())
.await
.map_err(Self::Error::from_eth_err)?;

// On scroll, transactions are forwarded directly to the sequencer to be included in
// blocks that it builds.
if let Some(client) = self.raw_tx_forwarder().as_ref() {
if let Some(client) = self.raw_tx_forwarder() {
tracing::debug!(target: "scroll::rpc::eth", hash = %pool_transaction.hash(), "forwarding raw transaction to sequencer");

// Retain tx in local tx pool before forwarding to sequencer rpc, for local RPC usage.
let AddedTransactionOutcome { hash, .. } = self
.pool()
.add_transaction(TransactionOrigin::Local, pool_transaction.clone())
.await
.map_err(Self::Error::from_eth_err)?;

tracing::debug!(target: "scroll::rpc::eth", %hash, "successfully added transaction to local tx pool");

// Forward to remote sequencer RPC.
match client.forward_raw_transaction(&tx).await {
Ok(sequencer_hash) => {
tracing::debug!(target: "scroll::rpc::eth", local_hash=%hash, sequencer_hash=%sequencer_hash, "successfully forwarded transaction to sequencer");
}
Err(err) => {
tracing::warn!(target: "scroll::rpc::eth", %err, %hash, "failed to forward transaction to sequencer, but transaction is in local pool");
if self.inner.propagate_local_transactions {
// Forward to remote sequencer RPC asynchronously (fire and forget)
let client = client.clone();
tokio::spawn(async move {
match client.forward_raw_transaction(&tx).await {
Ok(sequencer_hash) => {
tracing::debug!(target: "scroll::rpc::eth", local_hash=%hash, %sequencer_hash, "successfully forwarded transaction to sequencer");
}
Err(err) => {
tracing::warn!(target: "scroll::rpc::eth", %err, local_hash=%hash, "failed to forward transaction to sequencer, but transaction is in local pool and will be propagated");
}
}
});
} else {
// Forward to remote sequencer RPC synchronously
match client.forward_raw_transaction(&tx).await {
Ok(sequencer_hash) => {
tracing::debug!(target: "scroll::rpc::eth", local_hash=%hash, %sequencer_hash, "successfully forwarded transaction to sequencer");
}
Err(err) => {
tracing::warn!(target: "scroll::rpc::eth", %err, local_hash=%hash, "failed to forward transaction to sequencer");
return Err(ScrollEthApiError::Sequencer(err));
}
}
}

return Ok(hash);
}

// submit the transaction to the pool with a `Local` origin
let AddedTransactionOutcome { hash, .. } = self
.pool()
.add_transaction(TransactionOrigin::Local, pool_transaction)
.await
.map_err(Self::Error::from_eth_err)?;

Ok(hash)
}
}
Expand Down