feat(bot): add fast inbox bot with public/private consumption probes and OTel metrics - #25443
Open
spalladino wants to merge 7 commits into
Open
feat(bot): add fast inbox bot with public/private consumption probes and OTel metrics#25443spalladino wants to merge 7 commits into
spalladino wants to merge 7 commits into
Conversation
…ycle Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ation schedule Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ks and replay probe Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… docs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…atch path Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
spalladino
force-pushed
the
spl/fi2-message-only-docs
branch
2 times, most recently
from
September 10, 2026 12:06
15e855e to
0df3fa2
Compare
… handling Addresses review findings on the inbox bot mode: - The saturation schedule now owns its run from the moment the batch is reserved, so a crash during the L1 wait cannot leave an orphan batch that reconciliation adopts and the schedule then follows with a second full-bucket send. Retention no longer deletes the batch a run is waiting on, and a run whose record is gone is closed instead of holding the schedule forever. A run waits for its replay probe before reporting a verdict. - L1 RPC failures are no longer read as negative evidence: only viem's BlockNotFoundError means a block is not canonical, and only TransactionReceiptNotFoundError means a batch has no receipt. Anything else propagates and leaves the batch state untouched for the next tick, rather than failing every in-flight batch as a reorg during an outage. - Message transitions are guarded by their expected state, so a consumption attempt that outlives its message's timeout no longer resurrects a terminal record and exports a second outcome for it. A re-mined receipt no longer rewrites the identity of a message whose attempt was built against the previous one; such a message is failed as a reorg instead. - A consumption whose effects do not carry the message nullifier is failed rather than completed. - Consumption dispatch honours maxPendingTxs, and the bot exits on stopWhenUnhealthy, neither of which the lifecycle path reached. - A batch's outcome, size and gas are exported once even if its receipt is resolved again. - The block relation re-checks canonicality after the insertion search, so a re-mine mid-search reports an unknown relation rather than a wrong one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
BOT_MODE=inboxto@aztec/bot: a continuous L1-to-L2 messaging probe that sends atomic Multicall3 batches through the Inbox and follows every message to consumption on L2, through both public and private execution, reporting latency and correctness as OTel metrics.No new Noir contract — it reuses
TestContract'sconsume_message_from_arbitrary_sender_public/_private. Every existing bot mode keeps its defaults and behaviour.Fixes A-1986.
What it does
BOT_TX_INTERVAL_SECONDS. In inbox mode that clock drives L1 batch starts, not L2 consumption; readiness and receipts are polled independently at ~1s.BOT_INBOX_SATURATION_INTERVAL_SECONDS=0disables it.Configuration
BOT_MODEtransferinbox.BOT_INBOX_MESSAGES_PER_BATCH4[1, 257].BOT_INBOX_CONSUME_MODEmixedmixed,publicorprivate.BOT_INBOX_SATURATION_INTERVAL_SECONDS864000disables.In inbox mode
BOT_L1_TO_L2_SEED_COUNTdefaults to 512 (an outstanding-message cap, not a seeded pipeline) andBOT_FOLLOW_CHAIN=NONEis rejected. Explicit overrides always win.Telemetry
16 instruments under
aztec.bot.inbox.*through the existingTelemetryClientand collector — no new collector, no push loop, no log scraping. Milestone counters, five stage-latency histograms, simulation/execution/check/failure counters, pending-work gauges and the saturation schedule. Attributes are bounded; no hash, address, index, block number, batch id, exception text or timestamp is ever a label. Instrument names, their Prometheus translations, example queries, worked configurations and the alerting recipe are inbot/README.md.Measured L1 gas
Multicall3
aggregate3, gas from estimation, measured against this branch:The 257th message costs 58,639 gas because it opens a bucket. The historical 2,212,595 execution-gas estimate from the design notes is not a limit and is not comparable — it excludes intrinsic gas, calldata and wrapper overhead and predates current bytecode.
Two bugs found on the way
BotRunner.update()calledstop(), which closed the KV store before recreating the bot. Pre-existing for every mode; it only became visible once a bot persisted state.update()now stops the bot and leaves the store open.sentcould be dispatched a second time once readiness landed after a public consumption. Dispatch now re-reads each candidate.Testing
@aztec/bot, clock-controlled over a fake L1 producer, a modelled chain and an in-memory recording meter.end-to-end/src/single-node/cross-chain/inbox_bot.test.ts: a mixed batch through both domains with a cross-domain replay rejection, a controlled same-block public success (the race is removed rather than retried), the 257-message batch with contiguous indices and real bucket rollover, and the gas measurements above. Passes in ~200s.Stacked on #25416.
🤖 Generated with Claude Code