@aztec/sequencer-client 0.0.1-commit.f504929 → 0.0.1-commit.f5d02921e
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/client/sequencer-client.d.ts +4 -1
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +46 -23
- package/dest/config.d.ts +25 -5
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +21 -12
- package/dest/global_variable_builder/global_builder.d.ts +15 -9
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +29 -25
- package/dest/global_variable_builder/index.d.ts +2 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/publisher/config.d.ts +13 -1
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +17 -2
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +2 -2
- package/dest/publisher/sequencer-publisher.d.ts +52 -25
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +98 -42
- package/dest/sequencer/checkpoint_proposal_job.d.ts +33 -8
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +284 -158
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/events.d.ts +2 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +5 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +11 -0
- package/dest/sequencer/sequencer.d.ts +23 -10
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +123 -68
- package/dest/sequencer/timetable.d.ts +4 -3
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +6 -7
- package/dest/sequencer/types.d.ts +2 -2
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +7 -9
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +39 -30
- package/package.json +27 -28
- package/src/client/sequencer-client.ts +56 -21
- package/src/config.ts +28 -14
- package/src/global_variable_builder/global_builder.ts +37 -26
- package/src/global_variable_builder/index.ts +1 -1
- package/src/publisher/config.ts +32 -0
- package/src/publisher/sequencer-publisher-factory.ts +3 -3
- package/src/publisher/sequencer-publisher.ts +144 -54
- package/src/sequencer/checkpoint_proposal_job.ts +367 -175
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/metrics.ts +14 -0
- package/src/sequencer/sequencer.ts +178 -79
- package/src/sequencer/timetable.ts +7 -7
- package/src/sequencer/types.ts +1 -1
- package/src/test/mock_checkpoint_builder.ts +51 -48
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
|
|
1
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import { unfreeze } from '@aztec/foundation/types';
|
|
4
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
2
5
|
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
3
|
-
import { Gas } from '@aztec/stdlib/gas';
|
|
4
6
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
5
7
|
import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
6
8
|
/**
|
|
@@ -63,8 +65,10 @@ import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
|
63
65
|
let block;
|
|
64
66
|
let usedTxs;
|
|
65
67
|
if (this.blockProvider) {
|
|
66
|
-
// Dynamic mode: get block from provider
|
|
67
|
-
block = this.blockProvider();
|
|
68
|
+
// Dynamic mode: get block from provider, cloning to avoid shared references across multiple buildBlock calls
|
|
69
|
+
block = L2Block.fromBuffer(this.blockProvider().toBuffer());
|
|
70
|
+
block.header.globalVariables.blockNumber = blockNumber;
|
|
71
|
+
await block.header.recomputeHash();
|
|
68
72
|
usedTxs = [];
|
|
69
73
|
this.builtBlocks.push(block);
|
|
70
74
|
} else {
|
|
@@ -87,61 +91,63 @@ import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
|
87
91
|
}
|
|
88
92
|
return {
|
|
89
93
|
block,
|
|
90
|
-
publicGas: Gas.empty(),
|
|
91
94
|
publicProcessorDuration: 0,
|
|
92
95
|
numTxs: block?.body?.txEffects?.length ?? usedTxs.length,
|
|
93
96
|
usedTxs,
|
|
94
|
-
failedTxs: []
|
|
95
|
-
usedTxBlobFields: block?.body?.txEffects?.reduce((sum, tx)=>sum + tx.getNumBlobFields(), 0) ?? 0
|
|
97
|
+
failedTxs: []
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
100
|
completeCheckpoint() {
|
|
99
101
|
this.completeCheckpointCalled = true;
|
|
100
102
|
const allBlocks = this.blockProvider ? this.builtBlocks : this.blocks;
|
|
101
|
-
|
|
102
|
-
// Create a CheckpointHeader from the last block's header for testing
|
|
103
|
-
const checkpointHeader = this.createCheckpointHeader(lastBlock);
|
|
104
|
-
return Promise.resolve(new Checkpoint(makeAppendOnlyTreeSnapshot(lastBlock.header.globalVariables.blockNumber + 1), checkpointHeader, allBlocks, this.checkpointNumber));
|
|
103
|
+
return this.buildCheckpoint(allBlocks);
|
|
105
104
|
}
|
|
106
105
|
getCheckpoint() {
|
|
107
106
|
this.getCheckpointCalled = true;
|
|
108
107
|
const builtBlocks = this.blockProvider ? this.builtBlocks : this.blocks.slice(0, this.blockIndex);
|
|
109
|
-
|
|
110
|
-
if (!lastBlock) {
|
|
108
|
+
if (builtBlocks.length === 0) {
|
|
111
109
|
throw new Error('No blocks built yet');
|
|
112
110
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
return this.buildCheckpoint(builtBlocks);
|
|
112
|
+
}
|
|
113
|
+
/** Builds a structurally valid Checkpoint from a list of blocks, fixing up indexes and archive chaining. */ async buildCheckpoint(blocks) {
|
|
114
|
+
// Fix up indexWithinCheckpoint and archive chaining so the checkpoint passes structural validation.
|
|
115
|
+
for(let i = 0; i < blocks.length; i++){
|
|
116
|
+
blocks[i].indexWithinCheckpoint = IndexWithinCheckpoint(i);
|
|
117
|
+
if (i > 0) {
|
|
118
|
+
unfreeze(blocks[i].header).lastArchive = blocks[i - 1].archive;
|
|
119
|
+
await blocks[i].header.recomputeHash();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const firstBlock = blocks[0];
|
|
123
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
124
|
+
const gv = firstBlock.header.globalVariables;
|
|
125
|
+
const checkpointHeader = CheckpointHeader.empty({
|
|
126
|
+
lastArchiveRoot: firstBlock.header.lastArchive.root,
|
|
125
127
|
blockHeadersHash: Fr.random(),
|
|
126
128
|
slotNumber: gv.slotNumber,
|
|
127
129
|
timestamp: gv.timestamp,
|
|
128
130
|
coinbase: gv.coinbase,
|
|
129
131
|
feeRecipient: gv.feeRecipient,
|
|
130
132
|
gasFees: gv.gasFees,
|
|
131
|
-
totalManaUsed: header.totalManaUsed
|
|
133
|
+
totalManaUsed: lastBlock.header.totalManaUsed
|
|
132
134
|
});
|
|
135
|
+
return new Checkpoint(makeAppendOnlyTreeSnapshot(lastBlock.header.globalVariables.blockNumber + 1), checkpointHeader, blocks, this.checkpointNumber);
|
|
133
136
|
}
|
|
134
|
-
/**
|
|
135
|
-
this.blocks = [];
|
|
137
|
+
/** Resets per-checkpoint state (built blocks, consumed txs) while preserving config (blockProvider, seeded blocks). */ resetCheckpointState() {
|
|
136
138
|
this.builtBlocks = [];
|
|
137
|
-
this.usedTxsPerBlock = [];
|
|
138
139
|
this.blockIndex = 0;
|
|
139
|
-
this.buildBlockCalls = [];
|
|
140
140
|
this.consumedTxHashes.clear();
|
|
141
141
|
this.completeCheckpointCalled = false;
|
|
142
142
|
this.getCheckpointCalled = false;
|
|
143
|
+
}
|
|
144
|
+
/** Reset for reuse in another test */ reset() {
|
|
145
|
+
this.blocks = [];
|
|
146
|
+
this.usedTxsPerBlock = [];
|
|
147
|
+
this.buildBlockCalls = [];
|
|
143
148
|
this.errorOnBuild = undefined;
|
|
144
149
|
this.blockProvider = undefined;
|
|
150
|
+
this.resetCheckpointState();
|
|
145
151
|
}
|
|
146
152
|
}
|
|
147
153
|
/**
|
|
@@ -175,7 +181,8 @@ import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
|
175
181
|
l1GenesisTime: 0n,
|
|
176
182
|
slotDuration: 24,
|
|
177
183
|
l1ChainId: 1,
|
|
178
|
-
rollupVersion: 1
|
|
184
|
+
rollupVersion: 1,
|
|
185
|
+
rollupManaLimit: 200_000_000
|
|
179
186
|
};
|
|
180
187
|
}
|
|
181
188
|
updateConfig(config) {
|
|
@@ -192,6 +199,8 @@ import { makeAppendOnlyTreeSnapshot } from '@aztec/stdlib/testing';
|
|
|
192
199
|
if (!this.checkpointBuilder) {
|
|
193
200
|
// Auto-create a builder if none was set
|
|
194
201
|
this.checkpointBuilder = new MockCheckpointBuilder(constants, checkpointNumber);
|
|
202
|
+
} else {
|
|
203
|
+
this.checkpointBuilder.resetCheckpointState();
|
|
195
204
|
}
|
|
196
205
|
return Promise.resolve(this.checkpointBuilder);
|
|
197
206
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.f5d02921e",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -26,38 +26,37 @@
|
|
|
26
26
|
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aztec/aztec.js": "0.0.1-commit.
|
|
30
|
-
"@aztec/bb-prover": "0.0.1-commit.
|
|
31
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
32
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
33
|
-
"@aztec/constants": "0.0.1-commit.
|
|
34
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
35
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
36
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
37
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
38
|
-
"@aztec/
|
|
39
|
-
"@aztec/
|
|
40
|
-
"@aztec/noir-
|
|
41
|
-
"@aztec/noir-
|
|
42
|
-
"@aztec/noir-
|
|
43
|
-
"@aztec/
|
|
44
|
-
"@aztec/
|
|
45
|
-
"@aztec/
|
|
46
|
-
"@aztec/
|
|
47
|
-
"@aztec/
|
|
48
|
-
"@aztec/
|
|
49
|
-
"@aztec/
|
|
50
|
-
"@aztec/
|
|
51
|
-
"@aztec/validator-
|
|
52
|
-
"@aztec/
|
|
53
|
-
"@aztec/world-state": "0.0.1-commit.f504929",
|
|
29
|
+
"@aztec/aztec.js": "0.0.1-commit.f5d02921e",
|
|
30
|
+
"@aztec/bb-prover": "0.0.1-commit.f5d02921e",
|
|
31
|
+
"@aztec/blob-client": "0.0.1-commit.f5d02921e",
|
|
32
|
+
"@aztec/blob-lib": "0.0.1-commit.f5d02921e",
|
|
33
|
+
"@aztec/constants": "0.0.1-commit.f5d02921e",
|
|
34
|
+
"@aztec/epoch-cache": "0.0.1-commit.f5d02921e",
|
|
35
|
+
"@aztec/ethereum": "0.0.1-commit.f5d02921e",
|
|
36
|
+
"@aztec/foundation": "0.0.1-commit.f5d02921e",
|
|
37
|
+
"@aztec/l1-artifacts": "0.0.1-commit.f5d02921e",
|
|
38
|
+
"@aztec/node-keystore": "0.0.1-commit.f5d02921e",
|
|
39
|
+
"@aztec/noir-acvm_js": "0.0.1-commit.f5d02921e",
|
|
40
|
+
"@aztec/noir-contracts.js": "0.0.1-commit.f5d02921e",
|
|
41
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.f5d02921e",
|
|
42
|
+
"@aztec/noir-types": "0.0.1-commit.f5d02921e",
|
|
43
|
+
"@aztec/p2p": "0.0.1-commit.f5d02921e",
|
|
44
|
+
"@aztec/protocol-contracts": "0.0.1-commit.f5d02921e",
|
|
45
|
+
"@aztec/prover-client": "0.0.1-commit.f5d02921e",
|
|
46
|
+
"@aztec/simulator": "0.0.1-commit.f5d02921e",
|
|
47
|
+
"@aztec/slasher": "0.0.1-commit.f5d02921e",
|
|
48
|
+
"@aztec/stdlib": "0.0.1-commit.f5d02921e",
|
|
49
|
+
"@aztec/telemetry-client": "0.0.1-commit.f5d02921e",
|
|
50
|
+
"@aztec/validator-client": "0.0.1-commit.f5d02921e",
|
|
51
|
+
"@aztec/validator-ha-signer": "0.0.1-commit.f5d02921e",
|
|
52
|
+
"@aztec/world-state": "0.0.1-commit.f5d02921e",
|
|
54
53
|
"lodash.chunk": "^4.2.0",
|
|
55
54
|
"tslib": "^2.4.0",
|
|
56
55
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
|
-
"@aztec/archiver": "0.0.1-commit.
|
|
60
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
58
|
+
"@aztec/archiver": "0.0.1-commit.f5d02921e",
|
|
59
|
+
"@aztec/kv-store": "0.0.1-commit.f5d02921e",
|
|
61
60
|
"@electric-sql/pglite": "^0.3.14",
|
|
62
61
|
"@jest/globals": "^30.0.0",
|
|
63
62
|
"@types/jest": "^30.0.0",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
+
import { MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT } from '@aztec/constants';
|
|
2
3
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
3
4
|
import { isAnvilTestChain } from '@aztec/ethereum/chain';
|
|
4
5
|
import { getPublicClient } from '@aztec/ethereum/client';
|
|
@@ -19,7 +20,7 @@ import { L1Metrics, type TelemetryClient } from '@aztec/telemetry-client';
|
|
|
19
20
|
import { FullNodeCheckpointsBuilder, NodeKeystoreAdapter, type ValidatorClient } from '@aztec/validator-client';
|
|
20
21
|
|
|
21
22
|
import { type SequencerClientConfig, getPublisherConfigFromSequencerConfig } from '../config.js';
|
|
22
|
-
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
23
|
+
import type { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
23
24
|
import { SequencerPublisherFactory } from '../publisher/sequencer-publisher-factory.js';
|
|
24
25
|
import { Sequencer, type SequencerConfig } from '../sequencer/index.js';
|
|
25
26
|
|
|
@@ -64,7 +65,9 @@ export class SequencerClient {
|
|
|
64
65
|
dateProvider: DateProvider;
|
|
65
66
|
epochCache?: EpochCache;
|
|
66
67
|
l1TxUtils: L1TxUtils[];
|
|
68
|
+
funderL1TxUtils?: L1TxUtils;
|
|
67
69
|
nodeKeyStore: KeystoreManager;
|
|
70
|
+
globalVariableBuilder: GlobalVariableBuilder;
|
|
68
71
|
},
|
|
69
72
|
) {
|
|
70
73
|
const {
|
|
@@ -86,16 +89,14 @@ export class SequencerClient {
|
|
|
86
89
|
publicClient,
|
|
87
90
|
l1TxUtils.map(x => x.getSenderAddress()),
|
|
88
91
|
);
|
|
89
|
-
const publisherManager = new PublisherManager(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
);
|
|
92
|
+
const publisherManager = new PublisherManager(l1TxUtils, getPublisherConfigFromSequencerConfig(config), {
|
|
93
|
+
bindings: log.getBindings(),
|
|
94
|
+
funder: deps.funderL1TxUtils,
|
|
95
|
+
});
|
|
94
96
|
const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
|
|
95
|
-
const [l1GenesisTime, slotDuration,
|
|
97
|
+
const [l1GenesisTime, slotDuration, rollupManaLimit] = await Promise.all([
|
|
96
98
|
rollupContract.getL1GenesisTime(),
|
|
97
99
|
rollupContract.getSlotDuration(),
|
|
98
|
-
rollupContract.getVersion(),
|
|
99
100
|
rollupContract.getManaLimit().then(Number),
|
|
100
101
|
] as const);
|
|
101
102
|
|
|
@@ -112,6 +113,7 @@ export class SequencerClient {
|
|
|
112
113
|
l1ChainId: chainId,
|
|
113
114
|
viemPollingIntervalMS: config.viemPollingIntervalMS,
|
|
114
115
|
ethereumSlotDuration: config.ethereumSlotDuration,
|
|
116
|
+
enableProposerPipelining: config.enableProposerPipelining,
|
|
115
117
|
},
|
|
116
118
|
{ dateProvider: deps.dateProvider },
|
|
117
119
|
));
|
|
@@ -137,17 +139,8 @@ export class SequencerClient {
|
|
|
137
139
|
});
|
|
138
140
|
|
|
139
141
|
const ethereumSlotDuration = config.ethereumSlotDuration;
|
|
140
|
-
const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration };
|
|
141
|
-
|
|
142
|
-
const globalsBuilder = new GlobalVariableBuilder({ ...config, ...l1Constants, rollupVersion });
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
if (sequencerManaLimit > rollupManaLimit) {
|
|
146
|
-
log.warn(
|
|
147
|
-
`Provided maxL2BlockGas ${sequencerManaLimit} is greater than the max allowed by L1. Setting limit to ${rollupManaLimit}.`,
|
|
148
|
-
);
|
|
149
|
-
sequencerManaLimit = rollupManaLimit;
|
|
150
|
-
}
|
|
143
|
+
const globalsBuilder = deps.globalVariableBuilder;
|
|
151
144
|
|
|
152
145
|
// When running in anvil, assume we can post a tx up until one second before the end of an L1 slot.
|
|
153
146
|
// Otherwise, we need the full L1 slot duration for publishing to ensure inclusion.
|
|
@@ -157,6 +150,10 @@ export class SequencerClient {
|
|
|
157
150
|
const l1PublishingTimeBasedOnChain = isAnvilTestChain(config.l1ChainId) ? 1 : ethereumSlotDuration;
|
|
158
151
|
const l1PublishingTime = config.l1PublishingTime ?? l1PublishingTimeBasedOnChain;
|
|
159
152
|
|
|
153
|
+
const { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock } = capPerBlockLimits(config, rollupManaLimit, log);
|
|
154
|
+
|
|
155
|
+
const l1Constants = { l1GenesisTime, slotDuration: Number(slotDuration), ethereumSlotDuration, rollupManaLimit };
|
|
156
|
+
|
|
160
157
|
const sequencer = new Sequencer(
|
|
161
158
|
publisherFactory,
|
|
162
159
|
validatorClient,
|
|
@@ -171,7 +168,7 @@ export class SequencerClient {
|
|
|
171
168
|
deps.dateProvider,
|
|
172
169
|
epochCache,
|
|
173
170
|
rollupContract,
|
|
174
|
-
{ ...config, l1PublishingTime, maxL2BlockGas
|
|
171
|
+
{ ...config, l1PublishingTime, maxL2BlockGas, maxDABlockGas, maxTxsPerBlock },
|
|
175
172
|
telemetryClient,
|
|
176
173
|
log,
|
|
177
174
|
);
|
|
@@ -199,7 +196,7 @@ export class SequencerClient {
|
|
|
199
196
|
await this.validatorClient?.start();
|
|
200
197
|
this.sequencer.start();
|
|
201
198
|
this.l1Metrics?.start();
|
|
202
|
-
await this.publisherManager.
|
|
199
|
+
await this.publisherManager.start();
|
|
203
200
|
}
|
|
204
201
|
|
|
205
202
|
/**
|
|
@@ -208,7 +205,7 @@ export class SequencerClient {
|
|
|
208
205
|
public async stop() {
|
|
209
206
|
await this.sequencer.stop();
|
|
210
207
|
await this.validatorClient?.stop();
|
|
211
|
-
this.publisherManager.
|
|
208
|
+
await this.publisherManager.stop();
|
|
212
209
|
this.l1Metrics?.stop();
|
|
213
210
|
}
|
|
214
211
|
|
|
@@ -234,3 +231,41 @@ export class SequencerClient {
|
|
|
234
231
|
return this.sequencer.maxL2BlockGas;
|
|
235
232
|
}
|
|
236
233
|
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Caps operator-provided per-block limits at checkpoint-level limits.
|
|
237
|
+
* Returns undefined for any limit the operator didn't set — the checkpoint builder handles redistribution.
|
|
238
|
+
*/
|
|
239
|
+
function capPerBlockLimits(
|
|
240
|
+
config: SequencerClientConfig,
|
|
241
|
+
rollupManaLimit: number,
|
|
242
|
+
log: ReturnType<typeof createLogger>,
|
|
243
|
+
): { maxL2BlockGas: number | undefined; maxDABlockGas: number | undefined; maxTxsPerBlock: number | undefined } {
|
|
244
|
+
let maxL2BlockGas = config.maxL2BlockGas;
|
|
245
|
+
if (maxL2BlockGas !== undefined && maxL2BlockGas > rollupManaLimit) {
|
|
246
|
+
log.warn(`Provided MAX_L2_BLOCK_GAS ${maxL2BlockGas} exceeds rollup mana limit ${rollupManaLimit} (capping)`);
|
|
247
|
+
maxL2BlockGas = rollupManaLimit;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
let maxDABlockGas = config.maxDABlockGas;
|
|
251
|
+
if (maxDABlockGas !== undefined && maxDABlockGas > MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT) {
|
|
252
|
+
log.warn(
|
|
253
|
+
`Provided MAX_DA_BLOCK_GAS ${maxDABlockGas} exceeds DA checkpoint limit ${MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT} (capping)`,
|
|
254
|
+
);
|
|
255
|
+
maxDABlockGas = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let maxTxsPerBlock = config.maxTxsPerBlock;
|
|
259
|
+
if (
|
|
260
|
+
maxTxsPerBlock !== undefined &&
|
|
261
|
+
config.maxTxsPerCheckpoint !== undefined &&
|
|
262
|
+
maxTxsPerBlock > config.maxTxsPerCheckpoint
|
|
263
|
+
) {
|
|
264
|
+
log.warn(
|
|
265
|
+
`Provided MAX_TX_PER_BLOCK ${maxTxsPerBlock} exceeds MAX_TX_PER_CHECKPOINT ${config.maxTxsPerCheckpoint} (capping)`,
|
|
266
|
+
);
|
|
267
|
+
maxTxsPerBlock = config.maxTxsPerCheckpoint;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return { maxL2BlockGas, maxDABlockGas, maxTxsPerBlock };
|
|
271
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -13,9 +13,10 @@ import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
|
|
|
13
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
14
14
|
import {
|
|
15
15
|
type ChainConfig,
|
|
16
|
-
|
|
16
|
+
type PipelineConfig,
|
|
17
17
|
type SequencerConfig,
|
|
18
18
|
chainConfigMappings,
|
|
19
|
+
pipelineConfigMappings,
|
|
19
20
|
sharedSequencerConfigMappings,
|
|
20
21
|
} from '@aztec/stdlib/config';
|
|
21
22
|
import type { ResolvedSequencerConfig } from '@aztec/stdlib/interfaces/server';
|
|
@@ -36,15 +37,13 @@ export type { SequencerConfig };
|
|
|
36
37
|
* Default values for SequencerConfig.
|
|
37
38
|
* Centralized location for all sequencer configuration defaults.
|
|
38
39
|
*/
|
|
39
|
-
export const DefaultSequencerConfig
|
|
40
|
+
export const DefaultSequencerConfig = {
|
|
40
41
|
sequencerPollingIntervalMS: 500,
|
|
41
|
-
maxTxsPerBlock: DEFAULT_MAX_TXS_PER_BLOCK,
|
|
42
42
|
minTxsPerBlock: 1,
|
|
43
43
|
buildCheckpointIfEmpty: false,
|
|
44
44
|
publishTxsWithProposals: false,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
maxBlockSizeInBytes: 1024 * 1024,
|
|
45
|
+
perBlockAllocationMultiplier: 1.2,
|
|
46
|
+
redistributeCheckpointBudget: true,
|
|
48
47
|
enforceTimeTable: true,
|
|
49
48
|
attestationPropagationTime: DEFAULT_P2P_PROPAGATION_TIME,
|
|
50
49
|
secondsBeforeInvalidatingBlockAsCommitteeMember: 144, // 12 L1 blocks
|
|
@@ -59,7 +58,7 @@ export const DefaultSequencerConfig: ResolvedSequencerConfig = {
|
|
|
59
58
|
shuffleAttestationOrdering: false,
|
|
60
59
|
skipPushProposedBlocksToArchiver: false,
|
|
61
60
|
skipPublishingCheckpointsPercent: 0,
|
|
62
|
-
};
|
|
61
|
+
} satisfies ResolvedSequencerConfig;
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
64
|
* Configuration settings for the SequencerClient.
|
|
@@ -71,6 +70,7 @@ export type SequencerClientConfig = SequencerPublisherConfig &
|
|
|
71
70
|
SequencerConfig &
|
|
72
71
|
L1ReaderConfig &
|
|
73
72
|
ChainConfig &
|
|
73
|
+
PipelineConfig &
|
|
74
74
|
Pick<P2PConfig, 'txPublicSetupAllowListExtend'> &
|
|
75
75
|
Pick<L1ContractsConfig, 'ethereumSlotDuration' | 'aztecSlotDuration' | 'aztecEpochDuration'>;
|
|
76
76
|
|
|
@@ -80,6 +80,11 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
80
80
|
description: 'The number of ms to wait between polling for checking to build on the next slot.',
|
|
81
81
|
...numberConfigHelper(DefaultSequencerConfig.sequencerPollingIntervalMS),
|
|
82
82
|
},
|
|
83
|
+
maxTxsPerCheckpoint: {
|
|
84
|
+
env: 'SEQ_MAX_TX_PER_CHECKPOINT',
|
|
85
|
+
description: 'The maximum number of txs across all blocks in a checkpoint.',
|
|
86
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
87
|
+
},
|
|
83
88
|
minTxsPerBlock: {
|
|
84
89
|
env: 'SEQ_MIN_TX_PER_BLOCK',
|
|
85
90
|
description: 'The minimum number of txs to include in a block.',
|
|
@@ -97,12 +102,25 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
97
102
|
maxL2BlockGas: {
|
|
98
103
|
env: 'SEQ_MAX_L2_BLOCK_GAS',
|
|
99
104
|
description: 'The maximum L2 block gas.',
|
|
100
|
-
|
|
105
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
101
106
|
},
|
|
102
107
|
maxDABlockGas: {
|
|
103
108
|
env: 'SEQ_MAX_DA_BLOCK_GAS',
|
|
104
109
|
description: 'The maximum DA block gas.',
|
|
105
|
-
|
|
110
|
+
parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined),
|
|
111
|
+
},
|
|
112
|
+
perBlockAllocationMultiplier: {
|
|
113
|
+
env: 'SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER',
|
|
114
|
+
description:
|
|
115
|
+
'Per-block gas budget multiplier for both L2 and DA gas. Budget per block is (checkpointLimit / maxBlocks) * multiplier.' +
|
|
116
|
+
' Values greater than one allow early blocks to use more than their even share, relying on checkpoint-level capping for later blocks.',
|
|
117
|
+
...numberConfigHelper(DefaultSequencerConfig.perBlockAllocationMultiplier),
|
|
118
|
+
},
|
|
119
|
+
redistributeCheckpointBudget: {
|
|
120
|
+
env: 'SEQ_REDISTRIBUTE_CHECKPOINT_BUDGET',
|
|
121
|
+
description:
|
|
122
|
+
'Redistribute remaining checkpoint budget evenly across remaining blocks instead of allowing a single block to consume the entire remaining budget.',
|
|
123
|
+
...booleanConfigHelper(DefaultSequencerConfig.redistributeCheckpointBudget),
|
|
106
124
|
},
|
|
107
125
|
coinbase: {
|
|
108
126
|
env: 'COINBASE',
|
|
@@ -122,11 +140,6 @@ export const sequencerConfigMappings: ConfigMappingsType<SequencerConfig> = {
|
|
|
122
140
|
env: 'ACVM_BINARY_PATH',
|
|
123
141
|
description: 'The path to the ACVM binary',
|
|
124
142
|
},
|
|
125
|
-
maxBlockSizeInBytes: {
|
|
126
|
-
env: 'SEQ_MAX_BLOCK_SIZE_IN_BYTES',
|
|
127
|
-
description: 'Max block size',
|
|
128
|
-
...numberConfigHelper(DefaultSequencerConfig.maxBlockSizeInBytes),
|
|
129
|
-
},
|
|
130
143
|
enforceTimeTable: {
|
|
131
144
|
env: 'SEQ_ENFORCE_TIME_TABLE',
|
|
132
145
|
description: 'Whether to enforce the time table when building blocks',
|
|
@@ -231,6 +244,7 @@ export const sequencerClientConfigMappings: ConfigMappingsType<SequencerClientCo
|
|
|
231
244
|
...sequencerTxSenderConfigMappings,
|
|
232
245
|
...sequencerPublisherConfigMappings,
|
|
233
246
|
...chainConfigMappings,
|
|
247
|
+
...pipelineConfigMappings,
|
|
234
248
|
...pickConfigMappings(l1ContractsConfigMappings, ['ethereumSlotDuration', 'aztecSlotDuration', 'aztecEpochDuration']),
|
|
235
249
|
};
|
|
236
250
|
|
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
2
|
-
import type { L1ContractsConfig } from '@aztec/ethereum/config';
|
|
3
1
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
4
|
-
import type {
|
|
2
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
5
3
|
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
6
4
|
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
7
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
8
6
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import type { DateProvider } from '@aztec/foundation/timer';
|
|
10
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
|
-
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
10
|
+
import { type L1RollupConstants, getNextL1SlotTimestamp, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
12
11
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
13
12
|
import type {
|
|
13
|
+
BuildCheckpointGlobalVariablesOpts,
|
|
14
14
|
CheckpointGlobalVariables,
|
|
15
15
|
GlobalVariableBuilder as GlobalVariableBuilderInterface,
|
|
16
16
|
} from '@aztec/stdlib/tx';
|
|
17
17
|
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
/** Configuration for the GlobalVariableBuilder (excludes L1 client config). */
|
|
20
|
+
export type GlobalVariableBuilderConfig = {
|
|
21
|
+
l1Contracts: Pick<L1ContractAddresses, 'rollupAddress'>;
|
|
22
|
+
ethereumSlotDuration: number;
|
|
23
|
+
rollupVersion: bigint;
|
|
24
|
+
} & Pick<L1RollupConstants, 'slotDuration' | 'l1GenesisTime'>;
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Simple global variables builder.
|
|
@@ -27,7 +32,6 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
27
32
|
private currentL1BlockNumber: bigint | undefined = undefined;
|
|
28
33
|
|
|
29
34
|
private readonly rollupContract: RollupContract;
|
|
30
|
-
private readonly publicClient: ViemPublicClient;
|
|
31
35
|
private readonly ethereumSlotDuration: number;
|
|
32
36
|
private readonly aztecSlotDuration: number;
|
|
33
37
|
private readonly l1GenesisTime: bigint;
|
|
@@ -36,28 +40,18 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
36
40
|
private version: Fr;
|
|
37
41
|
|
|
38
42
|
constructor(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
private readonly dateProvider: DateProvider,
|
|
44
|
+
private readonly publicClient: ViemPublicClient,
|
|
45
|
+
config: GlobalVariableBuilderConfig,
|
|
42
46
|
) {
|
|
43
|
-
const { l1RpcUrls, l1ChainId: chainId, l1Contracts } = config;
|
|
44
|
-
|
|
45
|
-
const chain = createEthereumChain(l1RpcUrls, chainId);
|
|
46
|
-
|
|
47
47
|
this.version = new Fr(config.rollupVersion);
|
|
48
|
-
this.chainId = new Fr(
|
|
48
|
+
this.chainId = new Fr(this.publicClient.chain!.id);
|
|
49
49
|
|
|
50
50
|
this.ethereumSlotDuration = config.ethereumSlotDuration;
|
|
51
51
|
this.aztecSlotDuration = config.slotDuration;
|
|
52
52
|
this.l1GenesisTime = config.l1GenesisTime;
|
|
53
53
|
|
|
54
|
-
this.
|
|
55
|
-
chain: chain.chainInfo,
|
|
56
|
-
transport: fallback(chain.rpcUrls.map(url => http(url, { batch: false }))),
|
|
57
|
-
pollingInterval: config.viemPollingIntervalMS,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
this.rollupContract = new RollupContract(this.publicClient, l1Contracts.rollupAddress);
|
|
54
|
+
this.rollupContract = new RollupContract(this.publicClient, config.l1Contracts.rollupAddress);
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
/**
|
|
@@ -73,7 +67,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
73
67
|
const earliestTimestamp = await this.rollupContract.getTimestampForSlot(
|
|
74
68
|
SlotNumber.fromBigInt(BigInt(lastCheckpoint.slotNumber) + 1n),
|
|
75
69
|
);
|
|
76
|
-
const nextEthTimestamp =
|
|
70
|
+
const nextEthTimestamp = getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
71
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
72
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
73
|
+
});
|
|
77
74
|
const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp;
|
|
78
75
|
|
|
79
76
|
return new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true));
|
|
@@ -108,7 +105,10 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
108
105
|
const slot: SlotNumber =
|
|
109
106
|
maybeSlot ??
|
|
110
107
|
(await this.rollupContract.getSlotAt(
|
|
111
|
-
|
|
108
|
+
getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), {
|
|
109
|
+
l1GenesisTime: this.l1GenesisTime,
|
|
110
|
+
ethereumSlotDuration: this.ethereumSlotDuration,
|
|
111
|
+
}),
|
|
112
112
|
));
|
|
113
113
|
|
|
114
114
|
const checkpointGlobalVariables = await this.buildCheckpointGlobalVariables(coinbase, feeRecipient, slot);
|
|
@@ -120,6 +120,7 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
120
120
|
coinbase: EthAddress,
|
|
121
121
|
feeRecipient: AztecAddress,
|
|
122
122
|
slotNumber: SlotNumber,
|
|
123
|
+
opts?: BuildCheckpointGlobalVariablesOpts,
|
|
123
124
|
): Promise<CheckpointGlobalVariables> {
|
|
124
125
|
const { chainId, version } = this;
|
|
125
126
|
|
|
@@ -128,9 +129,19 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface {
|
|
|
128
129
|
l1GenesisTime: this.l1GenesisTime,
|
|
129
130
|
});
|
|
130
131
|
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
const
|
|
132
|
+
// When pipelining, force the proposed checkpoint number and fee header to the parent so that
|
|
133
|
+
// the fee computation matches what L1 will see when the previous pipelined checkpoint has landed.
|
|
134
|
+
const pendingNumberOverride = await this.rollupContract.makePendingCheckpointNumberOverride(
|
|
135
|
+
opts?.forcePendingCheckpointNumber,
|
|
136
|
+
);
|
|
137
|
+
const feeHeaderOverride = opts?.forceProposedFeeHeader
|
|
138
|
+
? await this.rollupContract.makeFeeHeaderOverride(
|
|
139
|
+
opts.forceProposedFeeHeader.checkpointNumber,
|
|
140
|
+
opts.forceProposedFeeHeader.feeHeader,
|
|
141
|
+
)
|
|
142
|
+
: [];
|
|
143
|
+
const stateOverride = RollupContract.mergeStateOverrides(pendingNumberOverride, feeHeaderOverride);
|
|
144
|
+
const gasFees = new GasFees(0, await this.rollupContract.getManaMinFeeAt(timestamp, true, stateOverride));
|
|
134
145
|
|
|
135
146
|
return { chainId, version, slotNumber, timestamp, coinbase, feeRecipient, gasFees };
|
|
136
147
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { GlobalVariableBuilder } from './global_builder.js';
|
|
1
|
+
export { GlobalVariableBuilder, type GlobalVariableBuilderConfig } from './global_builder.js';
|