feat: add RPC endpoints to manipulate time#22084
Conversation
0d144cb to
9d67fa9
Compare
This stack of pull requests is managed by Graphite. Learn more about stacking. |
51b33a2 to
5d00440
Compare
c7c7580 to
b715407
Compare
| signalHandlers.push(stop); | ||
| services.node = [node, AztecNodeApiSchema]; | ||
| adminServices.node = [node, AztecNodeAdminApiSchema]; | ||
| adminServices.nodeDebug = [node, AztecNodeDebugApiSchema]; |
There was a problem hiding this comment.
This code is quite foreign to me so I asked this to AI:
so this seems reasonable.
If the debug interface got accidentally exposed in prod in its current form then there would not be much damage to do as the function would error out with the warping methods but anyway there is a danger of us adding more powerful methods on the interface, then accidentally exposing this in prod and then bad things happening.
Do you think we should somehow guardrail this more such that via some code changes we don't accidentally expose this?
There was a problem hiding this comment.
Yeah, we introduced the idea of a debug API recently to support testing. I would only create add this schema if a particular env var is turned on (e.g. AZTEC_DEBUG=true)
b715407 to
061ad4f
Compare
0749b9f to
fcfc5d6
Compare
77c7a7c to
41bb0d0
Compare
| signalHandlers.push(stop); | ||
| services.node = [node, AztecNodeApiSchema]; | ||
| adminServices.node = [node, AztecNodeAdminApiSchema]; | ||
| adminServices.nodeDebug = [node, AztecNodeDebugApiSchema]; |
There was a problem hiding this comment.
Yeah, we introduced the idea of a debug API recently to support testing. I would only create add this schema if a particular env var is turned on (e.g. AZTEC_DEBUG=true)
41bb0d0 to
3ee69b3
Compare
| --local-network.noPXE ($NO_PXE) | ||
| Do not expose PXE service on local network start |
There was a problem hiding this comment.
The NO_PXE flag was archaic and no longer used (pxe is never exposed as standalone service) so I sneaked this change here.
| signalHandlers.push(stop); | ||
| services.node = [node, AztecNodeApiSchema]; | ||
| adminServices.node = [node, AztecNodeAdminApiSchema]; | ||
| services.nodeDebug = [node, AztecNodeDebugApiSchema]; |
There was a problem hiding this comment.
In local network mode we automatically expose this so that people don't need to go through the hassle of setting the env var in test environments.
| const { startNode } = await import('./cmds/start_node.js'); | ||
| const networkName = getActiveNetworkName(options.network); | ||
| ({ config } = await startNode(options, signalHandlers, services, adminServices, userLog, networkName)); | ||
| if (options.nodeDebug && services.node) { |
There was a problem hiding this comment.
In the non-local-network setting the env var has to be explicitly set.
|
❌ Failed to cherry-pick to |
…23213) ## Summary Fixes the merge-queue failure in `e2e_blacklist_token_contract/shielding` ([CI run](http://ci.aztec-labs.com/d5485e6652b3f32a)) where every test fails in `applyMint` with `Invalid tx: Invalid expiration timestamp`. ## Root cause `warpL2TimeAtLeastTo` (introduced in #22084) calls `eth.warp` followed by `node.mineBlock()`. The sequencer's polling loop captures `nowSeconds`/`slot` at the top of each `work()` cycle. An in-flight cycle that started just before the warp will mine an L2 block at the *pre-warp* slot — L1 sync prunes that block from the canonical chain, but it lingers in local world state and the PXE anchors subsequent txs against it. With `MAX_TX_LIFETIME == CHANGE_ROLES_DELAY == 86400s`, the resulting `expiration_timestamp` lands exactly on the post-warp slot boundary and the validator rejects the tx as soon as the wall-clock crosses to the next slot. ## Fix After `eth.warp`, retry `mineBlock` until the latest L2 block's slot is at or past the slot corresponding to the warped timestamp. The first `mineBlock` may return a stale block produced by an in-flight cycle; the next triggers a fresh sequencer cycle that reads the post-warp time and builds a block at the post-warp slot. Subsequent txs then anchor against a fresh block whose `expiration_timestamp` is well in the future. The signature of `warpL2TimeAtLeastTo`/`warpL2TimeAtLeastBy` widens from `AztecNodeDebug` to `AztecNode & AztecNodeDebug` so we can read the latest block via `getBlockData('latest')`. All current callers already type their node as the intersection. This re-applies the diagnosis from the prior #22796 (which never merged), adapted to the current `getBlockData('latest')` API. Full analysis: https://gist.github.com/AztecBot/67815cbe3c3f853d97ec3345dfb0c985 ## Test plan - `e2e_blacklist_token_contract/shielding` (originally failing) - `e2e_blacklist_token_contract/{access_control,burn,minting,transfer_*,unshielding}` — share `applyBaseSetup` → `crossTimestampOfChange` - `e2e_contract_updates` - `composed/e2e_cheat_codes` (verifies the type-widening change still resolves the methods correctly) ClaudeBox log: https://claudebox.work/s/28594b4dc64f1cd0?run=1

The goal of this PR is to give devs an easy way to manipulate L2 block time in test environments. Since this only for testing we don't want to clutter AztecNodeService with too much of this functionality. For this reason the following approach was implemented:
AztecNodeDebuginterface and this endpoint is functional only in test environment,AnvilTestWatcherwas mentioned by Palla, is there a risk of us not using in some test env?)CheatCodesclass that performs this L1 warping and L2 mining automatically.AZTEC_NODE_DEBUGenv varThe debug endpoint (
mineBlock) is gated behind a newAZTEC_NODE_DEBUGenv var /--node-debugCLI flag. When set, it exposes theAztecNodeDebuginterface on the main RPC port.--local-networkauto-enables it — devs runningaztec start --local-networkgetmineBlockby default without extra config.--noderequires explicit opt-in viaAZTEC_NODE_DEBUG=trueor--node-debug.Composed e2e test
The
e2e_cheat_codestest was rewritten as a composed test (src/composed/e2e_cheat_codes.test.ts) that runs against a remote local-network node via RPC, rather than spinning up an in-process node. This validates that the time manipulation cheat codes work end-to-end over the JSON-RPC boundary.Why we need
mineBlockon node?Note that I tried to minimize the impact on the node but we need to add the
mineBlockmethod on the node because we need to trigger block getting mined and we cannot get a hold of theSequencerClientin all the places where we want to use this functionality - this is typically on Sandbox when we connect to the node via JSON-RPC (and hence we need to have this exposed on that RPC).Closes F-407
Note for me
Ping Hao here once this is merged