flashblocks: track tx time-to-inclusion within a flashblock#465
flashblocks: track tx time-to-inclusion within a flashblock#465bitwiseguy wants to merge 17 commits intoflashbots:mainfrom
Conversation
There was a problem hiding this comment.
Potential Issues:
pending_flashblock_marksunbounded growth — The 20s TTL eviction only runs during RemoveConfirmed flush events. If no blocks are being confirmed (e.g., chain stall), marks from foreign tx hashes could accumulate indefinitely. Consider also evicting in the main loop periodically, or capping the map size.flashblock_latency_ms()uses .unwrap() on try_into() — At tx_actor.rs the u128 -> u64 conversion uses .try_into().unwrap(). While saturating_sub prevents the result from being huge in practice, if both timestamps are very large u128 values, the difference could theoretically exceed u64::MAX. A try_into().unwrap_or(u64::MAX) would be safer.- No reconnection in flashblocks_listener — The PR description mentions "automatic reconnection" but the implementation cancels the token and returns on connection loss. This means a transient WS disconnect kills flashblock tracking for the entire run. Consider a retry loop with backoff.
- Burst → Delay missed-tick behavior — This is a meaningful behavioral change. Delay means that if a batch takes longer than the interval, subsequent ticks shift forward rather than catching up. This is probably the right call for this use case, but worth noting, perhaps in the changelog, since it changes throughput characteristics under load.
- Batch start timestamp before HTTP POST — Good fix for accuracy. However, for non-batch (single tx) sends, I don't see the same treatment — the RuntimeTxInfo::default() still uses SystemTime::now() at construction. Worth verifying that single-tx sends also capture the timestamp before the RPC call.
Minor Suggestions
- FlashblockTimeToInclusionChart::echart_data() — Sparse bucket filtering removes empty interior buckets (e.g., if you have 0-100ms and 300-400ms, buckets 1-2 are dropped). This makes the histogram non-contiguous which could be confusing visually. Consider keeping empty buckets between min and max for a proper histogram shape.
- ws_message_to_text — Message::Text(t) => Some(t.to_string()) — t is already a String in tungstenite 0.26, so .to_string() is a no-op clone. Could just use Some(t) if the type matches.
- Heatmap chart with --skip-tx-traces — The tx_gas_used chart shows a "no data" message when empty, but the heatmap chart doesn't get the same treatment. Users with --skip-tx-traces will see an empty heatmap section with no explanation.
consolidate flashblocks code to a module, add custom error types
Capped the map size at 1024.
Done.
The pr description was wrong based on the latest implementation. The code now fails and returns an error if the ws connection is broken because it would lose flashblocks and distort results.
Yes this behavioral change is intentional.
Good catch. The single-tx path was relying on Fixed by removing
Done.
In tungstenite 0.26,
The heatmap already had a "no data" message, but it was misleading. Updated the message |
acb4d35 to
959a31b
Compare
Flashblocks feature
When
--flashblocks-ws-urlis provided, contender connects to a flashblocks WebSocket endpoint that auto-streams flashblocks. Each flashblock containsmetadata.receiptskeyed by tx hash — contender matches these against its pending tx cache to record when each tx first appeared in a flashblock.A preflight check validates the ws endpoint on startup. Since flashblock diffs may arrive before the
SentRunTxmessage is processed by the actor, marks are buffered in apending_flashblock_marksmap and applied retroactively.Two new report charts are conditionally rendered when flashblock data is present:
Additional changes
--skip-tx-tracesflag to speed up report generation by skippingdebug_traceTransactioncallseth_blobBaseFeeRPC calls for non-EIP-4844 tx typesBursttoDelayto prevent cascading immediate ticksBreaking Change
run_txstable addsflashblock_latencyandflashblock_indexcolumns;start_timestampandend_timestampnow store milliseconds instead of seconds. Existing databases are incompatible.Related Issue