@aztec/ethereum 3.0.0-nightly.20250911 → 3.0.0-nightly.20250912
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/config.d.ts +3 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +6 -0
- package/dest/contracts/rollup.d.ts +10 -4
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +27 -2
- package/dest/deploy_l1_contracts.d.ts +4 -4
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +45 -19
- package/dest/l1_artifacts.d.ts +89 -31
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils.js +4 -1
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +3 -1
- package/dest/test/chain_monitor.d.ts +4 -0
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +57 -11
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +10 -161
- package/package.json +5 -5
- package/src/config.ts +8 -0
- package/src/contracts/rollup.ts +37 -4
- package/src/deploy_l1_contracts.ts +61 -16
- package/src/l1_tx_utils.ts +11 -2
- package/src/queries.ts +3 -0
- package/src/test/chain_monitor.ts +64 -8
- package/src/utils.ts +13 -185
package/dest/utils.js
CHANGED
|
@@ -118,34 +118,16 @@ function getNestedErrorData(error) {
|
|
|
118
118
|
if (error instanceof Error) {
|
|
119
119
|
return new FormattedViemError(error.message, error?.metaMessages);
|
|
120
120
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// If we found a specific error detail, format it clearly
|
|
134
|
-
if (errorDetail) {
|
|
135
|
-
// Look for key sections of the formatted result to replace with highlighted error
|
|
136
|
-
let replaced = false;
|
|
137
|
-
// Try to find the Details: section
|
|
138
|
-
const detailsMatch = formattedRes.match(/Details: ([^\n]+)/);
|
|
139
|
-
if (detailsMatch) {
|
|
140
|
-
formattedRes = formattedRes.replace(detailsMatch[0], `Details: *${errorDetail}*`);
|
|
141
|
-
replaced = true;
|
|
142
|
-
}
|
|
143
|
-
// If we didn't find a Details section, add the error at the beginning
|
|
144
|
-
if (!replaced) {
|
|
145
|
-
formattedRes = `Error: *${errorDetail}*\n\n${formattedRes}`;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return new FormattedViemError(formattedRes.replace(/\\n/g, '\n'), error?.metaMessages);
|
|
121
|
+
const body = String(error);
|
|
122
|
+
const length = body.length;
|
|
123
|
+
// LogExplorer can only render up to 2500 characters in it's summary view. Try to keep the whole message below this number
|
|
124
|
+
// Limit the error to 2000 chacaters in order to allow code higher up to decorate this error with extra details (up to 500 characters)
|
|
125
|
+
if (length > 2000) {
|
|
126
|
+
const chunk = 950;
|
|
127
|
+
const truncated = length - 2 * chunk;
|
|
128
|
+
return new FormattedViemError(body.slice(0, chunk) + `...${truncated} characters truncated...` + body.slice(-1 * chunk));
|
|
129
|
+
}
|
|
130
|
+
return new FormattedViemError(body);
|
|
149
131
|
}
|
|
150
132
|
function stripAbis(obj) {
|
|
151
133
|
if (!obj || typeof obj !== 'object') {
|
|
@@ -166,139 +148,6 @@ function stripAbis(obj) {
|
|
|
166
148
|
}
|
|
167
149
|
});
|
|
168
150
|
}
|
|
169
|
-
function extractAndFormatRequestBody(message) {
|
|
170
|
-
// First check if message is extremely large and contains very large hex strings
|
|
171
|
-
if (message.length > 50000) {
|
|
172
|
-
message = replaceHexStrings(message, {
|
|
173
|
-
minLength: 10000,
|
|
174
|
-
truncateLength: 200
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
// Add a specific check for RPC calls with large params
|
|
178
|
-
if (message.includes('"method":"eth_sendRawTransaction"')) {
|
|
179
|
-
message = replaceHexStrings(message, {
|
|
180
|
-
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
181
|
-
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
// First handle Request body JSON
|
|
185
|
-
const requestBodyRegex = /Request body: ({[\s\S]*?})\n/g;
|
|
186
|
-
let result = message.replace(requestBodyRegex, (match, body)=>{
|
|
187
|
-
return `Request body: ${formatRequestBody(body)}\n`;
|
|
188
|
-
});
|
|
189
|
-
// Then handle Arguments section
|
|
190
|
-
const argsRegex = /((?:Request |Estimate Gas )?Arguments:[\s\S]*?(?=\n\n|$))/g;
|
|
191
|
-
result = result.replace(argsRegex, (section)=>{
|
|
192
|
-
const lines = section.split('\n');
|
|
193
|
-
const processedLines = lines.map((line)=>{
|
|
194
|
-
// Check if line contains a colon followed by content
|
|
195
|
-
const colonIndex = line.indexOf(':');
|
|
196
|
-
if (colonIndex !== -1) {
|
|
197
|
-
const [prefix, content] = [
|
|
198
|
-
line.slice(0, colonIndex + 1),
|
|
199
|
-
line.slice(colonIndex + 1).trim()
|
|
200
|
-
];
|
|
201
|
-
// If content contains a hex string, truncate it
|
|
202
|
-
if (content.includes('0x')) {
|
|
203
|
-
const processedContent = replaceHexStrings(content);
|
|
204
|
-
return `${prefix} ${processedContent}`;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return line;
|
|
208
|
-
});
|
|
209
|
-
return processedLines.join('\n');
|
|
210
|
-
});
|
|
211
|
-
// Finally, catch any remaining hex strings in the message
|
|
212
|
-
result = replaceHexStrings(result);
|
|
213
|
-
return result;
|
|
214
|
-
}
|
|
215
|
-
function truncateHex(hex, length = 100) {
|
|
216
|
-
if (!hex || typeof hex !== 'string') {
|
|
217
|
-
return hex;
|
|
218
|
-
}
|
|
219
|
-
if (!hex.startsWith('0x')) {
|
|
220
|
-
return hex;
|
|
221
|
-
}
|
|
222
|
-
if (hex.length <= length * 2) {
|
|
223
|
-
return hex;
|
|
224
|
-
}
|
|
225
|
-
// For extremely large hex strings, use more aggressive truncation
|
|
226
|
-
if (hex.length > 10000) {
|
|
227
|
-
return `${hex.slice(0, length)}...<${hex.length - length * 2} chars omitted>...${hex.slice(-length)}`;
|
|
228
|
-
}
|
|
229
|
-
return `${hex.slice(0, length)}...${hex.slice(-length)}`;
|
|
230
|
-
}
|
|
231
|
-
function replaceHexStrings(text, options = {}) {
|
|
232
|
-
const { minLength = 10, maxLength = Infinity, truncateLength = 100, pattern, transform = (hex)=>truncateHex(hex, truncateLength) } = options;
|
|
233
|
-
const hexRegex = pattern ?? new RegExp(`(0x[a-fA-F0-9]{${minLength},${maxLength}})`, 'g');
|
|
234
|
-
return text.replace(hexRegex, (match)=>transform(match));
|
|
235
|
-
}
|
|
236
|
-
function formatRequestBody(body) {
|
|
237
|
-
try {
|
|
238
|
-
// Special handling for eth_sendRawTransaction
|
|
239
|
-
if (body.includes('"method":"eth_sendRawTransaction"')) {
|
|
240
|
-
try {
|
|
241
|
-
const parsed = JSON.parse(body);
|
|
242
|
-
if (parsed.params && Array.isArray(parsed.params) && parsed.params.length > 0) {
|
|
243
|
-
// These are likely large transaction hex strings
|
|
244
|
-
parsed.params = parsed.params.map((param)=>{
|
|
245
|
-
if (typeof param === 'string' && param.startsWith('0x') && param.length > 1000) {
|
|
246
|
-
return truncateHex(param, 200);
|
|
247
|
-
}
|
|
248
|
-
return param;
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
return JSON.stringify(parsed, null, 2);
|
|
252
|
-
} catch {
|
|
253
|
-
// If specific parsing fails, fall back to regex-based truncation
|
|
254
|
-
return replaceHexStrings(body, {
|
|
255
|
-
pattern: /"params":\s*\[\s*"(0x[a-fA-F0-9]{1000,})"\s*\]/g,
|
|
256
|
-
transform: (hex)=>`"params":["${truncateHex(hex, 200)}"]`
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// For extremely large request bodies, use simple truncation instead of parsing
|
|
261
|
-
if (body.length > 50000) {
|
|
262
|
-
const jsonStart = body.indexOf('{');
|
|
263
|
-
const jsonEnd = body.lastIndexOf('}');
|
|
264
|
-
if (jsonStart >= 0 && jsonEnd > jsonStart) {
|
|
265
|
-
return replaceHexStrings(body, {
|
|
266
|
-
minLength: 10000,
|
|
267
|
-
truncateLength: 200
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
const parsed = JSON.parse(body);
|
|
272
|
-
// Process the entire request body
|
|
273
|
-
const processed = processParams(parsed);
|
|
274
|
-
return JSON.stringify(processed, null, 2);
|
|
275
|
-
} catch {
|
|
276
|
-
// If JSON parsing fails, do a simple truncation of any large hex strings
|
|
277
|
-
return replaceHexStrings(body, {
|
|
278
|
-
minLength: 1000,
|
|
279
|
-
truncateLength: 150
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// Recursively process all parameters that might contain hex strings
|
|
284
|
-
function processParams(obj) {
|
|
285
|
-
if (Array.isArray(obj)) {
|
|
286
|
-
return obj.map((item)=>processParams(item));
|
|
287
|
-
}
|
|
288
|
-
if (typeof obj === 'object' && obj !== null) {
|
|
289
|
-
const result = {};
|
|
290
|
-
for (const [key, value] of Object.entries(obj)){
|
|
291
|
-
result[key] = processParams(value);
|
|
292
|
-
}
|
|
293
|
-
return result;
|
|
294
|
-
}
|
|
295
|
-
if (typeof obj === 'string') {
|
|
296
|
-
if (obj.startsWith('0x')) {
|
|
297
|
-
return truncateHex(obj);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return obj;
|
|
301
|
-
}
|
|
302
151
|
export function tryGetCustomErrorName(err) {
|
|
303
152
|
try {
|
|
304
153
|
// See https://viem.sh/docs/contract/simulateContract#handling-custom-errors
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20250912",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"../package.common.json"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@aztec/blob-lib": "3.0.0-nightly.
|
|
35
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
36
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
37
|
-
"@aztec/l1-artifacts": "3.0.0-nightly.
|
|
34
|
+
"@aztec/blob-lib": "3.0.0-nightly.20250912",
|
|
35
|
+
"@aztec/constants": "3.0.0-nightly.20250912",
|
|
36
|
+
"@aztec/foundation": "3.0.0-nightly.20250912",
|
|
37
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20250912",
|
|
38
38
|
"@viem/anvil": "^0.0.10",
|
|
39
39
|
"dotenv": "^16.0.3",
|
|
40
40
|
"lodash.chunk": "^4.2.0",
|
package/src/config.ts
CHANGED
|
@@ -28,6 +28,8 @@ export type L1ContractsConfig = {
|
|
|
28
28
|
aztecEpochDuration: number;
|
|
29
29
|
/** The target validator committee size. */
|
|
30
30
|
aztecTargetCommitteeSize: number;
|
|
31
|
+
/** The number of epochs to lag behind the current epoch for validator selection. */
|
|
32
|
+
lagInEpochs: number;
|
|
31
33
|
/** The number of epochs after an epoch ends that proofs are still accepted. */
|
|
32
34
|
aztecProofSubmissionEpochs: number;
|
|
33
35
|
/** The deposit amount for a validator */
|
|
@@ -73,6 +75,7 @@ export const DefaultL1ContractsConfig = {
|
|
|
73
75
|
aztecSlotDuration: 36,
|
|
74
76
|
aztecEpochDuration: 32,
|
|
75
77
|
aztecTargetCommitteeSize: 48,
|
|
78
|
+
lagInEpochs: 2,
|
|
76
79
|
aztecProofSubmissionEpochs: 1, // you have a full epoch to submit a proof after the epoch to prove ends
|
|
77
80
|
activationThreshold: BigInt(100e18),
|
|
78
81
|
ejectionThreshold: BigInt(50e18),
|
|
@@ -303,6 +306,11 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
303
306
|
description: 'The target validator committee size.',
|
|
304
307
|
...numberConfigHelper(DefaultL1ContractsConfig.aztecTargetCommitteeSize),
|
|
305
308
|
},
|
|
309
|
+
lagInEpochs: {
|
|
310
|
+
env: 'AZTEC_LAG_IN_EPOCHS',
|
|
311
|
+
description: 'The number of epochs to lag behind the current epoch for validator selection.',
|
|
312
|
+
...numberConfigHelper(DefaultL1ContractsConfig.lagInEpochs),
|
|
313
|
+
},
|
|
306
314
|
aztecProofSubmissionEpochs: {
|
|
307
315
|
env: 'AZTEC_PROOF_SUBMISSION_EPOCHS',
|
|
308
316
|
description: 'The number of epochs after an epoch ends that proofs are still accepted.',
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type GetContractReturnType,
|
|
11
11
|
type Hex,
|
|
12
12
|
type StateOverride,
|
|
13
|
+
type WatchContractEventReturnType,
|
|
13
14
|
encodeFunctionData,
|
|
14
15
|
getContract,
|
|
15
16
|
hexToBigInt,
|
|
@@ -225,6 +226,11 @@ export class RollupContract {
|
|
|
225
226
|
return this.rollup.read.getLocalEjectionThreshold();
|
|
226
227
|
}
|
|
227
228
|
|
|
229
|
+
@memoize
|
|
230
|
+
getLagInEpochs() {
|
|
231
|
+
return this.rollup.read.getLagInEpochs();
|
|
232
|
+
}
|
|
233
|
+
|
|
228
234
|
@memoize
|
|
229
235
|
getActivationThreshold() {
|
|
230
236
|
return this.rollup.read.getActivationThreshold();
|
|
@@ -436,8 +442,15 @@ export class RollupContract {
|
|
|
436
442
|
return this.rollup.read.getEntryQueueLength();
|
|
437
443
|
}
|
|
438
444
|
|
|
439
|
-
|
|
440
|
-
|
|
445
|
+
getNextFlushableEpoch() {
|
|
446
|
+
return this.rollup.read.getNextFlushableEpoch();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
getCurrentEpochNumber(): Promise<bigint> {
|
|
450
|
+
return this.rollup.read.getCurrentEpoch();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
getEpochNumberForBlock(blockNumber: bigint) {
|
|
441
454
|
return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
|
|
442
455
|
}
|
|
443
456
|
|
|
@@ -722,7 +735,9 @@ export class RollupContract {
|
|
|
722
735
|
});
|
|
723
736
|
}
|
|
724
737
|
|
|
725
|
-
public listenToSlasherChanged(
|
|
738
|
+
public listenToSlasherChanged(
|
|
739
|
+
callback: (args: { oldSlasher: `0x${string}`; newSlasher: `0x${string}` }) => unknown,
|
|
740
|
+
): WatchContractEventReturnType {
|
|
726
741
|
return this.rollup.watchEvent.SlasherUpdated(
|
|
727
742
|
{},
|
|
728
743
|
{
|
|
@@ -738,6 +753,22 @@ export class RollupContract {
|
|
|
738
753
|
);
|
|
739
754
|
}
|
|
740
755
|
|
|
756
|
+
public listenToBlockInvalidated(callback: (args: { blockNumber: bigint }) => unknown): WatchContractEventReturnType {
|
|
757
|
+
return this.rollup.watchEvent.BlockInvalidated(
|
|
758
|
+
{},
|
|
759
|
+
{
|
|
760
|
+
onLogs: logs => {
|
|
761
|
+
for (const log of logs) {
|
|
762
|
+
const args = log.args;
|
|
763
|
+
if (args.blockNumber !== undefined) {
|
|
764
|
+
callback({ blockNumber: args.blockNumber });
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
741
772
|
public async getSlashEvents(l1BlockHash: Hex): Promise<{ amount: bigint; attester: EthAddress }[]> {
|
|
742
773
|
const events = await this.rollup.getEvents.Slashed({}, { blockHash: l1BlockHash, strict: true });
|
|
743
774
|
return events.map(event => ({
|
|
@@ -746,7 +777,9 @@ export class RollupContract {
|
|
|
746
777
|
}));
|
|
747
778
|
}
|
|
748
779
|
|
|
749
|
-
public listenToSlash(
|
|
780
|
+
public listenToSlash(
|
|
781
|
+
callback: (args: { amount: bigint; attester: EthAddress }) => unknown,
|
|
782
|
+
): WatchContractEventReturnType {
|
|
750
783
|
return this.rollup.watchEvent.Slashed(
|
|
751
784
|
{},
|
|
752
785
|
{
|
|
@@ -5,6 +5,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
5
5
|
import type { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
7
7
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import { retryUntil } from '@aztec/foundation/retry';
|
|
8
9
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
10
|
import type { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
10
11
|
|
|
@@ -430,6 +431,7 @@ export const deployRollupForUpgrade = async (
|
|
|
430
431
|
registryAddress: EthAddress,
|
|
431
432
|
logger: Logger,
|
|
432
433
|
txUtilsConfig: L1TxUtilsConfig,
|
|
434
|
+
flushEntryQueue: boolean = true,
|
|
433
435
|
) => {
|
|
434
436
|
const deployer = new L1Deployer(
|
|
435
437
|
extendedClient,
|
|
@@ -442,7 +444,14 @@ export const deployRollupForUpgrade = async (
|
|
|
442
444
|
|
|
443
445
|
const addresses = await RegistryContract.collectAddresses(extendedClient, registryAddress, 'canonical');
|
|
444
446
|
|
|
445
|
-
const { rollup, slashFactoryAddress } = await deployRollup(
|
|
447
|
+
const { rollup, slashFactoryAddress } = await deployRollup(
|
|
448
|
+
extendedClient,
|
|
449
|
+
deployer,
|
|
450
|
+
args,
|
|
451
|
+
addresses,
|
|
452
|
+
flushEntryQueue,
|
|
453
|
+
logger,
|
|
454
|
+
);
|
|
446
455
|
|
|
447
456
|
await deployer.waitForDeployments();
|
|
448
457
|
|
|
@@ -501,6 +510,7 @@ export const deployRollup = async (
|
|
|
501
510
|
| 'gseAddress'
|
|
502
511
|
| 'governanceAddress'
|
|
503
512
|
>,
|
|
513
|
+
flushEntryQueue: boolean,
|
|
504
514
|
logger: Logger,
|
|
505
515
|
) => {
|
|
506
516
|
if (!addresses.gseAddress) {
|
|
@@ -530,6 +540,7 @@ export const deployRollup = async (
|
|
|
530
540
|
aztecSlotDuration: BigInt(args.aztecSlotDuration),
|
|
531
541
|
aztecEpochDuration: BigInt(args.aztecEpochDuration),
|
|
532
542
|
targetCommitteeSize: BigInt(args.aztecTargetCommitteeSize),
|
|
543
|
+
lagInEpochs: BigInt(args.lagInEpochs),
|
|
533
544
|
aztecProofSubmissionEpochs: BigInt(args.aztecProofSubmissionEpochs),
|
|
534
545
|
slashingQuorum: BigInt(args.slashingQuorum ?? (args.slashingRoundSizeInEpochs * args.aztecEpochDuration) / 2 + 1),
|
|
535
546
|
slashingRoundSize: BigInt(args.slashingRoundSizeInEpochs * args.aztecEpochDuration),
|
|
@@ -674,6 +685,7 @@ export const deployRollup = async (
|
|
|
674
685
|
addresses.stakingAssetAddress.toString(),
|
|
675
686
|
args.initialValidators,
|
|
676
687
|
args.acceleratedTestDeployments,
|
|
688
|
+
flushEntryQueue,
|
|
677
689
|
logger,
|
|
678
690
|
);
|
|
679
691
|
}
|
|
@@ -850,6 +862,7 @@ export const addMultipleValidators = async (
|
|
|
850
862
|
stakingAssetAddress: Hex,
|
|
851
863
|
validators: Operator[],
|
|
852
864
|
acceleratedTestDeployments: boolean | undefined,
|
|
865
|
+
flushEntryQueue: boolean,
|
|
853
866
|
logger: Logger,
|
|
854
867
|
) => {
|
|
855
868
|
const rollup = new RollupContract(extendedClient, rollupAddress);
|
|
@@ -916,7 +929,7 @@ export const addMultipleValidators = async (
|
|
|
916
929
|
data: encodeFunctionData({
|
|
917
930
|
abi: MultiAdderArtifact.contractAbi,
|
|
918
931
|
functionName: 'addValidators',
|
|
919
|
-
args: [validatorsTuples, true],
|
|
932
|
+
args: [validatorsTuples, /* skip flushing */ true],
|
|
920
933
|
}),
|
|
921
934
|
},
|
|
922
935
|
{
|
|
@@ -924,19 +937,49 @@ export const addMultipleValidators = async (
|
|
|
924
937
|
},
|
|
925
938
|
);
|
|
926
939
|
|
|
927
|
-
await
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
+
let queueLength = await rollup.getEntryQueueLength();
|
|
941
|
+
while (flushEntryQueue && queueLength > 0n) {
|
|
942
|
+
logger.info(`Flushing entry queue with ${queueLength} entries`);
|
|
943
|
+
|
|
944
|
+
try {
|
|
945
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
946
|
+
{
|
|
947
|
+
to: rollupAddress,
|
|
948
|
+
data: encodeFunctionData({
|
|
949
|
+
abi: RollupArtifact.contractAbi,
|
|
950
|
+
functionName: 'flushEntryQueue',
|
|
951
|
+
args: [],
|
|
952
|
+
}),
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
gasLimit: 20_000_000n,
|
|
956
|
+
},
|
|
957
|
+
);
|
|
958
|
+
} catch (err) {
|
|
959
|
+
logger.warn('Failed to flush queue', { err });
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
queueLength = await rollup.getEntryQueueLength();
|
|
963
|
+
// check if we drained the queue enough here so we can avoid sleep
|
|
964
|
+
if (queueLength === 0n) {
|
|
965
|
+
break;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
logger.info(`Waiting for next flushable epoch to flush remaining ${queueLength} entries`);
|
|
969
|
+
await retryUntil(
|
|
970
|
+
async () => {
|
|
971
|
+
const [currentEpoch, flushableEpoch] = await Promise.all([
|
|
972
|
+
rollup.getCurrentEpochNumber(),
|
|
973
|
+
rollup.getNextFlushableEpoch(),
|
|
974
|
+
]);
|
|
975
|
+
logger.debug(`Next flushable epoch is ${flushableEpoch} (current epoch is ${currentEpoch})`);
|
|
976
|
+
return currentEpoch >= flushableEpoch;
|
|
977
|
+
},
|
|
978
|
+
'wait for next flushable epoch',
|
|
979
|
+
3600,
|
|
980
|
+
12,
|
|
981
|
+
);
|
|
982
|
+
}
|
|
940
983
|
} else {
|
|
941
984
|
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
942
985
|
{
|
|
@@ -944,7 +987,7 @@ export const addMultipleValidators = async (
|
|
|
944
987
|
data: encodeFunctionData({
|
|
945
988
|
abi: MultiAdderArtifact.contractAbi,
|
|
946
989
|
functionName: 'addValidators',
|
|
947
|
-
args: [validatorsTuples,
|
|
990
|
+
args: [validatorsTuples, /* skip flushing */ !flushEntryQueue],
|
|
948
991
|
}),
|
|
949
992
|
},
|
|
950
993
|
{
|
|
@@ -1027,6 +1070,7 @@ export const deployL1Contracts = async (
|
|
|
1027
1070
|
args: DeployL1ContractsArgs,
|
|
1028
1071
|
txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(),
|
|
1029
1072
|
createVerificationJson: string | false = false,
|
|
1073
|
+
flushEntryQueue: boolean = true,
|
|
1030
1074
|
): Promise<DeployL1ContractsReturnType> => {
|
|
1031
1075
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1032
1076
|
validateConfig(args);
|
|
@@ -1093,6 +1137,7 @@ export const deployL1Contracts = async (
|
|
|
1093
1137
|
stakingAssetAddress,
|
|
1094
1138
|
governanceAddress,
|
|
1095
1139
|
},
|
|
1140
|
+
flushEntryQueue,
|
|
1096
1141
|
logger,
|
|
1097
1142
|
);
|
|
1098
1143
|
|
package/src/l1_tx_utils.ts
CHANGED
|
@@ -279,7 +279,13 @@ export class ReadOnlyL1TxUtils {
|
|
|
279
279
|
let blobBaseFee = 0n;
|
|
280
280
|
if (isBlobTx) {
|
|
281
281
|
try {
|
|
282
|
-
blobBaseFee = await
|
|
282
|
+
blobBaseFee = await retry<bigint>(
|
|
283
|
+
() => this.client.getBlobBaseFee(),
|
|
284
|
+
'Getting L1 blob base fee',
|
|
285
|
+
makeBackoff(times(2, () => 1)),
|
|
286
|
+
this.logger,
|
|
287
|
+
true,
|
|
288
|
+
);
|
|
283
289
|
this.logger?.debug('L1 Blob base fee:', { blobBaseFee: formatGwei(blobBaseFee) });
|
|
284
290
|
} catch {
|
|
285
291
|
this.logger?.warn('Failed to get L1 blob base fee', attempt);
|
|
@@ -864,7 +870,7 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
864
870
|
},
|
|
865
871
|
);
|
|
866
872
|
|
|
867
|
-
const txData = {
|
|
873
|
+
const txData: PrepareTransactionRequestRequest = {
|
|
868
874
|
...request,
|
|
869
875
|
...blobInputs,
|
|
870
876
|
nonce,
|
|
@@ -872,6 +878,9 @@ export class L1TxUtils extends ReadOnlyL1TxUtils {
|
|
|
872
878
|
maxFeePerGas: newGasPrice.maxFeePerGas,
|
|
873
879
|
maxPriorityFeePerGas: newGasPrice.maxPriorityFeePerGas,
|
|
874
880
|
};
|
|
881
|
+
if (isBlobTx && newGasPrice.maxFeePerBlobGas) {
|
|
882
|
+
(txData as any).maxFeePerBlobGas = newGasPrice.maxFeePerBlobGas;
|
|
883
|
+
}
|
|
875
884
|
const signedRequest = await this.prepareSignedTransaction(txData);
|
|
876
885
|
const newHash = await this.client.sendRawTransaction({ serializedTransaction: signedRequest });
|
|
877
886
|
if (!isCancelTx) {
|
package/src/queries.ts
CHANGED
|
@@ -33,6 +33,7 @@ export async function getL1ContractsConfig(
|
|
|
33
33
|
aztecSlotDuration,
|
|
34
34
|
aztecProofSubmissionEpochs,
|
|
35
35
|
aztecTargetCommitteeSize,
|
|
36
|
+
lagInEpochs,
|
|
36
37
|
activationThreshold,
|
|
37
38
|
ejectionThreshold,
|
|
38
39
|
localEjectionThreshold,
|
|
@@ -57,6 +58,7 @@ export async function getL1ContractsConfig(
|
|
|
57
58
|
rollup.getSlotDuration(),
|
|
58
59
|
rollup.getProofSubmissionEpochs(),
|
|
59
60
|
rollup.getTargetCommitteeSize(),
|
|
61
|
+
rollup.getLagInEpochs(),
|
|
60
62
|
rollup.getActivationThreshold(),
|
|
61
63
|
rollup.getEjectionThreshold(),
|
|
62
64
|
rollup.getLocalEjectionThreshold(),
|
|
@@ -83,6 +85,7 @@ export async function getL1ContractsConfig(
|
|
|
83
85
|
aztecSlotDuration: Number(aztecSlotDuration),
|
|
84
86
|
aztecProofSubmissionEpochs: Number(aztecProofSubmissionEpochs),
|
|
85
87
|
aztecTargetCommitteeSize: Number(aztecTargetCommitteeSize),
|
|
88
|
+
lagInEpochs: Number(lagInEpochs),
|
|
86
89
|
governanceProposerQuorum: Number(governanceProposerQuorum),
|
|
87
90
|
governanceProposerRoundSize: Number(governanceProposerRoundSize),
|
|
88
91
|
activationThreshold,
|
|
@@ -10,7 +10,7 @@ import type { ViemClient } from '../types.js';
|
|
|
10
10
|
|
|
11
11
|
export type ChainMonitorEventMap = {
|
|
12
12
|
'l1-block': [{ l1BlockNumber: number; timestamp: bigint }];
|
|
13
|
-
'l2-block': [{ l2BlockNumber: number; l1BlockNumber: number; timestamp: bigint }];
|
|
13
|
+
'l2-block': [{ l2BlockNumber: number; l1BlockNumber: number; l2SlotNumber: number; timestamp: bigint }];
|
|
14
14
|
'l2-block-proven': [{ l2ProvenBlockNumber: number; l1BlockNumber: number; timestamp: bigint }];
|
|
15
15
|
'l2-messages': [{ totalL2Messages: number; l1BlockNumber: number }];
|
|
16
16
|
'l2-epoch': [{ l2EpochNumber: number; timestamp: bigint; committee: EthAddress[] | undefined }];
|
|
@@ -102,8 +102,13 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
|
|
|
102
102
|
}
|
|
103
103
|
this.l1BlockNumber = newL1BlockNumber;
|
|
104
104
|
|
|
105
|
-
const
|
|
106
|
-
|
|
105
|
+
const [l2SlotNumber, l2Epoch, l1block] = await Promise.all([
|
|
106
|
+
this.rollup.getSlotNumber(),
|
|
107
|
+
this.rollup.getCurrentEpoch(),
|
|
108
|
+
this.l1Client.getBlock({ blockNumber: BigInt(newL1BlockNumber), includeTransactions: false }),
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
const timestamp = l1block.timestamp;
|
|
107
112
|
const timestampString = new Date(Number(timestamp) * 1000).toTimeString().split(' ')[0];
|
|
108
113
|
|
|
109
114
|
this.emit('l1-block', { l1BlockNumber: newL1BlockNumber, timestamp });
|
|
@@ -111,16 +116,21 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
|
|
|
111
116
|
|
|
112
117
|
const newL2BlockNumber = Number(await this.rollup.getBlockNumber());
|
|
113
118
|
if (this.l2BlockNumber !== newL2BlockNumber) {
|
|
114
|
-
const epochNumber = await this.rollup.
|
|
119
|
+
const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2BlockNumber));
|
|
115
120
|
msg += ` with new L2 block ${newL2BlockNumber} for epoch ${epochNumber}`;
|
|
116
121
|
this.l2BlockNumber = newL2BlockNumber;
|
|
117
122
|
this.l2BlockTimestamp = timestamp;
|
|
118
|
-
this.emit('l2-block', {
|
|
123
|
+
this.emit('l2-block', {
|
|
124
|
+
l2BlockNumber: newL2BlockNumber,
|
|
125
|
+
l1BlockNumber: newL1BlockNumber,
|
|
126
|
+
l2SlotNumber: Number(l2SlotNumber),
|
|
127
|
+
timestamp,
|
|
128
|
+
});
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
const newL2ProvenBlockNumber = Number(await this.rollup.getProvenBlockNumber());
|
|
122
132
|
if (this.l2ProvenBlockNumber !== newL2ProvenBlockNumber) {
|
|
123
|
-
const epochNumber = await this.rollup.
|
|
133
|
+
const epochNumber = await this.rollup.getEpochNumberForBlock(BigInt(newL2ProvenBlockNumber));
|
|
124
134
|
msg += ` with proof up to L2 block ${newL2ProvenBlockNumber} for epoch ${epochNumber}`;
|
|
125
135
|
this.l2ProvenBlockNumber = newL2ProvenBlockNumber;
|
|
126
136
|
this.l2ProvenBlockTimestamp = timestamp;
|
|
@@ -139,8 +149,6 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
|
|
|
139
149
|
this.emit('l2-messages', { totalL2Messages: newTotalL2Messages, l1BlockNumber: newL1BlockNumber });
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
const [l2SlotNumber, l2Epoch] = await Promise.all([this.rollup.getSlotNumber(), this.rollup.getCurrentEpoch()]);
|
|
143
|
-
|
|
144
152
|
let committee: EthAddress[] | undefined;
|
|
145
153
|
if (l2Epoch !== this.l2EpochNumber) {
|
|
146
154
|
this.l2EpochNumber = l2Epoch;
|
|
@@ -184,4 +192,52 @@ export class ChainMonitor extends EventEmitter<ChainMonitorEventMap> {
|
|
|
184
192
|
this.on('l2-slot', listener);
|
|
185
193
|
});
|
|
186
194
|
}
|
|
195
|
+
|
|
196
|
+
public waitUntilL1Block(block: number | bigint): Promise<void> {
|
|
197
|
+
const targetBlock = typeof block === 'bigint' ? block.valueOf() : block;
|
|
198
|
+
if (this.l1BlockNumber >= targetBlock) {
|
|
199
|
+
return Promise.resolve();
|
|
200
|
+
}
|
|
201
|
+
return new Promise(resolve => {
|
|
202
|
+
const listener = (data: { l1BlockNumber: number; timestamp: bigint }) => {
|
|
203
|
+
if (data.l1BlockNumber >= targetBlock) {
|
|
204
|
+
this.off('l1-block', listener);
|
|
205
|
+
resolve();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
this.on('l1-block', listener);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
public waitUntilL1Timestamp(timestamp: number | bigint): Promise<void> {
|
|
213
|
+
const targetTimestamp = typeof timestamp === 'bigint' ? timestamp.valueOf() : timestamp;
|
|
214
|
+
if (this.l1BlockNumber >= targetTimestamp) {
|
|
215
|
+
return Promise.resolve();
|
|
216
|
+
}
|
|
217
|
+
return new Promise(resolve => {
|
|
218
|
+
const listener = (data: { l1BlockNumber: number; timestamp: bigint }) => {
|
|
219
|
+
if (data.timestamp >= targetTimestamp) {
|
|
220
|
+
this.off('l1-block', listener);
|
|
221
|
+
resolve();
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
this.on('l1-block', listener);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public waitUntilL2Block(l2BlockNumber: number | bigint): Promise<void> {
|
|
229
|
+
const targetBlock = typeof l2BlockNumber === 'bigint' ? l2BlockNumber.valueOf() : l2BlockNumber;
|
|
230
|
+
if (this.l2BlockNumber >= targetBlock) {
|
|
231
|
+
return Promise.resolve();
|
|
232
|
+
}
|
|
233
|
+
return new Promise(resolve => {
|
|
234
|
+
const listener = (data: { l2BlockNumber: number; timestamp: bigint }) => {
|
|
235
|
+
if (data.l2BlockNumber >= targetBlock) {
|
|
236
|
+
this.off('l2-block', listener);
|
|
237
|
+
resolve();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
this.on('l2-block', listener);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
187
243
|
}
|