I am running a Monad full node on a high-performance Hetzner server and performing tests on transaction submission latency.
The Setup and Observation
My application listens to new blocks via a WebSocket (WS) connection to my local node. Upon receiving a new block notification, it immediately submits a transaction.
Consistent Delay: A transaction submitted immediately after block N is consistently included in block N+3.
Minimal Software Latency: The internal latency from the time I receive the new block number until the transaction is submitted to my node is very low, approximately 20ms.
The Goal
I am looking for methods or configurations that could significantly increase the probability of transaction inclusion in the next block (N+1).
Actions Already Tested (Did Not Improve Inclusion Time)
Fixed Gas Cost: Used a fixed gas cost to bypass the transaction simulation step on my node.
High Fees: Set fixed, but very high, values for both max_fee_per_gas and max_priority_fee_per_gas.
Request for Guidance
Given the minimal internal latency, is this delay likely related to mempool prioritization logic or perhaps a specific node configuration parameter that could be optimized for submission speed?
Any guidance from experienced node operators or the core team is greatly appreciated.
This is a result of Monad’s async execution and what seems like a regular / reasonable amount of latency.
Looking at the supply chain makes this a bit clearer. At a given point in time:
Transactions that can be included in block N are being received by the proposer N
Block N-1 was built and is being proposed by proposer N-1 and voted on by all of the other validators (who are sending their votes to proposer N)
Block N-2 is being finalized and, simultaneously, executed by the execution client to figure out what state changes resulted from the transactions in Block N-2
Block N-3 is fully executed and ready to be viewed
Technically, there’s a window where block N-2 has completed execution and is viewable while the proposer for block N is still accepting new transactions, but latency usually covers that window for most connections… so I don’t think there’s anything unusual about what you’re seeing.
But just because there isn’t anything unusual about your results doesn’t mean that there aren’t ways to speed it up–it’s possible to be only one block behind if you have access to colocation with validators N and N-1 and a lot of spare compute to optimistically execute blocks before they’re voted on / pipelined. It’s just not default behavior.
As Thogard mentioned, that’s expected behaviour given Monad’s asynchronous execution pipeline.
Your 20ms internal latency is already fine; the delay comes from Monad’s intentional decoupling of consensus from execution, which is what enables 10,000 TPS and 400ms block times in the first place.
I’d like to add: If you want to dive deeper into why this pipeline exists and how it enables Monad’s performance, I’d recommend reading up on MonadBFT (consensus algorithm), RaptorCast (block propagation protocol), and Asynchronous Execution in Monad’s documentation (I can only post 2 links as a new user, but you can find all three topics in the Monad Architecture section of the docs).
@martines3000 Is your WebSocket connection subscribed to newHeads or monadNewHeads ? The former emits an event on block finalization and the latter on block propose. Block finalization lags block proposals by ~2 blocks, due to consensus needing a QC-of-QC to finalize. Subscribing to the finalized new block could explain the 3 block submission delay, because the chain tip is actually at N+2 at the time of transaction submission.
If you’re subscribed to monadNewHeads, let us know because we need to look into this delay. Async execution is irrelevant here because execution starts immediately after the block passes some basic consensus validity check. It doesn’t wait for block finalization