Skip to content

feat(aztec.js): delay first receipt poll after sending a tx - #25089

Merged
nchamo merged 2 commits into
merge-train/fairiesfrom
nchamo/aztecbot-gist-0d9bd928
Aug 5, 2026
Merged

feat(aztec.js): delay first receipt poll after sending a tx#25089
nchamo merged 2 commits into
merge-train/fairiesfrom
nchamo/aztecbot-gist-0d9bd928

Conversation

@nchamo

@nchamo nchamo commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Motivation

Follow-up to #25074 and #25076 in the effort to reduce PXE↔node RPC traffic. Two calls per sent tx were guaranteed wasted: a pre-send getTxReceipt used only to reject settled duplicates, which the node's tx validation already rejects via its double-spend check, and the first receipt poll of .wait(), issued immediately after sendTx when the tx cannot have been mined yet.

The change

  • BaseWallet.sendTx no longer reads the receipt before sending; duplicate submissions are rejected by the node instead.
  • WaitOpts gains initialDelay: seconds to sleep before the first receipt poll. The wallet defaults it to the poll interval, so the first poll now happens where the second poll used to. Environments where receipts are available immediately after sending (e.g. automine) can pass initialDelay: 0.
  • The delay counts against timeout (the deadline is fixed before sleeping) and does not consume the DROPPED-receipt grace period, which starts at the first poll.

Wallet benchmark results:

Before → After
getTxReceipt calls 40 → 32 (−20.0%)
Total node RPC calls 232 → 224 (−3.4%)
Node RPC round trips 163 → 156 (−4.3%)

@nchamo nchamo self-assigned this Aug 3, 2026
@nchamo nchamo added ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure labels Aug 3, 2026
/** The amount of time to ignore TxStatus.DROPPED receipts (in seconds) due to the presumption that it is being propagated by the p2p network. Defaults to 5. */
ignoreDroppedReceiptsFor?: number;
/** The maximum time (in seconds) to wait for the transaction to be mined. Defaults to 60. */
/** The maximum time (in seconds) to wait for the transaction to be mined. Defaults to 300 (5 min). */

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 was outdated, look at the defaults below

);
const tx = await provenTx.toTx();
const txHash = tx.getTxHash();
if ((await this.aztecNode.getTxReceipt(txHash)).isMined()) {

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 wasn't necessary, as the node already rejects it. I added a test to assert this behaviour

@nchamo
nchamo marked this pull request as ready for review August 3, 2026 20:29
@nchamo
nchamo requested a review from Thunkar August 3, 2026 20:29
@nchamo
nchamo merged commit 61cc513 into merge-train/fairies Aug 5, 2026
21 checks passed
@nchamo
nchamo deleted the nchamo/aztecbot-gist-0d9bd928 branch August 5, 2026 11:04
AztecBot pushed a commit that referenced this pull request Aug 5, 2026
## Motivation

Follow-up to #25074 and #25076 in the effort to reduce PXE↔node RPC
traffic. Two calls per sent tx were guaranteed wasted: a pre-send
`getTxReceipt` used only to reject settled duplicates, which the node's
tx validation already rejects via its double-spend check, and the first
receipt poll of `.wait()`, issued immediately after `sendTx` when the tx
cannot have been mined yet.

## The change

- `BaseWallet.sendTx` no longer reads the receipt before sending;
duplicate submissions are rejected by the node instead.
- `WaitOpts` gains `initialDelay`: seconds to sleep before the first
receipt poll. The wallet defaults it to the poll interval, so the first
poll now happens where the second poll used to. Environments where
receipts are available immediately after sending (e.g. automine) can
pass `initialDelay: 0`.
- The delay counts against `timeout` (the deadline is fixed before
sleeping) and does not consume the DROPPED-receipt grace period, which
starts at the first poll.

Wallet benchmark results:

| | Before → After |
|---|---|
| `getTxReceipt` calls | 40 → 32 (−20.0%) |
| Total node RPC calls | 232 → 224 (−3.4%) |
| Node RPC round trips | 163 → 156 (−4.3%) |
@AztecBot

AztecBot commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

✅ Successfully backported to backport-to-v5-next-staging #25113.

nventuro pushed a commit that referenced this pull request Aug 6, 2026
…nts (#25116)

## Why we are doing this

Follow-up to #25089 in the PXE↔node RPC-reduction line. When PXE tracks
the proposed chain tip it anchors on the tip's header, but the block
stream's `chain-proposed` event only carried the block id, so the PXE
handler had to fetch the header back from the node on every tip
movement.

## Our fix

`chain-proposed` now carries the tip's `BlockHeader` as a required
payload, so consumers anchor on the event without a fetch of their own.
The stream sources the header from whatever the pass already has: the
delivered tip block in block mode, a prefetch that runs in parallel with
the reorg walk-back in tips-only mode, or an on-demand by-hash read as a
fallback. If the header cannot be obtained the pass aborts and retries
on the next poll, so tier events never get ahead of a proposed tip the
consumer never received.

## Metrics

Measured on the `key_flows` transfers benchmark with a counting wrapper
between the benchmarking wallet and the in-process node, applied to both
base and this branch. Per-flow calls are unchanged; the saving is one
serial fetch (round trip) per tip movement.

| Flow | RPC calls | Round trips |
|---|---|---|
| `ecdsar1+transfer_0_recursions+sponsored_fpc` | 35 → 35 | 26 → 25
(−3.8%) |
| `ecdsar1+transfer_1_recursions+sponsored_fpc` | 37 → 37 | 23 → 21
(−8.7%) |
| `ecdsar1+transfer_0_recursions+private_fpc` | 56 → 56 | 34 → 33
(−2.9%) |
| `ecdsar1+transfer_1_recursions+private_fpc` | 56 → 56 | 32 → 31
(−3.1%) |
| whole suite (both wallets, incl. setup) | 460 → 459 | 333 → 320
(−3.9%) |
AztecBot pushed a commit that referenced this pull request Aug 6, 2026
…nts (#25116)

## Why we are doing this

Follow-up to #25089 in the PXE↔node RPC-reduction line. When PXE tracks
the proposed chain tip it anchors on the tip's header, but the block
stream's `chain-proposed` event only carried the block id, so the PXE
handler had to fetch the header back from the node on every tip
movement.

## Our fix

`chain-proposed` now carries the tip's `BlockHeader` as a required
payload, so consumers anchor on the event without a fetch of their own.
The stream sources the header from whatever the pass already has: the
delivered tip block in block mode, a prefetch that runs in parallel with
the reorg walk-back in tips-only mode, or an on-demand by-hash read as a
fallback. If the header cannot be obtained the pass aborts and retries
on the next poll, so tier events never get ahead of a proposed tip the
consumer never received.

## Metrics

Measured on the `key_flows` transfers benchmark with a counting wrapper
between the benchmarking wallet and the in-process node, applied to both
base and this branch. Per-flow calls are unchanged; the saving is one
serial fetch (round trip) per tip movement.

| Flow | RPC calls | Round trips |
|---|---|---|
| `ecdsar1+transfer_0_recursions+sponsored_fpc` | 35 → 35 | 26 → 25
(−3.8%) |
| `ecdsar1+transfer_1_recursions+sponsored_fpc` | 37 → 37 | 23 → 21
(−8.7%) |
| `ecdsar1+transfer_0_recursions+private_fpc` | 56 → 56 | 34 → 33
(−2.9%) |
| `ecdsar1+transfer_1_recursions+private_fpc` | 56 → 56 | 32 → 31
(−3.1%) |
| whole suite (both wallets, incl. setup) | 460 → 459 | 333 → 320
(−3.9%) |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-v5-next ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants