@aztec-labs/stdlib 6.0.0 → 6.1.0-nightly.20261024
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/dest/avm/avm.d.ts +210 -210
- package/dest/checkpoint/checkpoint_reexecution_tracker.d.ts +25 -3
- package/dest/checkpoint/checkpoint_reexecution_tracker.d.ts.map +1 -1
- package/dest/checkpoint/checkpoint_reexecution_tracker.js +22 -1
- package/dest/checkpoint/simulation_overrides.d.ts +8 -1
- package/dest/checkpoint/simulation_overrides.d.ts.map +1 -1
- package/dest/checkpoint/simulation_overrides.js +6 -2
- package/dest/epoch-helpers/index.d.ts +1 -3
- package/dest/epoch-helpers/index.d.ts.map +1 -1
- package/dest/epoch-helpers/index.js +2 -4
- package/dest/gas/index.d.ts +2 -1
- package/dest/gas/index.d.ts.map +1 -1
- package/dest/gas/index.js +1 -0
- package/dest/gas/rollup_fee_config.d.ts +50 -0
- package/dest/gas/rollup_fee_config.d.ts.map +1 -0
- package/dest/gas/rollup_fee_config.js +105 -0
- package/dest/gas/tx_gas_limits.d.ts +9 -9
- package/dest/gas/tx_gas_limits.d.ts.map +1 -1
- package/dest/gas/tx_gas_limits.js +8 -7
- package/dest/interfaces/block-builder.d.ts +2 -2
- package/dest/interfaces/block-builder.d.ts.map +1 -1
- package/dest/interfaces/block-builder.js +1 -2
- package/dest/p2p/checkpoint_proposal.d.ts +1 -1
- package/dest/p2p/checkpoint_proposal.d.ts.map +1 -1
- package/dest/p2p/checkpoint_proposal.js +5 -3
- package/dest/rollup/checkpoint_rollup_public_inputs.d.ts +1 -1
- package/dest/validators/errors.d.ts +4 -2
- package/dest/validators/errors.d.ts.map +1 -1
- package/dest/validators/errors.js +6 -2
- package/dest/validators/schemas.d.ts +15 -1
- package/dest/validators/schemas.d.ts.map +1 -1
- package/dest/validators/schemas.js +2 -0
- package/dest/validators/types.d.ts +10 -4
- package/dest/validators/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/checkpoint/checkpoint_reexecution_tracker.ts +48 -2
- package/src/checkpoint/simulation_overrides.ts +11 -2
- package/src/epoch-helpers/index.ts +0 -3
- package/src/gas/README.md +3 -3
- package/src/gas/index.ts +1 -0
- package/src/gas/rollup_fee_config.ts +141 -0
- package/src/gas/tx_gas_limits.ts +10 -7
- package/src/interfaces/block-builder.ts +1 -2
- package/src/p2p/checkpoint_proposal.ts +5 -3
- package/src/validators/errors.ts +4 -0
- package/src/validators/schemas.ts +2 -0
- package/src/validators/types.ts +10 -2
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { RollupContract } from '@aztec-labs/ethereum/contracts';
|
|
2
|
+
import { type Logger, createLogger } from '@aztec-labs/foundation/log';
|
|
3
|
+
import { RunningPromise } from '@aztec-labs/foundation/running-promise';
|
|
4
|
+
|
|
5
|
+
/** Rollup fee settings that governance can change on L1, as read at one L1 block. */
|
|
6
|
+
export type RollupFeeConfig = {
|
|
7
|
+
manaTarget: bigint;
|
|
8
|
+
/** Read from L1 (getManaLimit), not derived as 2 x target. */
|
|
9
|
+
manaLimit: bigint;
|
|
10
|
+
provingCostPerManaInEth: bigint;
|
|
11
|
+
protocolFeeMarginBps: number;
|
|
12
|
+
/** L1 block the values were read at. */
|
|
13
|
+
l1BlockNumber: bigint;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Source of the rollup's live fee settings. */
|
|
17
|
+
export interface RollupFeeConfigProvider {
|
|
18
|
+
/**
|
|
19
|
+
* Last config successfully read from L1. Usually at most one polling interval old, but it stays at the last good
|
|
20
|
+
* read for as long as L1 reads keep failing.
|
|
21
|
+
*/
|
|
22
|
+
getFeeConfig(): RollupFeeConfig;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Default polling interval. Each pass reads L1's block number through the client's cache, and reads the fee settings
|
|
27
|
+
* only when that block is newer than the last read, so it is cheap.
|
|
28
|
+
*/
|
|
29
|
+
const DEFAULT_POLLING_INTERVAL_MS = 1_000;
|
|
30
|
+
|
|
31
|
+
/** Keeps a RollupFeeConfig in step with L1 by polling the rollup. */
|
|
32
|
+
export class RollupFeeConfigTracker implements RollupFeeConfigProvider {
|
|
33
|
+
private readonly loop: RunningPromise;
|
|
34
|
+
|
|
35
|
+
private constructor(
|
|
36
|
+
private readonly rollup: RollupContract,
|
|
37
|
+
private latest: RollupFeeConfig,
|
|
38
|
+
pollingIntervalMs: number,
|
|
39
|
+
private readonly log: Logger,
|
|
40
|
+
) {
|
|
41
|
+
this.loop = new RunningPromise(() => this.poll(), log, pollingIntervalMs);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Does the first read, so getFeeConfig() always has a value. */
|
|
45
|
+
public static async create(
|
|
46
|
+
rollup: RollupContract,
|
|
47
|
+
opts: { pollingIntervalMs?: number; logger?: Logger } = {},
|
|
48
|
+
): Promise<RollupFeeConfigTracker> {
|
|
49
|
+
const log = opts.logger ?? createLogger('rollup-fee-config');
|
|
50
|
+
const l1BlockNumber = await rollup.client.getBlockNumber();
|
|
51
|
+
const initial = await readRollupFeeConfig(rollup, l1BlockNumber);
|
|
52
|
+
log.info(`Read rollup fee config at L1 block ${l1BlockNumber}`, initial);
|
|
53
|
+
return new RollupFeeConfigTracker(rollup, initial, opts.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS, log);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public start(): void {
|
|
57
|
+
this.loop.start();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async stop(): Promise<void> {
|
|
61
|
+
await this.loop.stop();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public getFeeConfig(): RollupFeeConfig {
|
|
65
|
+
return this.latest;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* One pass of the polling loop: reads the config at L1's latest block. It takes the client's cached block number and
|
|
70
|
+
* skips blocks it has already read, so a pass within the cache window costs no new reads, and a lagging RPC node
|
|
71
|
+
* cannot move the value back. A failed read only logs: the last value stays until a later pass succeeds.
|
|
72
|
+
*/
|
|
73
|
+
private async poll(): Promise<void> {
|
|
74
|
+
try {
|
|
75
|
+
const l1BlockNumber = await this.rollup.client.getBlockNumber();
|
|
76
|
+
if (l1BlockNumber <= this.latest.l1BlockNumber) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.update(await readRollupFeeConfig(this.rollup, l1BlockNumber));
|
|
80
|
+
} catch (err) {
|
|
81
|
+
this.log.warn(`Failed to refresh rollup fee config from L1, keeping the last value`, {
|
|
82
|
+
err,
|
|
83
|
+
l1BlockNumber: this.latest.l1BlockNumber,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private update(config: RollupFeeConfig): void {
|
|
89
|
+
const previous = this.latest;
|
|
90
|
+
this.latest = config;
|
|
91
|
+
if (
|
|
92
|
+
config.manaTarget !== previous.manaTarget ||
|
|
93
|
+
config.manaLimit !== previous.manaLimit ||
|
|
94
|
+
config.provingCostPerManaInEth !== previous.provingCostPerManaInEth ||
|
|
95
|
+
config.protocolFeeMarginBps !== previous.protocolFeeMarginBps
|
|
96
|
+
) {
|
|
97
|
+
this.log.info(`Rollup fee config changed at L1 block ${config.l1BlockNumber}`, config);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A provider that never reads L1, for tests and for nodes that run without one. The default leaves the mana limit
|
|
104
|
+
* effectively unbounded.
|
|
105
|
+
*/
|
|
106
|
+
export class TestRollupFeeConfigProvider implements RollupFeeConfigProvider {
|
|
107
|
+
private config: RollupFeeConfig;
|
|
108
|
+
|
|
109
|
+
constructor(config: Partial<RollupFeeConfig> = {}) {
|
|
110
|
+
this.config = { ...DEFAULT_TEST_ROLLUP_FEE_CONFIG, ...config };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Replaces some of the values, as a governance update would. */
|
|
114
|
+
public setFeeConfig(config: Partial<RollupFeeConfig>): void {
|
|
115
|
+
this.config = { ...this.config, ...config };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public getFeeConfig(): RollupFeeConfig {
|
|
119
|
+
return this.config;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const DEFAULT_TEST_ROLLUP_FEE_CONFIG: RollupFeeConfig = {
|
|
124
|
+
manaTarget: BigInt(Math.floor(Number.MAX_SAFE_INTEGER / 2)),
|
|
125
|
+
manaLimit: BigInt(Number.MAX_SAFE_INTEGER),
|
|
126
|
+
provingCostPerManaInEth: 0n,
|
|
127
|
+
protocolFeeMarginBps: 0,
|
|
128
|
+
l1BlockNumber: 0n,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/** Reads every fee setting at the same L1 block, so the values describe one state. */
|
|
132
|
+
async function readRollupFeeConfig(rollup: RollupContract, l1BlockNumber: bigint): Promise<RollupFeeConfig> {
|
|
133
|
+
const opts = { blockNumber: l1BlockNumber };
|
|
134
|
+
const [manaTarget, manaLimit, provingCostPerManaInEth, protocolFeeMarginBps] = await Promise.all([
|
|
135
|
+
rollup.getManaTarget(opts),
|
|
136
|
+
rollup.getManaLimit(opts),
|
|
137
|
+
rollup.getProvingCostPerMana(opts),
|
|
138
|
+
rollup.getProtocolFeeMargin(opts),
|
|
139
|
+
]);
|
|
140
|
+
return { manaTarget, manaLimit, provingCostPerManaInEth, protocolFeeMarginBps, l1BlockNumber };
|
|
141
|
+
}
|
package/src/gas/tx_gas_limits.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { type ProposerTimetableConfig, buildProposerTimetable } from '../timetable/build_proposer_timetable.js';
|
|
11
11
|
import type { SlotTimingConstants } from '../timetable/consensus_timetable.js';
|
|
12
12
|
import { Gas } from './gas.js';
|
|
13
|
+
import type { RollupFeeConfig } from './rollup_fee_config.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Network-minimum per-block budget multiplier for L2 gas and tx-count allocation. A block packer must
|
|
@@ -75,7 +76,7 @@ export function getDaCheckpointBudgetForTxs(maxBlocksPerCheckpoint: number): num
|
|
|
75
76
|
* raw blob capacity net of encoding overhead for every block — so the admission limit is consistent with the
|
|
76
77
|
* builder's blob-field cap.
|
|
77
78
|
*
|
|
78
|
-
* @param manaCheckpointBudget - L2 (mana) budget per checkpoint (
|
|
79
|
+
* @param manaCheckpointBudget - L2 (mana) budget per checkpoint (the rollup's live mana limit).
|
|
79
80
|
*/
|
|
80
81
|
export function computeNetworkTxGasLimits(opts: { maxBlocksPerCheckpoint: number; manaCheckpointBudget: number }): Gas {
|
|
81
82
|
const blocks = Math.max(1, opts.maxBlocksPerCheckpoint);
|
|
@@ -101,15 +102,17 @@ export function computeNetworkTxGasLimits(opts: { maxBlocksPerCheckpoint: number
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
/**
|
|
104
|
-
* Network tx gas limits derived from a sequencer/p2p config
|
|
105
|
-
* single source of truth shared by `getNodeInfo` (advertising) and the RPC/gossip/pool gas
|
|
106
|
-
* (enforcing), so a node never rejects a tx it advertised as admissible. Always uses the network-minimum
|
|
107
|
-
* multipliers, never the node's (possibly higher) configured multipliers.
|
|
105
|
+
* Network tx gas limits derived from a sequencer/p2p config, the L1 slot-timing constants and the rollup's live
|
|
106
|
+
* mana limit. The single source of truth shared by `getNodeInfo` (advertising) and the RPC/gossip/pool gas
|
|
107
|
+
* validators (enforcing), so a node never rejects a tx it advertised as admissible. Always uses the network-minimum
|
|
108
|
+
* multipliers, never the node's (possibly higher) configured multipliers. Callers pass the fee config they read for
|
|
109
|
+
* this call, so a mana limit raised by governance takes effect without a restart.
|
|
108
110
|
*/
|
|
109
111
|
export function getNetworkTxGasLimits(
|
|
110
112
|
config: ProposerTimetableConfig,
|
|
111
|
-
l1Constants: SlotTimingConstants
|
|
113
|
+
l1Constants: SlotTimingConstants,
|
|
114
|
+
feeConfig: Pick<RollupFeeConfig, 'manaLimit'>,
|
|
112
115
|
): Gas {
|
|
113
116
|
const maxBlocksPerCheckpoint = buildProposerTimetable(config, l1Constants).getMaxBlocksPerCheckpoint();
|
|
114
|
-
return computeNetworkTxGasLimits({ maxBlocksPerCheckpoint, manaCheckpointBudget:
|
|
117
|
+
return computeNetworkTxGasLimits({ maxBlocksPerCheckpoint, manaCheckpointBudget: Number(feeConfig.manaLimit) });
|
|
115
118
|
}
|
|
@@ -87,7 +87,7 @@ export interface PublicProcessorValidator {
|
|
|
87
87
|
nullifierCache?: { addNullifiers: (nullifiers: Buffer[]) => void };
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
export type FullNodeBlockBuilderConfig = Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'
|
|
90
|
+
export type FullNodeBlockBuilderConfig = Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'> &
|
|
91
91
|
Pick<ChainConfig, 'l1ChainId' | 'rollupVersion'> &
|
|
92
92
|
Pick<
|
|
93
93
|
SequencerConfig,
|
|
@@ -112,7 +112,6 @@ export const FullNodeBlockBuilderConfigKeys: (keyof FullNodeBlockBuilderConfig)[
|
|
|
112
112
|
'maxTxsPerCheckpoint',
|
|
113
113
|
'maxL2BlockGas',
|
|
114
114
|
'maxDABlockGas',
|
|
115
|
-
'rollupManaLimit',
|
|
116
115
|
] as const;
|
|
117
116
|
|
|
118
117
|
/** Thrown when the number of successfully processed transactions is below the required minimum. */
|
|
@@ -310,9 +310,11 @@ export class CheckpointProposal extends Gossipable implements Signable {
|
|
|
310
310
|
|
|
311
311
|
// Decoding is lenient on purpose, for forward compatibility: trailing bytes are ignored and any non-zero
|
|
312
312
|
// presence flag reads as present, so a newer version can append fields that older nodes skip over. Rejecting
|
|
313
|
-
// them would make every wire extension a coordinated upgrade.
|
|
314
|
-
// several
|
|
315
|
-
//
|
|
313
|
+
// them would make every wire extension a coordinated upgrade. One signed payload can therefore reach the
|
|
314
|
+
// network under several encodings, each with its own P2P message identifier, which hashes the raw bytes. In
|
|
315
|
+
// particular the signature and the payload hash cover the checkpoint header, archive and fee modifier but not
|
|
316
|
+
// the embedded last block, so the same signed payload can travel with or without that block. The gossip layer
|
|
317
|
+
// must not treat a stored payload hash as covering the embedded block.
|
|
316
318
|
|
|
317
319
|
const checkpointHeader = reader.readObject(CheckpointHeader);
|
|
318
320
|
const archive = reader.readObject(Fr);
|
package/src/validators/errors.ts
CHANGED
|
@@ -66,6 +66,10 @@ export class ReExStateMismatchError extends ValidatorError {
|
|
|
66
66
|
constructor(
|
|
67
67
|
public readonly expectedArchiveRoot: Fr,
|
|
68
68
|
public readonly actualArchiveRoot: Fr,
|
|
69
|
+
// Which of the two comparisons failed. Only an archive-only mismatch binds a checkpoint that commits to this block
|
|
70
|
+
// as the committed sequence's last; see checkpointCommitsToRejectedBlock.
|
|
71
|
+
public readonly headerMismatch: boolean,
|
|
72
|
+
public readonly archiveMismatch: boolean,
|
|
69
73
|
) {
|
|
70
74
|
super('Re-execution state mismatch');
|
|
71
75
|
}
|
package/src/validators/types.ts
CHANGED
|
@@ -6,13 +6,19 @@ export type ValidatorStatusType = 'proposer' | 'attestation';
|
|
|
6
6
|
/**
|
|
7
7
|
* Per-slot status for a validator.
|
|
8
8
|
*
|
|
9
|
-
* Proposer statuses (six-case taxonomy):
|
|
9
|
+
* Proposer statuses (six-case taxonomy, with case 5 refined into 5a and 5b):
|
|
10
10
|
* - `blocks-missed` — no block proposals seen for the slot (case 1).
|
|
11
11
|
* - `checkpoint-missed` — block proposals seen but no checkpoint proposal (case 2).
|
|
12
12
|
* - `checkpoint-unvalidated` — checkpoint proposal seen but local re-execution couldn't
|
|
13
13
|
* validate (missing txs, timeouts, etc.) (case 3).
|
|
14
14
|
* - `checkpoint-invalid` — checkpoint proposal re-executed and rejected as invalid (case 4).
|
|
15
|
-
* - `checkpoint-valid` — checkpoint proposal re-executed locally as valid
|
|
15
|
+
* - `checkpoint-valid` — checkpoint proposal re-executed locally as valid, but it did not reach L1 and
|
|
16
|
+
* could not be refined into 5a or 5b (e.g. below quorum, equivocation) (case 5).
|
|
17
|
+
* - `checkpoint-orphaned` — valid checkpoint proposal that could not land because the parent it built on never
|
|
18
|
+
* landed on L1, or because an earlier slot landed its checkpoint number after it reached
|
|
19
|
+
* quorum (case 5b).
|
|
20
|
+
* - `checkpoint-unpublished` — valid checkpoint proposal with its parent on L1 and a quorum of attestations,
|
|
21
|
+
* which the proposer still failed to land on L1 (case 5a).
|
|
16
22
|
* - `checkpoint-mined` — checkpoint published on L1 (case 6).
|
|
17
23
|
*
|
|
18
24
|
* Attestor statuses:
|
|
@@ -22,6 +28,8 @@ export type ValidatorStatusType = 'proposer' | 'attestation';
|
|
|
22
28
|
*/
|
|
23
29
|
export type ValidatorStatusInSlot =
|
|
24
30
|
| 'checkpoint-mined'
|
|
31
|
+
| 'checkpoint-unpublished'
|
|
32
|
+
| 'checkpoint-orphaned'
|
|
25
33
|
| 'checkpoint-valid'
|
|
26
34
|
| 'checkpoint-invalid'
|
|
27
35
|
| 'checkpoint-unvalidated'
|