@aztec/ethereum 3.0.0-nightly.20250911 → 3.0.0-nightly.20250913
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 +6 -0
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +15 -3
- 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/contracts/slasher_contract.d.ts +10 -0
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/slasher_contract.js +18 -0
- 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 +47 -20
- package/dest/l1_artifacts.d.ts +3539 -3003
- 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 +6 -2
- 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 +18 -2
- package/src/contracts/rollup.ts +37 -4
- package/src/contracts/slasher_contract.ts +22 -0
- package/src/deploy_l1_contracts.ts +62 -16
- package/src/l1_tx_utils.ts +11 -2
- package/src/queries.ts +7 -1
- 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.20250913",
|
|
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.20250913",
|
|
35
|
+
"@aztec/constants": "3.0.0-nightly.20250913",
|
|
36
|
+
"@aztec/foundation": "3.0.0-nightly.20250913",
|
|
37
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20250913",
|
|
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 */
|
|
@@ -48,6 +50,8 @@ export type L1ContractsConfig = {
|
|
|
48
50
|
slashingVetoer: EthAddress;
|
|
49
51
|
/** How many slashing rounds back we slash (ie when slashing in round N, we slash for offenses committed during epochs of round N-offset) */
|
|
50
52
|
slashingOffsetInRounds: number;
|
|
53
|
+
/** How long slashing can be disabled for in seconds when vetoer disables it */
|
|
54
|
+
slashingDisableDuration: number;
|
|
51
55
|
/** Type of slasher proposer */
|
|
52
56
|
slasherFlavor: 'empire' | 'tally' | 'none';
|
|
53
57
|
/** Minimum amount that can be slashed in tally slashing */
|
|
@@ -73,6 +77,7 @@ export const DefaultL1ContractsConfig = {
|
|
|
73
77
|
aztecSlotDuration: 36,
|
|
74
78
|
aztecEpochDuration: 32,
|
|
75
79
|
aztecTargetCommitteeSize: 48,
|
|
80
|
+
lagInEpochs: 2,
|
|
76
81
|
aztecProofSubmissionEpochs: 1, // you have a full epoch to submit a proof after the epoch to prove ends
|
|
77
82
|
activationThreshold: BigInt(100e18),
|
|
78
83
|
ejectionThreshold: BigInt(50e18),
|
|
@@ -90,6 +95,7 @@ export const DefaultL1ContractsConfig = {
|
|
|
90
95
|
exitDelaySeconds: 2 * 24 * 60 * 60,
|
|
91
96
|
slasherFlavor: 'tally' as const,
|
|
92
97
|
slashingOffsetInRounds: 2,
|
|
98
|
+
slashingDisableDuration: 5 * 24 * 60 * 60, // 5 days in seconds
|
|
93
99
|
} satisfies L1ContractsConfig;
|
|
94
100
|
|
|
95
101
|
const LocalGovernanceConfiguration = {
|
|
@@ -303,6 +309,11 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
303
309
|
description: 'The target validator committee size.',
|
|
304
310
|
...numberConfigHelper(DefaultL1ContractsConfig.aztecTargetCommitteeSize),
|
|
305
311
|
},
|
|
312
|
+
lagInEpochs: {
|
|
313
|
+
env: 'AZTEC_LAG_IN_EPOCHS',
|
|
314
|
+
description: 'The number of epochs to lag behind the current epoch for validator selection.',
|
|
315
|
+
...numberConfigHelper(DefaultL1ContractsConfig.lagInEpochs),
|
|
316
|
+
},
|
|
306
317
|
aztecProofSubmissionEpochs: {
|
|
307
318
|
env: 'AZTEC_PROOF_SUBMISSION_EPOCHS',
|
|
308
319
|
description: 'The number of epochs after an epoch ends that proofs are still accepted.',
|
|
@@ -376,6 +387,11 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
376
387
|
parseEnv: (val: string) => EthAddress.fromString(val),
|
|
377
388
|
defaultValue: DefaultL1ContractsConfig.slashingVetoer,
|
|
378
389
|
},
|
|
390
|
+
slashingDisableDuration: {
|
|
391
|
+
env: 'AZTEC_SLASHING_DISABLE_DURATION',
|
|
392
|
+
description: 'How long slashing can be disabled for in seconds when vetoer disables it',
|
|
393
|
+
...numberConfigHelper(DefaultL1ContractsConfig.slashingDisableDuration),
|
|
394
|
+
},
|
|
379
395
|
governanceProposerQuorum: {
|
|
380
396
|
env: 'AZTEC_GOVERNANCE_PROPOSER_QUORUM',
|
|
381
397
|
description: 'The governance proposing quorum',
|
|
@@ -449,7 +465,7 @@ export function validateConfig(config: Omit<L1ContractsConfig, keyof L1TxUtilsCo
|
|
|
449
465
|
}
|
|
450
466
|
|
|
451
467
|
// EmpireBase constructor validations for governance/slashing proposers
|
|
452
|
-
// From: require(QUORUM_SIZE > ROUND_SIZE / 2, Errors.
|
|
468
|
+
// From: require(QUORUM_SIZE > ROUND_SIZE / 2, Errors.EmpireBase__InvalidQuorumAndRoundSize(QUORUM_SIZE, ROUND_SIZE));
|
|
453
469
|
const { governanceProposerQuorum, governanceProposerRoundSize } = config;
|
|
454
470
|
if (
|
|
455
471
|
governanceProposerQuorum !== undefined &&
|
|
@@ -460,7 +476,7 @@ export function validateConfig(config: Omit<L1ContractsConfig, keyof L1TxUtilsCo
|
|
|
460
476
|
);
|
|
461
477
|
}
|
|
462
478
|
|
|
463
|
-
// From: require(QUORUM_SIZE <= ROUND_SIZE, Errors.
|
|
479
|
+
// From: require(QUORUM_SIZE <= ROUND_SIZE, Errors.EmpireBase__QuorumCannotBeLargerThanRoundSize(QUORUM_SIZE, ROUND_SIZE));
|
|
464
480
|
if (governanceProposerQuorum !== undefined && governanceProposerQuorum > governanceProposerRoundSize) {
|
|
465
481
|
errors.push(
|
|
466
482
|
`governanceProposerQuorum (${governanceProposerQuorum}) cannot be larger than governanceProposerRoundSize (${governanceProposerRoundSize})`,
|
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
|
{
|
|
@@ -38,6 +38,19 @@ export class SlasherContract {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Checks if slashing is currently enabled. Slashing can be disabled by the vetoer.
|
|
43
|
+
* @returns True if slashing is enabled, false otherwise
|
|
44
|
+
*/
|
|
45
|
+
public async isSlashingEnabled(): Promise<boolean> {
|
|
46
|
+
try {
|
|
47
|
+
return await this.contract.read.isSlashingEnabled();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
this.log.error(`Error checking if slashing is enabled`, error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
/**
|
|
42
55
|
* Gets the current vetoer address.
|
|
43
56
|
* @returns The vetoer address
|
|
@@ -47,6 +60,15 @@ export class SlasherContract {
|
|
|
47
60
|
return EthAddress.fromString(vetoer);
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Gets the disable duration by the vetoer.
|
|
65
|
+
* @returns The disable duration in seconds
|
|
66
|
+
*/
|
|
67
|
+
public async getSlashingDisableDuration(): Promise<number> {
|
|
68
|
+
const duration = await this.contract.read.SLASHING_DISABLE_DURATION();
|
|
69
|
+
return Number(duration);
|
|
70
|
+
}
|
|
71
|
+
|
|
50
72
|
/**
|
|
51
73
|
* Gets the current governance address.
|
|
52
74
|
* @returns The governance address
|
|
@@ -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),
|
|
@@ -547,6 +558,7 @@ export const deployRollup = async (
|
|
|
547
558
|
slashingOffsetInRounds: BigInt(args.slashingOffsetInRounds),
|
|
548
559
|
slashAmounts: [args.slashAmountSmall, args.slashAmountMedium, args.slashAmountLarge],
|
|
549
560
|
localEjectionThreshold: args.localEjectionThreshold,
|
|
561
|
+
slashingDisableDuration: BigInt(args.slashingDisableDuration ?? 0n),
|
|
550
562
|
};
|
|
551
563
|
|
|
552
564
|
const genesisStateArgs = {
|
|
@@ -674,6 +686,7 @@ export const deployRollup = async (
|
|
|
674
686
|
addresses.stakingAssetAddress.toString(),
|
|
675
687
|
args.initialValidators,
|
|
676
688
|
args.acceleratedTestDeployments,
|
|
689
|
+
flushEntryQueue,
|
|
677
690
|
logger,
|
|
678
691
|
);
|
|
679
692
|
}
|
|
@@ -850,6 +863,7 @@ export const addMultipleValidators = async (
|
|
|
850
863
|
stakingAssetAddress: Hex,
|
|
851
864
|
validators: Operator[],
|
|
852
865
|
acceleratedTestDeployments: boolean | undefined,
|
|
866
|
+
flushEntryQueue: boolean,
|
|
853
867
|
logger: Logger,
|
|
854
868
|
) => {
|
|
855
869
|
const rollup = new RollupContract(extendedClient, rollupAddress);
|
|
@@ -916,7 +930,7 @@ export const addMultipleValidators = async (
|
|
|
916
930
|
data: encodeFunctionData({
|
|
917
931
|
abi: MultiAdderArtifact.contractAbi,
|
|
918
932
|
functionName: 'addValidators',
|
|
919
|
-
args: [validatorsTuples, true],
|
|
933
|
+
args: [validatorsTuples, /* skip flushing */ true],
|
|
920
934
|
}),
|
|
921
935
|
},
|
|
922
936
|
{
|
|
@@ -924,19 +938,49 @@ export const addMultipleValidators = async (
|
|
|
924
938
|
},
|
|
925
939
|
);
|
|
926
940
|
|
|
927
|
-
await
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
941
|
+
let queueLength = await rollup.getEntryQueueLength();
|
|
942
|
+
while (flushEntryQueue && queueLength > 0n) {
|
|
943
|
+
logger.info(`Flushing entry queue with ${queueLength} entries`);
|
|
944
|
+
|
|
945
|
+
try {
|
|
946
|
+
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
947
|
+
{
|
|
948
|
+
to: rollupAddress,
|
|
949
|
+
data: encodeFunctionData({
|
|
950
|
+
abi: RollupArtifact.contractAbi,
|
|
951
|
+
functionName: 'flushEntryQueue',
|
|
952
|
+
args: [],
|
|
953
|
+
}),
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
gasLimit: 20_000_000n,
|
|
957
|
+
},
|
|
958
|
+
);
|
|
959
|
+
} catch (err) {
|
|
960
|
+
logger.warn('Failed to flush queue', { err });
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
queueLength = await rollup.getEntryQueueLength();
|
|
964
|
+
// check if we drained the queue enough here so we can avoid sleep
|
|
965
|
+
if (queueLength === 0n) {
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
logger.info(`Waiting for next flushable epoch to flush remaining ${queueLength} entries`);
|
|
970
|
+
await retryUntil(
|
|
971
|
+
async () => {
|
|
972
|
+
const [currentEpoch, flushableEpoch] = await Promise.all([
|
|
973
|
+
rollup.getCurrentEpochNumber(),
|
|
974
|
+
rollup.getNextFlushableEpoch(),
|
|
975
|
+
]);
|
|
976
|
+
logger.debug(`Next flushable epoch is ${flushableEpoch} (current epoch is ${currentEpoch})`);
|
|
977
|
+
return currentEpoch >= flushableEpoch;
|
|
978
|
+
},
|
|
979
|
+
'wait for next flushable epoch',
|
|
980
|
+
3600,
|
|
981
|
+
12,
|
|
982
|
+
);
|
|
983
|
+
}
|
|
940
984
|
} else {
|
|
941
985
|
await deployer.l1TxUtils.sendAndMonitorTransaction(
|
|
942
986
|
{
|
|
@@ -944,7 +988,7 @@ export const addMultipleValidators = async (
|
|
|
944
988
|
data: encodeFunctionData({
|
|
945
989
|
abi: MultiAdderArtifact.contractAbi,
|
|
946
990
|
functionName: 'addValidators',
|
|
947
|
-
args: [validatorsTuples,
|
|
991
|
+
args: [validatorsTuples, /* skip flushing */ !flushEntryQueue],
|
|
948
992
|
}),
|
|
949
993
|
},
|
|
950
994
|
{
|
|
@@ -1027,6 +1071,7 @@ export const deployL1Contracts = async (
|
|
|
1027
1071
|
args: DeployL1ContractsArgs,
|
|
1028
1072
|
txUtilsConfig: L1TxUtilsConfig = getL1TxUtilsConfigEnvVars(),
|
|
1029
1073
|
createVerificationJson: string | false = false,
|
|
1074
|
+
flushEntryQueue: boolean = true,
|
|
1030
1075
|
): Promise<DeployL1ContractsReturnType> => {
|
|
1031
1076
|
logger.info(`Deploying L1 contracts with config: ${jsonStringify(args)}`);
|
|
1032
1077
|
validateConfig(args);
|
|
@@ -1093,6 +1138,7 @@ export const deployL1Contracts = async (
|
|
|
1093
1138
|
stakingAssetAddress,
|
|
1094
1139
|
governanceAddress,
|
|
1095
1140
|
},
|
|
1141
|
+
flushEntryQueue,
|
|
1096
1142
|
logger,
|
|
1097
1143
|
);
|
|
1098
1144
|
|
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,
|
|
@@ -45,6 +46,7 @@ export async function getL1ContractsConfig(
|
|
|
45
46
|
slashingOffsetInRounds,
|
|
46
47
|
slashingAmounts,
|
|
47
48
|
slashingVetoer,
|
|
49
|
+
slashingDisableDuration,
|
|
48
50
|
manaTarget,
|
|
49
51
|
provingCostPerMana,
|
|
50
52
|
rollupVersion,
|
|
@@ -57,6 +59,7 @@ export async function getL1ContractsConfig(
|
|
|
57
59
|
rollup.getSlotDuration(),
|
|
58
60
|
rollup.getProofSubmissionEpochs(),
|
|
59
61
|
rollup.getTargetCommitteeSize(),
|
|
62
|
+
rollup.getLagInEpochs(),
|
|
60
63
|
rollup.getActivationThreshold(),
|
|
61
64
|
rollup.getEjectionThreshold(),
|
|
62
65
|
rollup.getLocalEjectionThreshold(),
|
|
@@ -69,6 +72,7 @@ export async function getL1ContractsConfig(
|
|
|
69
72
|
slasherProposer?.type === 'tally' ? slasherProposer.getSlashOffsetInRounds() : 0n,
|
|
70
73
|
slasherProposer?.type === 'tally' ? slasherProposer.getSlashingAmounts() : [0n, 0n, 0n],
|
|
71
74
|
slasher?.getVetoer() ?? EthAddress.ZERO,
|
|
75
|
+
slasher?.getSlashingDisableDuration() ?? 0,
|
|
72
76
|
rollup.getManaTarget(),
|
|
73
77
|
rollup.getProvingCostPerMana(),
|
|
74
78
|
rollup.getVersion(),
|
|
@@ -83,6 +87,7 @@ export async function getL1ContractsConfig(
|
|
|
83
87
|
aztecSlotDuration: Number(aztecSlotDuration),
|
|
84
88
|
aztecProofSubmissionEpochs: Number(aztecProofSubmissionEpochs),
|
|
85
89
|
aztecTargetCommitteeSize: Number(aztecTargetCommitteeSize),
|
|
90
|
+
lagInEpochs: Number(lagInEpochs),
|
|
86
91
|
governanceProposerQuorum: Number(governanceProposerQuorum),
|
|
87
92
|
governanceProposerRoundSize: Number(governanceProposerRoundSize),
|
|
88
93
|
activationThreshold,
|
|
@@ -93,7 +98,8 @@ export async function getL1ContractsConfig(
|
|
|
93
98
|
slashingLifetimeInRounds: Number(slashingLifetimeInRounds),
|
|
94
99
|
slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds),
|
|
95
100
|
slashingVetoer,
|
|
96
|
-
|
|
101
|
+
slashingDisableDuration,
|
|
102
|
+
manaTarget,
|
|
97
103
|
provingCostPerMana: provingCostPerMana,
|
|
98
104
|
rollupVersion: Number(rollupVersion),
|
|
99
105
|
genesisArchiveTreeRoot,
|