Skip to content

feat: add RPC endpoints to manipulate time#22084

Merged
benesjan merged 22 commits into
merge-train/fairiesfrom
jan/f-407-add-an-rpc-endpoint-to-manipulate-time
Apr 10, 2026
Merged

feat: add RPC endpoints to manipulate time#22084
benesjan merged 22 commits into
merge-train/fairiesfrom
jan/f-407-add-an-rpc-endpoint-to-manipulate-time

Conversation

@benesjan

@benesjan benesjan commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

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:

  • On the node we expose only new mineBlock function on a new AztecNodeDebug interface and this endpoint is functional only in test environment,
  • the actual time manipulation happens by warping the time on anvil - we use EthCheatCodes class for this,
  • once the time is warped on L1, then the next mined block on L2 will have the warped timestamp because we use AnvilTestWatcher in those environments - this automatically updates inner sequencer's DateProvider based on Anvil's time (AnvilTestWatcher was mentioned by Palla, is there a risk of us not using in some test env?)
  • to have good devex I introduced new functionality on the CheatCodes class that performs this L1 warping and L2 mining automatically.

AZTEC_NODE_DEBUG env var

The debug endpoint (mineBlock) is gated behind a new AZTEC_NODE_DEBUG env var / --node-debug CLI flag. When set, it exposes the AztecNodeDebug interface on the main RPC port.

  • --local-network auto-enables it — devs running aztec start --local-network get mineBlock by default without extra config.
  • Standalone --node requires explicit opt-in via AZTEC_NODE_DEBUG=true or --node-debug.

Composed e2e test

The e2e_cheat_codes test 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 mineBlock on node?

Note that I tried to minimize the impact on the node but we need to add the mineBlock method on the node because we need to trigger block getting mined and we cannot get a hold of the SequencerClient in 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

@benesjan benesjan marked this pull request as draft March 27, 2026 03:31
Base automatically changed from merge-train/fairies to next March 27, 2026 07:58
@benesjan benesjan changed the base branch from next to graphite-base/22084 March 30, 2026 03:36
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch from 0d144cb to 9d67fa9 Compare March 30, 2026 03:36
@benesjan benesjan changed the base branch from graphite-base/22084 to merge-train/fairies March 30, 2026 03:36

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Comment thread yarn-project/yarn.lock
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch from 51b33a2 to 5d00440 Compare March 30, 2026 13:42
@benesjan benesjan marked this pull request as ready for review March 30, 2026 13:42
Comment thread yarn-project/stdlib/src/interfaces/aztec-node-admin.ts Outdated
@benesjan benesjan marked this pull request as draft March 31, 2026 01:36
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch 2 times, most recently from c7c7580 to b715407 Compare April 2, 2026 10:53
signalHandlers.push(stop);
services.node = [node, AztecNodeApiSchema];
adminServices.node = [node, AztecNodeAdminApiSchema];
adminServices.nodeDebug = [node, AztecNodeDebugApiSchema];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is quite foreign to me so I asked this to AI:

Image

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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch from b715407 to 061ad4f Compare April 9, 2026 03:55
Comment thread yarn-project/aztec/src/testing/cheat_codes.ts
@benesjan benesjan added the ci-draft Run CI on draft PRs. label Apr 9, 2026
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch 2 times, most recently from 0749b9f to fcfc5d6 Compare April 9, 2026 13:43
@benesjan benesjan marked this pull request as ready for review April 9, 2026 14:11
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch from 77c7a7c to 41bb0d0 Compare April 9, 2026 14:11
@benesjan benesjan requested a review from alexghr April 9, 2026 14:20
signalHandlers.push(stop);
services.node = [node, AztecNodeApiSchema];
adminServices.node = [node, AztecNodeAdminApiSchema];
adminServices.nodeDebug = [node, AztecNodeDebugApiSchema];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Comment thread yarn-project/aztec-node/src/aztec-node/server.ts Outdated
Comment thread yarn-project/aztec-node/src/aztec-node/server.ts
Comment thread yarn-project/aztec/src/testing/cheat_codes.ts
@benesjan benesjan marked this pull request as draft April 10, 2026 06:00
@benesjan benesjan removed the ci-draft Run CI on draft PRs. label Apr 10, 2026
@benesjan benesjan force-pushed the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch from 41bb0d0 to 3ee69b3 Compare April 10, 2026 06:06
Comment on lines -54 to -55
--local-network.noPXE ($NO_PXE)
Do not expose PXE service on local network start

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the non-local-network setting the env var has to be explicitly set.

@benesjan benesjan marked this pull request as ready for review April 10, 2026 08:06
@benesjan benesjan requested a review from spypsy April 10, 2026 08:34
@benesjan benesjan merged commit 53b278e into merge-train/fairies Apr 10, 2026
19 checks passed
@benesjan benesjan deleted the jan/f-407-add-an-rpc-endpoint-to-manipulate-time branch April 10, 2026 09:37
@AztecBot

Copy link
Copy Markdown
Collaborator

❌ Failed to cherry-pick to v4-next due to conflicts. (🤖) View backport run.

benesjan added a commit that referenced this pull request Apr 10, 2026
github-merge-queue Bot pushed a commit that referenced this pull request Apr 10, 2026
BEGIN_COMMIT_OVERRIDE
fix: passing in user call info from wallet (#21937)
feat: add RPC endpoints to manipulate time (#22084)
END_COMMIT_OVERRIDE
benesjan pushed a commit that referenced this pull request May 13, 2026
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants