Skip to content

chore: Accumulated backports to v4#20713

Merged
aminsammara merged 9 commits intov4from
backport-to-v4-staging
Feb 20, 2026
Merged

chore: Accumulated backports to v4#20713
aminsammara merged 9 commits intov4from
backport-to-v4-staging

Conversation

@AztecBot
Copy link
Collaborator

@AztecBot AztecBot commented Feb 20, 2026

BEGIN_COMMIT_OVERRIDE
feat: run low priority eviction rule on chain_pruned (#20687)
feat: adding mempool transactions (#20679)
feat: check calldata against emitted hashes (#20486)
fix: hodgepodge of small things (#20720)
feat: trim attestations to the minimum required length (#20591)
feat: call syncImmediate without block number during chain prune (#20717)
END_COMMIT_OVERRIDE

## Summary

After a chain prune (reorg), `handlePrunedBlocks()` moves mined transactions back to pending, which can temporarily push the v2 pool over its configured size limit. The `EvictionManager` already dispatches a `CHAIN_PRUNED` event (via `evictAfterChainPrune()`), but `LowPriorityEvictionRule` only handled `TXS_ADDED` events — returning an empty result for `CHAIN_PRUNED` and leaving the pool over its limit until the next `addPendingTxs()` call.

- Extended `LowPriorityEvictionRule.evict()` to also trigger on `CHAIN_PRUNED` events, so the pool size limit is enforced immediately after a reorg
- Guarded `context.newTxHashes` access (only present on the `TXS_ADDED` variant of the discriminated union) with an event-type check, logging a distinct message for the chain-prune case
- Added unit tests for `CHAIN_PRUNED` handling in `LowPriorityEvictionRule` (eviction when over limit, no-op when under limit, no-op when disabled, error handling)
- Added integration tests in `tx_pool_v2.test.ts` exercising the full add → mine → set limit → prune → verify eviction flow

## Test plan

- [x] Unit tests pass: `yarn workspace @aztec/p2p test src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.test.ts` (14 tests)
- [x] Integration tests pass: `yarn workspace @aztec/p2p test src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts -t 'handlePrunedBlocks'` (12 tests)
- [x] Lint and format pass

Fixes A-560
## Summary

Wraps all `TxPoolV2Impl` handler methods in `this.#store.transactionAsync()` to ensure DB atomicity. Without this, a failure mid-way through a handler can leave LMDB in a partially updated state (e.g., some txs marked as mined but not others), breaking pool invariants on restart.

`transactionAsync` accumulates writes in memory and flushes atomically at commit — it does not hold a real LMDB write lock during callback execution, so including eviction (with its world-state I/O) inside the transaction is safe.

**Handlers wrapped:**

- **`addPendingTxs`**: already had a transaction for the add loop; moved `evictAfterNewTxs` inside it
- **`protectTxs`**: wraps the loop that reads from `#txsDB` and calls `#addTx`
- **`handleMinedBlock`**: wraps markAsMined/clearIfMinedHigher loop and `evictAfterNewBlock`
- **`handleFailedExecution`**: wraps the `#deleteTxsBatch` call
- **`handleFinalizedBlock`**: wraps steps 2-5 (archive collection, batch delete, finalize soft-deletes, archive writes)
- **`prepareForSlot`**: wraps entire body from `cleanupSlotDeleted` through `evictAfterNewTxs`
- **`handlePrunedBlocks`**: wraps entire body from `markFromPrunedBlock` through `evictAfterChainPrune`

No operation reordering, no API changes, no new types.

## Test plan

- `yarn workspace @aztec/p2p test src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts` passes
- `yarn workspace @aztec/p2p test src/mem_pools/tx_pool_v2/eviction/` passes
- `yarn workspace @aztec/p2p test src/mem_pools/tx_pool_v2/tx_pool_v2.compat.test.ts` passes
- `yarn build` compiles

Part of A-546
## Summary

- Replace the allowlist-based "strict" multicall3 validation with hash-only matching: the archiver now finds `propose` calls by rollup address + selector and verifies them against `attestationsHash` and `payloadDigest` from `CheckpointProposed` events
- Make expected hashes required throughout — drop backwards compatibility for older events without hashes
- Simplify `CalldataRetriever` constructor from a contract addresses object to just `rollupAddress`
- Remove the allowlist infrastructure: `ValidContractCall`, `computeValidContractCalls`, all non-propose selector constants, and unused ABI imports (`EmpireSlashingProposerAbi`, `GovernanceProposerAbi`, `SlashFactoryAbi`, `TallySlashingProposerAbi`)
- Update Spire Proposer to return all wrapped calls (not just exactly one), enabling hash matching across multi-call Spire transactions
- Fix the CLI debug tool (`retrieve-calldata.ts`) to extract hashes from `CheckpointProposed` event logs and pass them to the retriever
- Remove `l1Addresses` constructor parameter from `ArchiverL1Synchronizer` and `contractAddresses` from data retrieval functions

## Details

### Hash-only matching in `tryDecodeMulticall3`

Previously, the method first tried "strict" validation (all calls must be on an allowlist of known addresses and selectors), then fell back to "relaxed" hash matching. Now there's a single path: find all calls matching rollup address + `propose` selector, verify each candidate against expected hashes, return the uniquely verified one. If multiple candidates verify (identical data), the first is returned with a warning.

### Required expected hashes

`attestationsHash` and `payloadDigest` are now required (not optional) in:
- `CheckpointProposedArgs` type in `rollup.ts`
- All `CalldataRetriever` methods (`getCheckpointFromRollupTx`, `getCheckpointFromTx`, `tryDecodeMulticall3`, `tryDecodeDirectPropose`, `tryDecodeSpireProposer`, `tryDecodeAndVerifyPropose`)

Runtime guards in `getCheckpointProposedEvents` throw if either field is missing from the event log.

### Simplified constructor

`CalldataRetriever` now takes just `rollupAddress: EthAddress` instead of `{ rollupAddress, governanceProposerAddress, slashingProposerAddress, slashFactoryAddress? }`. This eliminates the need for `l1Addresses` in `ArchiverL1Synchronizer` and `contractAddresses` in data retrieval functions.

### Spire Proposer multi-call support

`getCallFromSpireProposer` renamed to `getCallsFromSpireProposer`, now returns all wrapped calls as an array. `tryDecodeSpireProposer` iterates each call and tries it through `tryDecodeMulticall3` or direct propose + hash verification, returning the first verified match.

### CLI debug tool

`retrieve-calldata.ts` now uses `decodeEventLog` from viem to extract `attestationsHash` and `payloadDigest` from the `CheckpointProposed` event log, passing real hashes instead of an empty object.

## Test plan

- All 55 calldata retriever unit tests pass (hash matching, multicall3, direct propose, Spire Proposer, trace fallback, integration)
- All 17 spire proposer unit tests pass (single/multi call, validation failures, array return type)
- Build, format, and lint pass cleanly

Fixes A-408
Stuff I don't want hanging over my head while I'm out. Potentially (read: recommended) portable to current devnet.

* Comment about the protocol contracts `generate_data` script requested by @nchamo
* Fix for Niall's issue with deployments that require authwitnesses: https://linear.app/aztec-labs/issue/F-302/authwits-are-not-being-forwarded-to-the-executionpayload-in
* Update playground's devnet URL
* Avoid reregistering accounts on every operation in `EmbeddedWallet`
This PR:
 - Splits AVM_MAX_PROCESSABLE_GAS (6M) from MAX_PROCESSABLE_GAS (6M+PUBLIC_TX_OVERHEAD)
 - Splits Public tx overhead and private tx overhead
 - Plugs in numbers from simulation metrics to tx overheads
 - Plugs in numbers from simulation metrics to side effects
 - TODO: Figure out contract class logs: we are having trouble measuring them.
## Summary

- Trim attestations to the minimum required (2/3 + 1 of committee) before submitting to L1, saving calldata gas
- The proposer's own attestation is always preserved (L1 reverts with `MissingProposerSignature` without it)
- Attestations from the local node's validator keys are prioritized over external ones
- No L1 contract changes needed — the existing packed format already handles positions without signatures by storing addresses instead (20 bytes vs 65 bytes per signature)

## Changes

- `yarn-project/stdlib/src/p2p/attestation_utils.ts`: Added `trimAttestations()` utility that partitions attestations into proposer/local/external buckets and keeps only the minimum required, prioritizing proposer and local validators
- `yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts`: Call `trimAttestations()` between `collectAttestations()` and `orderAttestations()` in `waitForAttestations()`
- `yarn-project/stdlib/src/p2p/attestation_utils.test.ts`: New test file with 7 unit tests covering trimming behavior, priority ordering, edge cases
- `yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.test.ts`: Added `getValidatorAddresses` mock
- `yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.timing.test.ts`: Added `getValidatorAddresses` mock

## Test plan

- [x] `trimAttestations` unit tests (7/7 pass): no-op when under threshold, trims to required count, keeps proposer, prioritizes local, fills with external, no double-counting, handles bad signatures
- [x] `checkpoint_proposal_job.test.ts` (26/26 pass)
- [x] `checkpoint_proposal_job.timing.test.ts` (16/16 pass)
- [x] `sequencer.test.ts` (22/22 pass)
- [ ] E2E multi-validator tests (assertions use `>= quorum` so should be safe)
)

## Summary

- Update `syncImmediate` calls in `FeePayerBalanceEvictionRule` and `InvalidTxsAfterReorgRule` to call without a block number during `CHAIN_PRUNED` events
- `syncImmediate(blockNumber)` returns early when the world state is already at or past the target, skipping `blockStream.sync()` — calling without args ensures the prune event is always processed

Note: despite the original issue description (A-545) suggesting that validations may produce incorrect results, the eviction rules were already correct. Both rules use `getSnapshot(blockNumber)` which serves historical data via the native content-addressed store's root hash, regardless of whether `unwindBlocks` has run. Additionally, `#revalidateMetadata` (step 5 in `handlePrunedBlocks`) already calls `syncImmediate()` without args through `createPoolTxValidator`, so the world state processes the prune before the eviction rules run. This change makes the eviction rules' intent explicit rather than relying on the earlier sync.

Fixes A-545
@AztecBot
Copy link
Collaborator Author

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/d342c3c9f4b58512�d342c3c9f4b585128;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_epochs/epochs_invalidate_block.parallel.test.ts "proposer invalidates previous block with shuffled attestations" (123s) (code: 0) group:e2e-p2p-epoch-flakes

@aminsammara aminsammara merged commit 43caf7c into v4 Feb 20, 2026
9 checks passed
@aminsammara aminsammara deleted the backport-to-v4-staging branch February 20, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants