@aztec/validator-client 5.0.0-nightly.20260315 → 5.0.0-nightly.20260317
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.
- package/README.md +4 -3
- package/dest/checkpoint_builder.d.ts +2 -1
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +52 -30
- package/dest/duties/validation_service.js +1 -1
- package/package.json +19 -19
- package/src/checkpoint_builder.ts +60 -38
- package/src/duties/validation_service.ts +1 -1
package/README.md
CHANGED
|
@@ -239,11 +239,11 @@ L1 enforces gas and blob capacity per checkpoint. The node enforces these during
|
|
|
239
239
|
|
|
240
240
|
Per-block budgets prevent one block from consuming the entire checkpoint budget.
|
|
241
241
|
|
|
242
|
-
**Proposer**: `computeBlockLimits()` derives budgets at startup as `min(checkpointLimit, ceil(checkpointLimit / maxBlocks * multiplier))`, where `maxBlocks` comes from the timetable and `multiplier` defaults to 2. The multiplier greater than 1 allows early blocks to use more than their even share of the checkpoint budget, since different blocks hit different limit dimensions (L2 gas, DA gas, blob fields) — a strict even split would waste capacity. Operators can override via `SEQ_MAX_L2_BLOCK_GAS` / `SEQ_MAX_DA_BLOCK_GAS` / `SEQ_MAX_TX_PER_BLOCK` (capped at checkpoint limits). Per-block TX limits follow the same derivation pattern when `SEQ_MAX_TX_PER_CHECKPOINT` is set.
|
|
242
|
+
**Proposer**: `computeBlockLimits()` derives budgets at startup as `min(checkpointLimit, ceil(checkpointLimit / maxBlocks * multiplier))`, where `maxBlocks` comes from the timetable and `multiplier` defaults to 1.2. The multiplier greater than 1 allows early blocks to use more than their even share of the checkpoint budget, since different blocks hit different limit dimensions (L2 gas, DA gas, blob fields) — a strict even split would waste capacity. Operators can override via `SEQ_MAX_L2_BLOCK_GAS` / `SEQ_MAX_DA_BLOCK_GAS` / `SEQ_MAX_TX_PER_BLOCK` (capped at checkpoint limits). Per-block TX limits follow the same derivation pattern when `SEQ_MAX_TX_PER_CHECKPOINT` is set.
|
|
243
243
|
|
|
244
244
|
**Validator**: Optionally enforces per-block limits via `VALIDATOR_MAX_L2_BLOCK_GAS`, `VALIDATOR_MAX_DA_BLOCK_GAS`, and `VALIDATOR_MAX_TX_PER_BLOCK`. When set, these are passed to `buildBlock` during re-execution and to `validateCheckpoint` for final validation. When unset, no per-block limit is enforced for that dimension (checkpoint-level protocol limits still apply). These are independent of the `SEQ_` vars so operators can tune proposer and validation limits separately.
|
|
245
245
|
|
|
246
|
-
**Checkpoint-level capping**: `CheckpointBuilder.capLimitsByCheckpointBudgets()` always runs before tx processing, capping per-block limits by `checkpointBudget - sum(used by prior blocks)
|
|
246
|
+
**Checkpoint-level capping**: `CheckpointBuilder.capLimitsByCheckpointBudgets()` always runs before tx processing, capping per-block limits by the remaining checkpoint budget. When `SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET` is enabled (default: true), the remaining budget is distributed evenly across remaining blocks with the multiplier applied: `min(perBlockLimit, ceil(remainingBudget / remainingBlocks * multiplier), remainingBudget)`. This prevents early blocks from consuming the entire checkpoint budget, producing smoother distribution. When disabled, each block can consume up to the full remaining budget, ie caps by `checkpointBudget - sum(used by prior blocks)`. This applies to all four dimensions (L2 gas, DA gas, blob fields, transaction count). Validators always cap by the total remaining.
|
|
247
247
|
|
|
248
248
|
### Per-transaction enforcement
|
|
249
249
|
|
|
@@ -259,7 +259,8 @@ Per-block budgets prevent one block from consuming the entire checkpoint budget.
|
|
|
259
259
|
| `SEQ_MAX_DA_BLOCK_GAS` | *auto* | Per-block DA gas. Auto-derived from checkpoint DA limit / maxBlocks * multiplier. |
|
|
260
260
|
| `SEQ_MAX_TX_PER_BLOCK` | *none* | Per-block tx count. If `SEQ_MAX_TX_PER_CHECKPOINT` is set and per-block is not, derived as `ceil(checkpointLimit / maxBlocks * multiplier)`. |
|
|
261
261
|
| `SEQ_MAX_TX_PER_CHECKPOINT` | *none* | Total txs across all blocks in a checkpoint. When set, per-block tx limit is derived from it (unless explicitly overridden) and checkpoint-level capping is enforced. |
|
|
262
|
-
| `SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER` | 2 | Multiplier for per-block budget computation. |
|
|
262
|
+
| `SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER` | 1.2 | Multiplier for per-block budget computation. |
|
|
263
|
+
| `SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET` | true | Redistribute remaining checkpoint budget evenly across remaining blocks instead of allowing one block to consume it all. |
|
|
263
264
|
| `VALIDATOR_MAX_L2_BLOCK_GAS` | *none* | Per-block L2 gas limit for validation. Proposals exceeding this are rejected. |
|
|
264
265
|
| `VALIDATOR_MAX_DA_BLOCK_GAS` | *none* | Per-block DA gas limit for validation. Proposals exceeding this are rejected. |
|
|
265
266
|
| `VALIDATOR_MAX_TX_PER_BLOCK` | *none* | Per-block tx count limit for validation. Proposals exceeding this are rejected. |
|
|
@@ -34,6 +34,7 @@ export declare class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
34
34
|
*/
|
|
35
35
|
buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, blockNumber: BlockNumber, timestamp: bigint, opts?: PublicProcessorLimits & {
|
|
36
36
|
expectedEndState?: StateReference;
|
|
37
|
+
minValidTxs?: number;
|
|
37
38
|
}): Promise<BuildBlockInCheckpointResult>;
|
|
38
39
|
/** Completes the checkpoint and returns it. */
|
|
39
40
|
completeCheckpoint(): Promise<Checkpoint>;
|
|
@@ -73,4 +74,4 @@ export declare class FullNodeCheckpointsBuilder implements ICheckpointsBuilder {
|
|
|
73
74
|
/** Returns a fork of the world state at the given block number. */
|
|
74
75
|
getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations>;
|
|
75
76
|
}
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF9idWlsZGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2hlY2twb2ludF9idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxXQUFXLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVoRixPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEQsT0FBTyxFQUFlLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBRXZGLE9BQU8sRUFBRSxZQUFZLEVBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUVoRSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMxRSxPQUFPLEVBR0wsZUFBZSxFQUVoQixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNqRSxPQUFPLEtBQUssRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRXJFLE9BQU8sRUFDTCxLQUFLLDRCQUE0QixFQUNqQyxLQUFLLDBCQUEwQixFQUUvQixLQUFLLHVCQUF1QixFQUM1QixLQUFLLG1CQUFtQixFQUV4QixLQUFLLHlCQUF5QixFQUM5QixLQUFLLHFCQUFxQixFQUMxQixLQUFLLHNCQUFzQixFQUM1QixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLGFBQWEsRUFBcUIsTUFBTSxvQkFBb0IsQ0FBQztBQUUzRSxPQUFPLEVBQUUsS0FBSyx5QkFBeUIsRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZHLE9BQU8sRUFBRSxLQUFL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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkpoint_builder.d.ts","sourceRoot":"","sources":["../src/checkpoint_builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAe,KAAK,cAAc,EAAgB,MAAM,uBAAuB,CAAC;AAEvF,OAAO,EAAE,YAAY,EAAW,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAE/B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"checkpoint_builder.d.ts","sourceRoot":"","sources":["../src/checkpoint_builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,11 +8,12 @@ import { createTxValidatorForBlockBuilding, getDefaultAllowedSetupFunctions } fr
|
|
|
8
8
|
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
9
9
|
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, createPublicTxSimulatorForBlockBuilding } from '@aztec/simulator/server';
|
|
10
10
|
import { Gas } from '@aztec/stdlib/gas';
|
|
11
|
-
import { FullNodeBlockBuilderConfigKeys,
|
|
11
|
+
import { FullNodeBlockBuilderConfigKeys, InsufficientValidTxsError } from '@aztec/stdlib/interfaces/server';
|
|
12
12
|
import { NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
13
13
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
14
14
|
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
15
15
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
16
|
+
import { ForkCheckpoint } from '@aztec/world-state';
|
|
16
17
|
/**
|
|
17
18
|
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
18
19
|
* and completing it.
|
|
@@ -69,28 +70,40 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
69
70
|
...opts,
|
|
70
71
|
...this.capLimitsByCheckpointBudgets(opts)
|
|
71
72
|
};
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
// We execute all merkle tree operations on a world state fork checkpoint
|
|
74
|
+
// This enables us to discard all modifications in the event that we fail to successfully process sufficient transactions
|
|
75
|
+
const forkCheckpoint = await ForkCheckpoint.new(this.fork);
|
|
76
|
+
try {
|
|
77
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(()=>processor.process(pendingTxs, cappedOpts, validator));
|
|
78
|
+
// Throw before updating state if we don't have enough valid txs
|
|
79
|
+
const minValidTxs = opts.minValidTxs ?? 0;
|
|
80
|
+
if (processedTxs.length < minValidTxs) {
|
|
81
|
+
throw new InsufficientValidTxsError(processedTxs.length, minValidTxs, failedTxs);
|
|
82
|
+
}
|
|
83
|
+
// Commit the fork checkpoint
|
|
84
|
+
await forkCheckpoint.commit();
|
|
85
|
+
// Add block to checkpoint
|
|
86
|
+
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
87
|
+
expectedEndState: opts.expectedEndState
|
|
88
|
+
});
|
|
89
|
+
this.log.debug('Built block within checkpoint', {
|
|
90
|
+
header: block.header.toInspect(),
|
|
91
|
+
processedTxs: processedTxs.map((tx)=>tx.hash.toString()),
|
|
92
|
+
failedTxs: failedTxs.map((tx)=>tx.tx.txHash.toString())
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
block,
|
|
96
|
+
publicProcessorDuration,
|
|
97
|
+
numTxs: processedTxs.length,
|
|
98
|
+
failedTxs,
|
|
99
|
+
usedTxs
|
|
100
|
+
};
|
|
101
|
+
} catch (err) {
|
|
102
|
+
// If we reached the point of committing the checkpoint, this does nothing
|
|
103
|
+
// Otherwise it reverts any changes made to the fork for this failed block
|
|
104
|
+
await forkCheckpoint.revert();
|
|
105
|
+
throw err;
|
|
77
106
|
}
|
|
78
|
-
// Add block to checkpoint
|
|
79
|
-
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
80
|
-
expectedEndState: opts.expectedEndState
|
|
81
|
-
});
|
|
82
|
-
this.log.debug('Built block within checkpoint', {
|
|
83
|
-
header: block.header.toInspect(),
|
|
84
|
-
processedTxs: processedTxs.map((tx)=>tx.hash.toString()),
|
|
85
|
-
failedTxs: failedTxs.map((tx)=>tx.tx.txHash.toString())
|
|
86
|
-
});
|
|
87
|
-
return {
|
|
88
|
-
block,
|
|
89
|
-
publicProcessorDuration,
|
|
90
|
-
numTxs: processedTxs.length,
|
|
91
|
-
failedTxs,
|
|
92
|
-
usedTxs
|
|
93
|
-
};
|
|
94
107
|
}
|
|
95
108
|
/** Completes the checkpoint and returns it. */ async completeCheckpoint() {
|
|
96
109
|
const checkpoint = await this.checkpointBuilder.completeCheckpoint();
|
|
@@ -124,18 +137,27 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
|
124
137
|
const isFirstBlock = existingBlocks.length === 0;
|
|
125
138
|
const blockEndOverhead = getNumBlockEndBlobFields(isFirstBlock);
|
|
126
139
|
const maxBlobFieldsForTxs = totalBlobCapacity - usedBlobFields - blockEndOverhead;
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
// When redistributeCheckpointBudget is enabled (default), compute a fair share of remaining budget
|
|
141
|
+
// across remaining blocks scaled by the multiplier, instead of letting one block consume it all.
|
|
142
|
+
const redistribute = this.config.redistributeCheckpointBudget !== false;
|
|
143
|
+
const remainingBlocks = Math.max(1, (this.config.maxBlocksPerCheckpoint ?? 1) - existingBlocks.length);
|
|
144
|
+
const multiplier = this.config.perBlockAllocationMultiplier ?? 1.2;
|
|
145
|
+
// Cap L2 gas by remaining checkpoint mana (with fair share when redistributing)
|
|
146
|
+
const fairShareL2 = redistribute ? Math.ceil(remainingMana / remainingBlocks * multiplier) : Infinity;
|
|
147
|
+
const cappedL2Gas = Math.min(opts.maxBlockGas?.l2Gas ?? Infinity, fairShareL2, remainingMana);
|
|
148
|
+
// Cap DA gas by remaining checkpoint DA gas budget (with fair share when redistributing)
|
|
149
|
+
const fairShareDA = redistribute ? Math.ceil(remainingDAGas / remainingBlocks * multiplier) : Infinity;
|
|
150
|
+
const cappedDAGas = Math.min(opts.maxBlockGas?.daGas ?? remainingDAGas, fairShareDA, remainingDAGas);
|
|
151
|
+
// Cap blob fields by remaining checkpoint blob capacity (with fair share when redistributing)
|
|
152
|
+
const fairShareBlobs = redistribute ? Math.ceil(maxBlobFieldsForTxs / remainingBlocks * multiplier) : Infinity;
|
|
153
|
+
const cappedBlobFields = Math.min(opts.maxBlobFields ?? Infinity, fairShareBlobs, maxBlobFieldsForTxs);
|
|
154
|
+
// Cap transaction count by remaining checkpoint tx budget (with fair share when redistributing)
|
|
134
155
|
let cappedMaxTransactions;
|
|
135
156
|
if (this.config.maxTxsPerCheckpoint !== undefined) {
|
|
136
157
|
const usedTxs = sum(existingBlocks.map((b)=>b.body.txEffects.length));
|
|
137
158
|
const remainingTxs = Math.max(0, this.config.maxTxsPerCheckpoint - usedTxs);
|
|
138
|
-
|
|
159
|
+
const fairShareTxs = redistribute ? Math.ceil(remainingTxs / remainingBlocks * multiplier) : Infinity;
|
|
160
|
+
cappedMaxTransactions = Math.min(opts.maxTransactions ?? Infinity, fairShareTxs, remainingTxs);
|
|
139
161
|
} else {
|
|
140
162
|
cappedMaxTransactions = opts.maxTransactions;
|
|
141
163
|
}
|
|
@@ -105,7 +105,7 @@ export class ValidationService {
|
|
|
105
105
|
} else {
|
|
106
106
|
const error = result.reason;
|
|
107
107
|
if (error instanceof DutyAlreadySignedError || error instanceof SlashingProtectionError) {
|
|
108
|
-
this.log.
|
|
108
|
+
this.log.verbose(`Attestation for slot ${proposal.slotNumber} by ${attestors[i]} already signed by another High-Availability node`);
|
|
109
109
|
// Continue with remaining attestors
|
|
110
110
|
} else {
|
|
111
111
|
throw error;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "5.0.0-nightly.
|
|
3
|
+
"version": "5.0.0-nightly.20260317",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,30 +64,30 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/blob-client": "5.0.0-nightly.
|
|
68
|
-
"@aztec/blob-lib": "5.0.0-nightly.
|
|
69
|
-
"@aztec/constants": "5.0.0-nightly.
|
|
70
|
-
"@aztec/epoch-cache": "5.0.0-nightly.
|
|
71
|
-
"@aztec/ethereum": "5.0.0-nightly.
|
|
72
|
-
"@aztec/foundation": "5.0.0-nightly.
|
|
73
|
-
"@aztec/node-keystore": "5.0.0-nightly.
|
|
74
|
-
"@aztec/noir-protocol-circuits-types": "5.0.0-nightly.
|
|
75
|
-
"@aztec/p2p": "5.0.0-nightly.
|
|
76
|
-
"@aztec/protocol-contracts": "5.0.0-nightly.
|
|
77
|
-
"@aztec/prover-client": "5.0.0-nightly.
|
|
78
|
-
"@aztec/simulator": "5.0.0-nightly.
|
|
79
|
-
"@aztec/slasher": "5.0.0-nightly.
|
|
80
|
-
"@aztec/stdlib": "5.0.0-nightly.
|
|
81
|
-
"@aztec/telemetry-client": "5.0.0-nightly.
|
|
82
|
-
"@aztec/validator-ha-signer": "5.0.0-nightly.
|
|
67
|
+
"@aztec/blob-client": "5.0.0-nightly.20260317",
|
|
68
|
+
"@aztec/blob-lib": "5.0.0-nightly.20260317",
|
|
69
|
+
"@aztec/constants": "5.0.0-nightly.20260317",
|
|
70
|
+
"@aztec/epoch-cache": "5.0.0-nightly.20260317",
|
|
71
|
+
"@aztec/ethereum": "5.0.0-nightly.20260317",
|
|
72
|
+
"@aztec/foundation": "5.0.0-nightly.20260317",
|
|
73
|
+
"@aztec/node-keystore": "5.0.0-nightly.20260317",
|
|
74
|
+
"@aztec/noir-protocol-circuits-types": "5.0.0-nightly.20260317",
|
|
75
|
+
"@aztec/p2p": "5.0.0-nightly.20260317",
|
|
76
|
+
"@aztec/protocol-contracts": "5.0.0-nightly.20260317",
|
|
77
|
+
"@aztec/prover-client": "5.0.0-nightly.20260317",
|
|
78
|
+
"@aztec/simulator": "5.0.0-nightly.20260317",
|
|
79
|
+
"@aztec/slasher": "5.0.0-nightly.20260317",
|
|
80
|
+
"@aztec/stdlib": "5.0.0-nightly.20260317",
|
|
81
|
+
"@aztec/telemetry-client": "5.0.0-nightly.20260317",
|
|
82
|
+
"@aztec/validator-ha-signer": "5.0.0-nightly.20260317",
|
|
83
83
|
"koa": "^2.16.1",
|
|
84
84
|
"koa-router": "^13.1.1",
|
|
85
85
|
"tslib": "^2.4.0",
|
|
86
86
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@aztec/archiver": "5.0.0-nightly.
|
|
90
|
-
"@aztec/world-state": "5.0.0-nightly.
|
|
89
|
+
"@aztec/archiver": "5.0.0-nightly.20260317",
|
|
90
|
+
"@aztec/world-state": "5.0.0-nightly.20260317",
|
|
91
91
|
"@electric-sql/pglite": "^0.3.14",
|
|
92
92
|
"@jest/globals": "^30.0.0",
|
|
93
93
|
"@types/jest": "^30.0.0",
|
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
FullNodeBlockBuilderConfigKeys,
|
|
26
26
|
type ICheckpointBlockBuilder,
|
|
27
27
|
type ICheckpointsBuilder,
|
|
28
|
+
InsufficientValidTxsError,
|
|
28
29
|
type MerkleTreeWriteOperations,
|
|
29
|
-
NoValidTxsError,
|
|
30
30
|
type PublicProcessorLimits,
|
|
31
31
|
type WorldStateSynchronizer,
|
|
32
32
|
} from '@aztec/stdlib/interfaces/server';
|
|
@@ -34,6 +34,7 @@ import { type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
|
34
34
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
35
35
|
import { type CheckpointGlobalVariables, GlobalVariables, StateReference, Tx } from '@aztec/stdlib/tx';
|
|
36
36
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
37
|
+
import { ForkCheckpoint } from '@aztec/world-state';
|
|
37
38
|
|
|
38
39
|
// Re-export for backward compatibility
|
|
39
40
|
export type { BuildBlockInCheckpointResult } from '@aztec/stdlib/interfaces/server';
|
|
@@ -73,7 +74,7 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
73
74
|
pendingTxs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
74
75
|
blockNumber: BlockNumber,
|
|
75
76
|
timestamp: bigint,
|
|
76
|
-
opts: PublicProcessorLimits & { expectedEndState?: StateReference } = {},
|
|
77
|
+
opts: PublicProcessorLimits & { expectedEndState?: StateReference; minValidTxs?: number } = {},
|
|
77
78
|
): Promise<BuildBlockInCheckpointResult> {
|
|
78
79
|
const slot = this.checkpointBuilder.constants.slotNumber;
|
|
79
80
|
|
|
@@ -103,34 +104,47 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
103
104
|
...this.capLimitsByCheckpointBudgets(opts),
|
|
104
105
|
};
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
);
|
|
107
|
+
// We execute all merkle tree operations on a world state fork checkpoint
|
|
108
|
+
// This enables us to discard all modifications in the event that we fail to successfully process sufficient transactions
|
|
109
|
+
const forkCheckpoint = await ForkCheckpoint.new(this.fork);
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
try {
|
|
112
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(() =>
|
|
113
|
+
processor.process(pendingTxs, cappedOpts, validator),
|
|
114
|
+
);
|
|
115
|
+
// Throw before updating state if we don't have enough valid txs
|
|
116
|
+
const minValidTxs = opts.minValidTxs ?? 0;
|
|
117
|
+
if (processedTxs.length < minValidTxs) {
|
|
118
|
+
throw new InsufficientValidTxsError(processedTxs.length, minValidTxs, failedTxs);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Commit the fork checkpoint
|
|
122
|
+
await forkCheckpoint.commit();
|
|
123
|
+
|
|
124
|
+
// Add block to checkpoint
|
|
125
|
+
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
126
|
+
expectedEndState: opts.expectedEndState,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
this.log.debug('Built block within checkpoint', {
|
|
130
|
+
header: block.header.toInspect(),
|
|
131
|
+
processedTxs: processedTxs.map(tx => tx.hash.toString()),
|
|
132
|
+
failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
block,
|
|
137
|
+
publicProcessorDuration,
|
|
138
|
+
numTxs: processedTxs.length,
|
|
139
|
+
failedTxs,
|
|
140
|
+
usedTxs,
|
|
141
|
+
};
|
|
142
|
+
} catch (err) {
|
|
143
|
+
// If we reached the point of committing the checkpoint, this does nothing
|
|
144
|
+
// Otherwise it reverts any changes made to the fork for this failed block
|
|
145
|
+
await forkCheckpoint.revert();
|
|
146
|
+
throw err;
|
|
114
147
|
}
|
|
115
|
-
|
|
116
|
-
// Add block to checkpoint
|
|
117
|
-
const { block } = await this.checkpointBuilder.addBlock(globalVariables, processedTxs, {
|
|
118
|
-
expectedEndState: opts.expectedEndState,
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
this.log.debug('Built block within checkpoint', {
|
|
122
|
-
header: block.header.toInspect(),
|
|
123
|
-
processedTxs: processedTxs.map(tx => tx.hash.toString()),
|
|
124
|
-
failedTxs: failedTxs.map(tx => tx.tx.txHash.toString()),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
block,
|
|
129
|
-
publicProcessorDuration,
|
|
130
|
-
numTxs: processedTxs.length,
|
|
131
|
-
failedTxs,
|
|
132
|
-
usedTxs,
|
|
133
|
-
};
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
/** Completes the checkpoint and returns it. */
|
|
@@ -178,23 +192,31 @@ export class CheckpointBuilder implements ICheckpointBlockBuilder {
|
|
|
178
192
|
const blockEndOverhead = getNumBlockEndBlobFields(isFirstBlock);
|
|
179
193
|
const maxBlobFieldsForTxs = totalBlobCapacity - usedBlobFields - blockEndOverhead;
|
|
180
194
|
|
|
181
|
-
//
|
|
182
|
-
|
|
195
|
+
// When redistributeCheckpointBudget is enabled (default), compute a fair share of remaining budget
|
|
196
|
+
// across remaining blocks scaled by the multiplier, instead of letting one block consume it all.
|
|
197
|
+
const redistribute = this.config.redistributeCheckpointBudget !== false;
|
|
198
|
+
const remainingBlocks = Math.max(1, (this.config.maxBlocksPerCheckpoint ?? 1) - existingBlocks.length);
|
|
199
|
+
const multiplier = this.config.perBlockAllocationMultiplier ?? 1.2;
|
|
200
|
+
|
|
201
|
+
// Cap L2 gas by remaining checkpoint mana (with fair share when redistributing)
|
|
202
|
+
const fairShareL2 = redistribute ? Math.ceil((remainingMana / remainingBlocks) * multiplier) : Infinity;
|
|
203
|
+
const cappedL2Gas = Math.min(opts.maxBlockGas?.l2Gas ?? Infinity, fairShareL2, remainingMana);
|
|
183
204
|
|
|
184
|
-
// Cap DA gas by remaining checkpoint DA gas budget
|
|
185
|
-
const
|
|
205
|
+
// Cap DA gas by remaining checkpoint DA gas budget (with fair share when redistributing)
|
|
206
|
+
const fairShareDA = redistribute ? Math.ceil((remainingDAGas / remainingBlocks) * multiplier) : Infinity;
|
|
207
|
+
const cappedDAGas = Math.min(opts.maxBlockGas?.daGas ?? remainingDAGas, fairShareDA, remainingDAGas);
|
|
186
208
|
|
|
187
|
-
// Cap blob fields by remaining checkpoint blob capacity
|
|
188
|
-
const
|
|
189
|
-
|
|
209
|
+
// Cap blob fields by remaining checkpoint blob capacity (with fair share when redistributing)
|
|
210
|
+
const fairShareBlobs = redistribute ? Math.ceil((maxBlobFieldsForTxs / remainingBlocks) * multiplier) : Infinity;
|
|
211
|
+
const cappedBlobFields = Math.min(opts.maxBlobFields ?? Infinity, fairShareBlobs, maxBlobFieldsForTxs);
|
|
190
212
|
|
|
191
|
-
// Cap transaction count by remaining checkpoint tx budget
|
|
213
|
+
// Cap transaction count by remaining checkpoint tx budget (with fair share when redistributing)
|
|
192
214
|
let cappedMaxTransactions: number | undefined;
|
|
193
215
|
if (this.config.maxTxsPerCheckpoint !== undefined) {
|
|
194
216
|
const usedTxs = sum(existingBlocks.map(b => b.body.txEffects.length));
|
|
195
217
|
const remainingTxs = Math.max(0, this.config.maxTxsPerCheckpoint - usedTxs);
|
|
196
|
-
|
|
197
|
-
|
|
218
|
+
const fairShareTxs = redistribute ? Math.ceil((remainingTxs / remainingBlocks) * multiplier) : Infinity;
|
|
219
|
+
cappedMaxTransactions = Math.min(opts.maxTransactions ?? Infinity, fairShareTxs, remainingTxs);
|
|
198
220
|
} else {
|
|
199
221
|
cappedMaxTransactions = opts.maxTransactions;
|
|
200
222
|
}
|
|
@@ -177,7 +177,7 @@ export class ValidationService {
|
|
|
177
177
|
} else {
|
|
178
178
|
const error = result.reason;
|
|
179
179
|
if (error instanceof DutyAlreadySignedError || error instanceof SlashingProtectionError) {
|
|
180
|
-
this.log.
|
|
180
|
+
this.log.verbose(
|
|
181
181
|
`Attestation for slot ${proposal.slotNumber} by ${attestors[i]} already signed by another High-Availability node`,
|
|
182
182
|
);
|
|
183
183
|
// Continue with remaining attestors
|