@aztec/validator-client 0.0.1-commit.3469e52 → 0.0.1-commit.35158ae7e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +63 -19
  2. package/dest/block_proposal_handler.d.ts +9 -10
  3. package/dest/block_proposal_handler.d.ts.map +1 -1
  4. package/dest/block_proposal_handler.js +135 -82
  5. package/dest/checkpoint_builder.d.ts +27 -15
  6. package/dest/checkpoint_builder.d.ts.map +1 -1
  7. package/dest/checkpoint_builder.js +136 -45
  8. package/dest/config.d.ts +1 -1
  9. package/dest/config.d.ts.map +1 -1
  10. package/dest/config.js +30 -7
  11. package/dest/duties/validation_service.d.ts +2 -2
  12. package/dest/duties/validation_service.d.ts.map +1 -1
  13. package/dest/duties/validation_service.js +6 -12
  14. package/dest/factory.d.ts +3 -1
  15. package/dest/factory.d.ts.map +1 -1
  16. package/dest/factory.js +3 -2
  17. package/dest/index.d.ts +1 -2
  18. package/dest/index.d.ts.map +1 -1
  19. package/dest/index.js +0 -1
  20. package/dest/key_store/ha_key_store.d.ts +1 -1
  21. package/dest/key_store/ha_key_store.d.ts.map +1 -1
  22. package/dest/key_store/ha_key_store.js +3 -3
  23. package/dest/metrics.d.ts +12 -3
  24. package/dest/metrics.d.ts.map +1 -1
  25. package/dest/metrics.js +46 -5
  26. package/dest/validator.d.ts +41 -15
  27. package/dest/validator.d.ts.map +1 -1
  28. package/dest/validator.js +230 -69
  29. package/package.json +19 -17
  30. package/src/block_proposal_handler.ts +165 -109
  31. package/src/checkpoint_builder.ts +185 -52
  32. package/src/config.ts +30 -7
  33. package/src/duties/validation_service.ts +12 -11
  34. package/src/factory.ts +4 -0
  35. package/src/index.ts +0 -1
  36. package/src/key_store/ha_key_store.ts +3 -3
  37. package/src/metrics.ts +63 -6
  38. package/src/validator.ts +294 -86
  39. package/dest/tx_validator/index.d.ts +0 -3
  40. package/dest/tx_validator/index.d.ts.map +0 -1
  41. package/dest/tx_validator/index.js +0 -2
  42. package/dest/tx_validator/nullifier_cache.d.ts +0 -14
  43. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  44. package/dest/tx_validator/nullifier_cache.js +0 -24
  45. package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
  46. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
  47. package/dest/tx_validator/tx_validator_factory.js +0 -54
  48. package/src/tx_validator/index.ts +0 -2
  49. package/src/tx_validator/nullifier_cache.ts +0 -30
  50. package/src/tx_validator/tx_validator_factory.ts +0 -135
package/README.md CHANGED
@@ -77,6 +77,8 @@ These rules must always hold:
77
77
  2. **Global variables match within checkpoint**: All blocks within the same checkpoint must have identical global variables (except `blockNumber`), which includes the slot number
78
78
  3. **inHash is constant**: All blocks in a checkpoint share the same L1-to-L2 messages hash
79
79
  4. **Sequential indexWithinCheckpoint**: Block N must have `indexWithinCheckpoint = parent.indexWithinCheckpoint + 1`
80
+ 5. **One proposer per slot**: Each slot has exactly one designated proposer. Sending multiple proposals for the same position (slot, indexWithinCheckpoint) with different content is equivocation and slashable
81
+ 6. **One attestation per slot**: Validators should only attest to one checkpoint per slot. Attesting to different proposals (different archives) for the same slot is equivocation and slashable
80
82
 
81
83
  ## Validation Flow
82
84
 
@@ -87,15 +89,14 @@ When a `BlockProposal` is received via P2P, the `BlockProposalHandler` performs:
87
89
  ```
88
90
  1. Verify proposer signature
89
91
  2. Check proposal is from current/next slot proposer (via BlockProposalValidator)
90
- 3. Find parent block by archive root (wait/retry if not synced)
91
- 4. Compute checkpoint number from parent
92
- 5. If indexWithinCheckpoint > 0:
93
- - Validate global variables match parent (chainId, version, slotNumber,
94
- timestamp, coinbase, feeRecipient, gasFees)
95
- 6. Verify inHash matches computed from L1-to-L2 messages
96
- 7. Collect transactions from pool/network/proposal
97
- 8. Re-execute transactions (if enabled)
98
- 9. Compare re-execution result with proposal
92
+ 3. Detect duplicate proposals (same slot + indexWithinCheckpoint, different archive) slashing proposer on equivocation
93
+ 4. Find parent block by archive root (wait/retry if not synced)
94
+ 5. Compute checkpoint number from parent
95
+ 6. If indexWithinCheckpoint > 0, then validate global variables match parent (chainId, version, slotNumber, timestamp, coinbase, feeRecipient, gasFees)
96
+ 7. Verify inHash matches computed from L1-to-L2 messages
97
+ 8. Collect transactions from pool/network/proposal
98
+ 9. Re-execute transactions (if enabled)
99
+ 10. Compare re-execution result with proposal
99
100
  ```
100
101
 
101
102
  ### Checkpoint Proposal Validation
@@ -155,15 +156,17 @@ Time | Proposer | Validator
155
156
 
156
157
  ## Configuration
157
158
 
158
- | Flag | Purpose |
159
- | ------------------------------------- | --------------------------------------------------------------------- |
160
- | `validatorReexecute` | Re-execute transactions to verify proposals |
161
- | `fishermanMode` | Validate proposals but don't broadcast attestations (monitoring only) |
162
- | `alwaysReexecuteBlockProposals` | Force re-execution even when not in committee |
163
- | `slashBroadcastedInvalidBlockPenalty` | Penalty amount for invalid proposals (0 = disabled) |
164
- | `validatorReexecuteDeadlineMs` | Time reserved at end of slot for propagation/publishing |
165
- | `attestationPollingIntervalMs` | How often to poll for attestations when collecting |
166
- | `disabledValidators` | Validator addresses to exclude from duties |
159
+ | Flag | Purpose |
160
+ | ------------------------------------- | -------------------------------------------------------------------------------------- |
161
+ | `validatorReexecute` | Re-execute transactions to verify proposals |
162
+ | `fishermanMode` | Validate proposals but don't broadcast attestations (monitoring only) |
163
+ | `alwaysReexecuteBlockProposals` | Force re-execution even when not in committee |
164
+ | `slashBroadcastedInvalidBlockPenalty` | Penalty amount for invalid proposals (0 = disabled) |
165
+ | `slashDuplicateProposalPenalty` | Penalty amount for duplicate proposals (0 = disabled) |
166
+ | `slashDuplicateAttestationPenalty` | Penalty amount for duplicate attestations (0 = disabled) |
167
+ | `validatorReexecuteDeadlineMs` | Time reserved at end of slot for propagation/publishing |
168
+ | `attestationPollingIntervalMs` | How often to poll for attestations when collecting |
169
+ | `disabledValidators` | Validator addresses to exclude from duties |
167
170
 
168
171
  ### High Availability (HA) Keystore
169
172
 
@@ -220,6 +223,47 @@ This is useful for monitoring network health without participating in consensus.
220
223
  - `createCheckpointProposal(...)` → `CheckpointProposal`: Signs checkpoint proposal
221
224
  - `attestToCheckpointProposal(proposal, attestors)` → `CheckpointAttestation[]`: Creates attestations for given addresses
222
225
 
226
+ ## Block Building Limits
227
+
228
+ L1 enforces gas and blob capacity per checkpoint. The node enforces these during block building to avoid L1 rejection. Three dimensions are metered: L2 gas (mana), DA gas, and blob fields. DA gas maps to blob fields today (`daGas = blobFields * 32`) but both are tracked independently.
229
+
230
+ ### Checkpoint limits
231
+
232
+ | Dimension | Source | Budget |
233
+ | --- | --- | --- |
234
+ | L2 gas (mana) | `rollup.getManaLimit()` | Fetched from L1 at startup |
235
+ | DA gas | `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT` | 786,432 (6 blobs × 4096 fields × 32 gas/field) |
236
+ | Blob fields | `BLOBS_PER_CHECKPOINT × FIELDS_PER_BLOB` | 24,576 minus checkpoint/block-end overhead |
237
+
238
+ ### Per-block budgets
239
+
240
+ Per-block budgets prevent one block from consuming the entire checkpoint budget. The checkpoint builder dynamically computes per-block limits before each block based on the remaining checkpoint budget and the number of remaining blocks.
241
+
242
+ **Proposer**: When building a proposal (`isBuildingProposal: true`), the `CheckpointProposalJob` passes `maxBlocksPerCheckpoint` (from the timetable) and `perBlockAllocationMultiplier` (default 1.2) via opts to `CheckpointBuilder.buildBlock`. The builder computes a fair share as `min(perBlockLimit, ceil(remainingBudget / remainingBlocks * multiplier), remainingBudget)`. The multiplier greater than 1 allows early blocks to use more than their even share, since different blocks hit different limit dimensions (L2 gas, DA gas, blob fields) — a strict even split would waste capacity. As prior blocks consume budget, later blocks see tightened limits. This applies to all four dimensions (L2 gas, DA gas, blob fields, transaction count). Operators can set hard per-block caps via `SEQ_MAX_L2_BLOCK_GAS` / `SEQ_MAX_DA_BLOCK_GAS` / `SEQ_MAX_TX_PER_BLOCK` (capped at checkpoint limits at startup); these act as additional upper bounds alongside the redistribution.
243
+
244
+ **Validator**: When re-executing a proposal (`isBuildingProposal` unset), `capLimitsByCheckpointBudgets` only caps by the per-block limit and the total remaining checkpoint budget — no redistribution or multiplier is applied. This avoids false rejections due to differences between proposer and validator fair-share calculations. Validators can optionally set hard per-block limits via `VALIDATOR_MAX_L2_BLOCK_GAS`, `VALIDATOR_MAX_DA_BLOCK_GAS`, and `VALIDATOR_MAX_TX_PER_BLOCK`. When unset, no per-block limit is enforced (checkpoint-level protocol limits still apply). These are independent of the `SEQ_` vars so operators can tune proposer and validation limits separately.
245
+
246
+ ### Per-transaction enforcement
247
+
248
+ **Mempool entry** (`GasLimitsValidator`): L2 gas must be ≤ `MAX_PROCESSABLE_L2_GAS` (6,540,000) and ≥ fixed minimums.
249
+
250
+ **Block building** (`PublicProcessor.process`): Before processing, txs are skipped if their estimated blob fields or gas limits would exceed the block budget. After processing, actual values are checked and the tx is reverted if limits are exceeded.
251
+
252
+ ### Gas limit configuration
253
+
254
+ | Variable | Default | Description |
255
+ | --- | --- | --- |
256
+ | `SEQ_MAX_L2_BLOCK_GAS` | *none* | Hard per-block L2 gas cap. Capped at `rollupManaLimit` at startup. When unset, redistribution dynamically computes per-block limits. |
257
+ | `SEQ_MAX_DA_BLOCK_GAS` | *none* | Hard per-block DA gas cap. Capped at `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT` at startup. When unset, redistribution handles it. |
258
+ | `SEQ_MAX_TX_PER_BLOCK` | *none* | Hard per-block tx count cap. Capped at `SEQ_MAX_TX_PER_CHECKPOINT` at startup (if set). |
259
+ | `SEQ_MAX_TX_PER_CHECKPOINT` | *none* | Total txs across all blocks in a checkpoint. When set, checkpoint-level capping and redistribution are enforced for tx count. |
260
+ | `SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER` | 1.2 | Multiplier for per-block budget redistribution. Passed via opts to the checkpoint builder during proposal building. |
261
+ | `SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET` | true | Legacy flag; redistribution is now always active during proposal building and inactive during validation. |
262
+ | `VALIDATOR_MAX_L2_BLOCK_GAS` | *none* | Per-block L2 gas limit for validation. Proposals exceeding this are rejected. |
263
+ | `VALIDATOR_MAX_DA_BLOCK_GAS` | *none* | Per-block DA gas limit for validation. Proposals exceeding this are rejected. |
264
+ | `VALIDATOR_MAX_TX_PER_BLOCK` | *none* | Per-block tx count limit for validation. Proposals exceeding this are rejected. |
265
+ | `VALIDATOR_MAX_TX_PER_CHECKPOINT` | *none* | Per-checkpoint tx count limit for validation. Proposals exceeding this are rejected. |
266
+
223
267
  ## Testing Patterns
224
268
 
225
269
  ### Common Mocks
@@ -268,7 +312,7 @@ For tests that exercise re-execution:
268
312
  ```typescript
269
313
  // Mock parent block lookup
270
314
  blockSource.getBlockHeaderByArchive.mockResolvedValue(parentBlockHeader);
271
- blockSource.getL2BlockNew.mockResolvedValue({
315
+ blockSource.getL2Block.mockResolvedValue({
272
316
  checkpointNumber: CheckpointNumber(1),
273
317
  indexWithinCheckpoint: 0,
274
318
  header: { globalVariables: parentGlobalVariables },
@@ -3,19 +3,18 @@ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import { DateProvider } from '@aztec/foundation/timer';
5
5
  import type { P2P, PeerId } from '@aztec/p2p';
6
- import { TxProvider } from '@aztec/p2p';
7
6
  import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
8
- import type { L2BlockNew, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
9
- import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
7
+ import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
8
+ import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
10
9
  import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
11
10
  import type { BlockProposal } from '@aztec/stdlib/p2p';
12
- import { type FailedTx, type Tx } from '@aztec/stdlib/tx';
11
+ import type { FailedTx, Tx } from '@aztec/stdlib/tx';
13
12
  import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
14
13
  import type { FullNodeCheckpointsBuilder } from './checkpoint_builder.js';
15
14
  import type { ValidatorMetrics } from './metrics.js';
16
- export type BlockProposalValidationFailureReason = 'invalid_proposal' | 'parent_block_not_found' | 'parent_block_wrong_slot' | 'in_hash_mismatch' | 'global_variables_mismatch' | 'block_number_already_exists' | 'txs_not_available' | 'state_mismatch' | 'failed_txs' | 'timeout' | 'unknown_error';
15
+ export type BlockProposalValidationFailureReason = 'invalid_proposal' | 'parent_block_not_found' | 'block_source_not_synced' | 'parent_block_wrong_slot' | 'in_hash_mismatch' | 'global_variables_mismatch' | 'block_number_already_exists' | 'txs_not_available' | 'state_mismatch' | 'failed_txs' | 'initial_state_mismatch' | 'timeout' | 'unknown_error';
17
16
  type ReexecuteTransactionsResult = {
18
- block: L2BlockNew;
17
+ block: L2Block;
19
18
  failedTxs: FailedTx[];
20
19
  reexecutionTimeMs: number;
21
20
  totalManaUsed: number;
@@ -45,8 +44,8 @@ export declare class BlockProposalHandler {
45
44
  private dateProvider;
46
45
  private log;
47
46
  readonly tracer: Tracer;
48
- constructor(checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, blockProposalValidator: BlockProposalValidator, epochCache: EpochCache, config: ValidatorClientFullConfig, metrics?: ValidatorMetrics | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
49
- registerForReexecution(p2pClient: P2P): BlockProposalHandler;
47
+ constructor(checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, blockProposalValidator: BlockProposalValidator, epochCache: EpochCache, config: ValidatorClientFullConfig, metrics?: ValidatorMetrics | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
48
+ register(p2pClient: P2P, shouldReexecute: boolean): BlockProposalHandler;
50
49
  handleBlockProposal(proposal: BlockProposal, proposalSender: PeerId, shouldReexecute: boolean): Promise<BlockProposalValidationResult>;
51
50
  private getParentBlock;
52
51
  private computeCheckpointNumber;
@@ -57,9 +56,9 @@ export declare class BlockProposalHandler {
57
56
  */
58
57
  private validateNonFirstBlockInCheckpoint;
59
58
  private getReexecutionDeadline;
60
- private getBlocksInCheckpoint;
59
+ private waitForBlockSourceSync;
61
60
  private getReexecuteFailureReason;
62
61
  reexecuteTransactions(proposal: BlockProposal, blockNumber: BlockNumber, checkpointNumber: CheckpointNumber, txs: Tx[], l1ToL2Messages: Fr[], previousCheckpointOutHashes: Fr[]): Promise<ReexecuteTransactionsResult>;
63
62
  }
64
63
  export {};
65
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfcHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2Jsb2NrX3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFBYyxNQUFNLGlDQUFpQyxDQUFDO0FBQzVGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUlwRCxPQUFPLEVBQUUsWUFBWSxFQUFTLE1BQU0seUJBQXlCLENBQUM7QUFDOUQsT0FBTyxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ25FLE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbEYsT0FBTyxLQUFLLEVBQUUseUJBQXlCLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6RyxPQUFPLEVBQ0wsS0FBSyxtQkFBbUIsRUFHekIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEtBQUssRUFBRSxhQUFhLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN2RCxPQUFPLEVBQStDLEtBQUssUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFPdkcsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFFLEtBQUssTUFBTSxFQUFzQixNQUFNLHlCQUF5QixDQUFDO0FBRWhHLE9BQU8sS0FBSyxFQUFFLDBCQUEwQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDMUUsT0FBTyxLQUFLLEVBQUUsZ0JBQWdC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
64
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfcHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2Jsb2NrX3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBRSxnQkFBZ0IsRUFBYyxNQUFNLGlDQUFpQyxDQUFDO0FBRTVGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUlwRCxPQUFPLEVBQUUsWUFBWSxFQUFTLE1BQU0seUJBQXlCLENBQUM7QUFDOUQsT0FBTyxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUM5QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNuRSxPQUFPLEtBQUssRUFBYSxPQUFPLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRzFGLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSx5QkFBeUIsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3RILE9BQU8sRUFBRSxLQUFLLG1CQUFtQixFQUFtQyxNQUFNLHlCQUF5QixDQUFDO0FBQ3BHLE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXZELE9BQU8sS0FBSyxFQUE2QixRQUFRLEVBQUUsRUFBRSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFRaEYsT0FBTyxFQUFFLEtBQUssZUFBZSxFQUFFLEtBQUssTUFBTSxFQUFzQixNQUFNLHlCQUF5QixDQUFDO0FBRWhHLE9BQU8sS0FBSyxFQUFFLDBCQUEwQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDMUUsT0FBTyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFckQsTUFBTSxNQUFN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
@@ -1 +1 @@
1
- {"version":3,"file":"block_proposal_handler.d.ts","sourceRoot":"","sources":["../src/block_proposal_handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"block_proposal_handler.d.ts","sourceRoot":"","sources":["../src/block_proposal_handler.ts"],"names":[],"mappings":"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"}
@@ -65,14 +65,17 @@ function _ts_dispose_resources(env) {
65
65
  }
66
66
  import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
67
67
  import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
68
+ import { pick } from '@aztec/foundation/collection';
68
69
  import { Fr } from '@aztec/foundation/curves/bn254';
69
70
  import { TimeoutError } from '@aztec/foundation/error';
70
71
  import { createLogger } from '@aztec/foundation/log';
71
72
  import { retryUntil } from '@aztec/foundation/retry';
72
73
  import { DateProvider, Timer } from '@aztec/foundation/timer';
73
74
  import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
74
- import { computeCheckpointOutHash, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
75
- import { ReExFailedTxsError, ReExStateMismatchError, ReExTimeoutError, TransactionsNotAvailableError } from '@aztec/stdlib/validators';
75
+ import { Gas } from '@aztec/stdlib/gas';
76
+ import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
77
+ import { MerkleTreeId } from '@aztec/stdlib/trees';
78
+ import { ReExFailedTxsError, ReExInitialStateMismatchError, ReExStateMismatchError, ReExTimeoutError, TransactionsNotAvailableError } from '@aztec/stdlib/validators';
76
79
  import { getTelemetryClient } from '@aztec/telemetry-client';
77
80
  export class BlockProposalHandler {
78
81
  checkpointsBuilder;
@@ -104,23 +107,27 @@ export class BlockProposalHandler {
104
107
  }
105
108
  this.tracer = telemetry.getTracer('BlockProposalHandler');
106
109
  }
107
- registerForReexecution(p2pClient) {
108
- // Non-validator handler that re-executes for monitoring but does not attest.
110
+ register(p2pClient, shouldReexecute) {
111
+ // Non-validator handler that processes or re-executes for monitoring but does not attest.
109
112
  // Returns boolean indicating whether the proposal was valid.
110
113
  const handler = async (proposal, proposalSender)=>{
111
114
  try {
112
- const result = await this.handleBlockProposal(proposal, proposalSender, true);
115
+ const { slotNumber, blockNumber } = proposal;
116
+ const result = await this.handleBlockProposal(proposal, proposalSender, shouldReexecute);
113
117
  if (result.isValid) {
114
- this.log.info(`Non-validator reexecution completed for slot ${proposal.slotNumber}`, {
118
+ this.log.info(`Non-validator block proposal ${blockNumber} at slot ${slotNumber} handled`, {
115
119
  blockNumber: result.blockNumber,
120
+ slotNumber,
116
121
  reexecutionTimeMs: result.reexecutionResult?.reexecutionTimeMs,
117
122
  totalManaUsed: result.reexecutionResult?.totalManaUsed,
118
- numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0
123
+ numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0,
124
+ reexecuted: shouldReexecute
119
125
  });
120
126
  return true;
121
127
  } else {
122
- this.log.warn(`Non-validator reexecution failed for slot ${proposal.slotNumber}`, {
128
+ this.log.warn(`Non-validator block proposal ${blockNumber} at slot ${slotNumber} failed processing with ${result.reason}`, {
123
129
  blockNumber: result.blockNumber,
130
+ slotNumber,
124
131
  reason: result.reason
125
132
  });
126
133
  return false;
@@ -147,7 +154,9 @@ export class BlockProposalHandler {
147
154
  }
148
155
  const proposalInfo = {
149
156
  ...proposal.toBlockInfo(),
150
- proposer: proposer.toString()
157
+ proposer: proposer.toString(),
158
+ blockNumber: undefined,
159
+ checkpointNumber: undefined
151
160
  };
152
161
  this.log.info(`Processing proposal for slot ${slotNumber}`, {
153
162
  ...proposalInfo,
@@ -155,27 +164,46 @@ export class BlockProposalHandler {
155
164
  });
156
165
  // Check that the proposal is from the current proposer, or the next proposer
157
166
  // This should have been handled by the p2p layer, but we double check here out of caution
158
- const invalidProposal = await this.blockProposalValidator.validate(proposal);
159
- if (invalidProposal) {
167
+ const validationResult = await this.blockProposalValidator.validate(proposal);
168
+ if (validationResult.result !== 'accept') {
160
169
  this.log.warn(`Proposal is not valid, skipping processing`, proposalInfo);
161
170
  return {
162
171
  isValid: false,
163
172
  reason: 'invalid_proposal'
164
173
  };
165
174
  }
166
- // Check that the parent proposal is a block we know, otherwise reexecution would fail
167
- const parentBlockHeader = await this.getParentBlock(proposal);
168
- if (parentBlockHeader === undefined) {
175
+ // Ensure the block source is synced before checking for existing blocks,
176
+ // since a pending checkpoint prune may remove blocks we'd otherwise find.
177
+ // This affects mostly the block_number_already_exists check, since a pending
178
+ // checkpoint prune could remove a block that would conflict with this proposal.
179
+ // When pipelining is enabled, the proposer builds ahead of L1 submission, so the
180
+ // block source won't have synced to the proposed slot yet. Skip the sync wait to
181
+ // avoid eating into the attestation window.
182
+ if (!this.epochCache.isProposerPipeliningEnabled()) {
183
+ const blockSourceSync = await this.waitForBlockSourceSync(slotNumber);
184
+ if (!blockSourceSync) {
185
+ this.log.warn(`Block source is not synced, skipping processing`, proposalInfo);
186
+ return {
187
+ isValid: false,
188
+ reason: 'block_source_not_synced'
189
+ };
190
+ }
191
+ }
192
+ // Check that the parent proposal is a block we know, otherwise reexecution would fail.
193
+ // If we don't find it immediately, we keep retrying for a while; it may be we still
194
+ // need to process other block proposals to get to it.
195
+ const parentBlock = await this.getParentBlock(proposal);
196
+ if (parentBlock === undefined) {
169
197
  this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
170
198
  return {
171
199
  isValid: false,
172
200
  reason: 'parent_block_not_found'
173
201
  };
174
202
  }
175
- // Check that the parent block's slot is less than the proposal's slot (should not happen, but we check anyway)
176
- if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() >= slotNumber) {
177
- this.log.warn(`Parent block slot is greater than or equal to proposal slot, skipping processing`, {
178
- parentBlockSlot: parentBlockHeader.getSlot().toString(),
203
+ // Check that the parent block's slot is not greater than the proposal's slot.
204
+ if (parentBlock !== 'genesis' && parentBlock.header.getSlot() > slotNumber) {
205
+ this.log.warn(`Parent block slot is greater than proposal slot, skipping processing`, {
206
+ parentBlockSlot: parentBlock.header.getSlot().toString(),
179
207
  proposalSlot: slotNumber.toString(),
180
208
  ...proposalInfo
181
209
  });
@@ -185,7 +213,8 @@ export class BlockProposalHandler {
185
213
  };
186
214
  }
187
215
  // Compute the block number based on the parent block
188
- const blockNumber = parentBlockHeader === 'genesis' ? BlockNumber(INITIAL_L2_BLOCK_NUM) : BlockNumber(parentBlockHeader.getBlockNumber() + 1);
216
+ const blockNumber = parentBlock === 'genesis' ? BlockNumber(INITIAL_L2_BLOCK_NUM) : BlockNumber(parentBlock.header.getBlockNumber() + 1);
217
+ proposalInfo.blockNumber = blockNumber;
189
218
  // Check that this block number does not exist already
190
219
  const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
191
220
  if (existingBlock) {
@@ -202,8 +231,16 @@ export class BlockProposalHandler {
202
231
  pinnedPeer: proposalSender,
203
232
  deadline: this.getReexecutionDeadline(slotNumber, config)
204
233
  });
234
+ // If reexecution is disabled, bail. We were just interested in triggering tx collection.
235
+ if (!shouldReexecute) {
236
+ this.log.info(`Received valid block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`, proposalInfo);
237
+ return {
238
+ isValid: true,
239
+ blockNumber
240
+ };
241
+ }
205
242
  // Compute the checkpoint number for this block and validate checkpoint consistency
206
- const checkpointResult = await this.computeCheckpointNumber(proposal, parentBlockHeader, proposalInfo);
243
+ const checkpointResult = this.computeCheckpointNumber(proposal, parentBlock, proposalInfo);
207
244
  if (checkpointResult.reason) {
208
245
  return {
209
246
  isValid: false,
@@ -212,6 +249,7 @@ export class BlockProposalHandler {
212
249
  };
213
250
  }
214
251
  const checkpointNumber = checkpointResult.checkpointNumber;
252
+ proposalInfo.checkpointNumber = checkpointNumber;
215
253
  // Check that I have the same set of l1ToL2Messages as the proposal
216
254
  const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
217
255
  const computedInHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
@@ -240,38 +278,32 @@ export class BlockProposalHandler {
240
278
  reason: 'txs_not_available'
241
279
  };
242
280
  }
281
+ // Collect the out hashes of all the checkpoints before this one in the same epoch
282
+ const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
283
+ const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
243
284
  // Try re-executing the transactions in the proposal if needed
244
285
  let reexecutionResult;
245
- if (shouldReexecute) {
246
- // Compute the previous checkpoint out hashes for the epoch.
247
- // TODO(mbps): This assumes one block per checkpoint, which is only true for now.
248
- // TODO: There can be a more efficient way to get the previous checkpoint out hashes without having to fetch all
249
- // the blocks.
250
- const epoch = getEpochAtSlot(slotNumber, this.epochCache.getL1Constants());
251
- const previousBlocks = (await this.blockSource.getBlocksForEpoch(epoch)).filter((b)=>b.number < blockNumber).sort((a, b)=>a.number - b.number);
252
- const previousCheckpointOutHashes = previousBlocks.map((b)=>computeCheckpointOutHash([
253
- b.body.txEffects.map((tx)=>tx.l2ToL1Msgs)
254
- ]));
255
- try {
256
- this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
257
- reexecutionResult = await this.reexecuteTransactions(proposal, blockNumber, checkpointNumber, txs, l1ToL2Messages, previousCheckpointOutHashes);
258
- } catch (error) {
259
- this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
260
- const reason = this.getReexecuteFailureReason(error);
261
- return {
262
- isValid: false,
263
- blockNumber,
264
- reason,
265
- reexecutionResult
266
- };
267
- }
286
+ try {
287
+ this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
288
+ reexecutionResult = await this.reexecuteTransactions(proposal, blockNumber, checkpointNumber, txs, l1ToL2Messages, previousCheckpointOutHashes);
289
+ } catch (error) {
290
+ this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
291
+ const reason = this.getReexecuteFailureReason(error);
292
+ return {
293
+ isValid: false,
294
+ blockNumber,
295
+ reason,
296
+ reexecutionResult
297
+ };
268
298
  }
269
299
  // If we succeeded, push this block into the archiver (unless disabled)
270
- // TODO(palla/mbps): Change default to false once block sync is stable.
271
300
  if (reexecutionResult?.block && this.config.skipPushProposedBlocksToArchiver === false) {
272
301
  await this.blockSource.addBlock(reexecutionResult?.block);
273
302
  }
274
- this.log.info(`Successfully processed block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`, proposalInfo);
303
+ this.log.info(`Successfully re-executed block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`, {
304
+ ...proposalInfo,
305
+ ...pick(reexecutionResult, 'reexecutionTimeMs', 'totalManaUsed')
306
+ });
275
307
  return {
276
308
  isValid: true,
277
309
  blockNumber,
@@ -290,7 +322,7 @@ export class BlockProposalHandler {
290
322
  const currentTime = this.dateProvider.now();
291
323
  const timeoutDurationMs = deadline.getTime() - currentTime;
292
324
  try {
293
- return await this.blockSource.getBlockHeaderByArchive(parentArchive) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(()=>this.blockSource.syncImmediate().then(()=>this.blockSource.getBlockHeaderByArchive(parentArchive)), 'force archiver sync', timeoutDurationMs / 1000, 0.5));
325
+ return await this.blockSource.getBlockDataByArchive(parentArchive) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(()=>this.blockSource.syncImmediate().then(()=>this.blockSource.getBlockDataByArchive(parentArchive)), 'force archiver sync', timeoutDurationMs / 1000, 0.5));
294
326
  } catch (err) {
295
327
  if (err instanceof TimeoutError) {
296
328
  this.log.debug(`Timed out getting parent block by archive root`, {
@@ -304,8 +336,8 @@ export class BlockProposalHandler {
304
336
  return undefined;
305
337
  }
306
338
  }
307
- async computeCheckpointNumber(proposal, parentBlockHeader, proposalInfo) {
308
- if (parentBlockHeader === 'genesis') {
339
+ computeCheckpointNumber(proposal, parentBlock, proposalInfo) {
340
+ if (parentBlock === 'genesis') {
309
341
  // First block is in checkpoint 1
310
342
  if (proposal.indexWithinCheckpoint !== 0) {
311
343
  this.log.warn(`First block proposal has non-zero indexWithinCheckpoint`, proposalInfo);
@@ -317,20 +349,9 @@ export class BlockProposalHandler {
317
349
  checkpointNumber: CheckpointNumber.INITIAL
318
350
  };
319
351
  }
320
- // Get the parent block to find its checkpoint number
321
- // TODO(palla/mbps): The block header should include the checkpoint number to avoid this lookup,
322
- // or at least the L2BlockSource should return a different struct that includes it.
323
- const parentBlockNumber = parentBlockHeader.getBlockNumber();
324
- const parentBlock = await this.blockSource.getL2BlockNew(parentBlockNumber);
325
- if (!parentBlock) {
326
- this.log.warn(`Parent block ${parentBlockNumber} not found in archiver`, proposalInfo);
327
- return {
328
- reason: 'invalid_proposal'
329
- };
330
- }
331
352
  if (proposal.indexWithinCheckpoint === 0) {
332
353
  // If this is the first block in a new checkpoint, increment the checkpoint number
333
- if (!(proposal.blockHeader.getSlot() > parentBlockHeader.getSlot())) {
354
+ if (!(proposal.blockHeader.getSlot() > parentBlock.header.getSlot())) {
334
355
  this.log.warn(`Slot should be greater than parent block slot for first block in checkpoint`, proposalInfo);
335
356
  return {
336
357
  reason: 'invalid_proposal'
@@ -347,7 +368,7 @@ export class BlockProposalHandler {
347
368
  reason: 'invalid_proposal'
348
369
  };
349
370
  }
350
- if (proposal.blockHeader.getSlot() !== parentBlockHeader.getSlot()) {
371
+ if (proposal.blockHeader.getSlot() !== parentBlock.header.getSlot()) {
351
372
  this.log.warn(`Slot should be equal to parent block slot for non-first block in checkpoint`, proposalInfo);
352
373
  return {
353
374
  reason: 'invalid_proposal'
@@ -447,23 +468,39 @@ export class BlockProposalHandler {
447
468
  const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
448
469
  return new Date(nextSlotTimestampSeconds * 1000);
449
470
  }
450
- /**
451
- * Gets all prior blocks in the same checkpoint (same slot and checkpoint number) up to but not including upToBlockNumber.
452
- */ async getBlocksInCheckpoint(slot, upToBlockNumber, checkpointNumber) {
453
- const blocks = [];
454
- let currentBlockNumber = BlockNumber(upToBlockNumber - 1);
455
- while(currentBlockNumber >= INITIAL_L2_BLOCK_NUM){
456
- const block = await this.blockSource.getL2BlockNew(currentBlockNumber);
457
- if (!block || block.header.getSlot() !== slot || block.checkpointNumber !== checkpointNumber) {
458
- break;
471
+ /** Waits for the block source to sync L1 data up to at least the slot before the given one. */ async waitForBlockSourceSync(slot) {
472
+ const deadline = this.getReexecutionDeadline(slot, this.checkpointsBuilder.getConfig());
473
+ const timeoutMs = deadline.getTime() - this.dateProvider.now();
474
+ if (slot === 0) {
475
+ return true;
476
+ }
477
+ // Make a quick check before triggering an archiver sync
478
+ const syncedSlot = await this.blockSource.getSyncedL2SlotNumber();
479
+ if (syncedSlot !== undefined && syncedSlot + 1 >= slot) {
480
+ return true;
481
+ }
482
+ try {
483
+ // Trigger an immediate sync of the block source, and wait until it reports being synced to the required slot
484
+ return await retryUntil(async ()=>{
485
+ await this.blockSource.syncImmediate();
486
+ const syncedSlot = await this.blockSource.getSyncedL2SlotNumber();
487
+ return syncedSlot !== undefined && syncedSlot + 1 >= slot;
488
+ }, 'wait for block source sync', timeoutMs / 1000, 0.5);
489
+ } catch (err) {
490
+ if (err instanceof TimeoutError) {
491
+ this.log.warn(`Timed out waiting for block source to sync to slot ${slot}`);
492
+ return false;
493
+ } else {
494
+ throw err;
459
495
  }
460
- blocks.unshift(block);
461
- currentBlockNumber = BlockNumber(currentBlockNumber - 1);
462
496
  }
463
- return blocks;
464
497
  }
465
498
  getReexecuteFailureReason(err) {
466
- if (err instanceof ReExStateMismatchError) {
499
+ if (err instanceof TransactionsNotAvailableError) {
500
+ return 'txs_not_available';
501
+ } else if (err instanceof ReExInitialStateMismatchError) {
502
+ return 'initial_state_mismatch';
503
+ } else if (err instanceof ReExStateMismatchError) {
467
504
  return 'state_mismatch';
468
505
  } else if (err instanceof ReExFailedTxsError) {
469
506
  return 'failed_txs';
@@ -490,34 +527,49 @@ export class BlockProposalHandler {
490
527
  const timer = new Timer();
491
528
  const slot = proposal.slotNumber;
492
529
  const config = this.checkpointsBuilder.getConfig();
493
- // Get prior blocks in this checkpoint (same slot and checkpoint number)
494
- const priorBlocks = await this.getBlocksInCheckpoint(slot, blockNumber, checkpointNumber);
530
+ // Get prior blocks in this checkpoint (same slot before current block)
531
+ const allBlocksInSlot = await this.blockSource.getBlocksForSlot(slot);
532
+ const priorBlocks = allBlocksInSlot.filter((b)=>b.number < blockNumber && b.header.getSlot() === slot);
495
533
  // Fork before the block to be built
496
534
  const parentBlockNumber = BlockNumber(blockNumber - 1);
497
- const fork = _ts_add_disposable_resource(env, await this.worldState.fork(parentBlockNumber), false);
498
- // Build checkpoint constants from proposal (excludes blockNumber and timestamp which are per-block)
535
+ await this.worldState.syncImmediate(parentBlockNumber);
536
+ const fork = _ts_add_disposable_resource(env, await this.worldState.fork(parentBlockNumber), true);
537
+ // Verify the fork's archive root matches the proposal's expected last archive.
538
+ // If they don't match, our world state synced to a different chain and reexecution would fail.
539
+ const forkArchiveRoot = new Fr((await fork.getTreeInfo(MerkleTreeId.ARCHIVE)).root);
540
+ if (!forkArchiveRoot.equals(proposal.blockHeader.lastArchive.root)) {
541
+ throw new ReExInitialStateMismatchError(proposal.blockHeader.lastArchive.root, forkArchiveRoot);
542
+ }
543
+ // Build checkpoint constants from proposal (excludes blockNumber which is per-block)
499
544
  const constants = {
500
545
  chainId: new Fr(config.l1ChainId),
501
546
  version: new Fr(config.rollupVersion),
502
547
  slotNumber: slot,
548
+ timestamp: blockHeader.globalVariables.timestamp,
503
549
  coinbase: blockHeader.globalVariables.coinbase,
504
550
  feeRecipient: blockHeader.globalVariables.feeRecipient,
505
551
  gasFees: blockHeader.globalVariables.gasFees
506
552
  };
507
553
  // Create checkpoint builder with prior blocks
508
- const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(checkpointNumber, constants, l1ToL2Messages, previousCheckpointOutHashes, fork, priorBlocks);
554
+ const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(checkpointNumber, constants, 0n, l1ToL2Messages, previousCheckpointOutHashes, fork, priorBlocks, this.log.getBindings());
509
555
  // Build the new block
510
556
  const deadline = this.getReexecutionDeadline(slot, config);
557
+ const maxBlockGas = this.config.validateMaxL2BlockGas !== undefined || this.config.validateMaxDABlockGas !== undefined ? new Gas(this.config.validateMaxDABlockGas ?? Infinity, this.config.validateMaxL2BlockGas ?? Infinity) : undefined;
511
558
  const result = await checkpointBuilder.buildBlock(txs, blockNumber, blockHeader.globalVariables.timestamp, {
559
+ isBuildingProposal: false,
560
+ minValidTxs: 0,
512
561
  deadline,
513
- expectedEndState: blockHeader.state
562
+ expectedEndState: blockHeader.state,
563
+ maxTransactions: this.config.validateMaxTxsPerBlock,
564
+ maxBlockGas
514
565
  });
515
566
  const { block, failedTxs } = result;
516
567
  const numFailedTxs = failedTxs.length;
517
- this.log.verbose(`Transaction re-execution complete for slot ${slot}`, {
568
+ this.log.verbose(`Block proposal ${blockNumber} at slot ${slot} transaction re-execution complete`, {
518
569
  numFailedTxs,
519
570
  numProposalTxs: txHashes.length,
520
571
  numProcessedTxs: block.body.txEffects.length,
572
+ blockNumber,
521
573
  slot
522
574
  });
523
575
  if (numFailedTxs > 0) {
@@ -555,7 +607,8 @@ export class BlockProposalHandler {
555
607
  env.error = e;
556
608
  env.hasError = true;
557
609
  } finally{
558
- _ts_dispose_resources(env);
610
+ const result = _ts_dispose_resources(env);
611
+ if (result) await result;
559
612
  }
560
613
  }
561
614
  }