@aztec/sequencer-client 0.71.0 → 0.73.0

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.
Files changed (66) hide show
  1. package/dest/client/sequencer-client.d.ts +11 -6
  2. package/dest/client/sequencer-client.d.ts.map +1 -1
  3. package/dest/client/sequencer-client.js +41 -10
  4. package/dest/config.d.ts +1 -1
  5. package/dest/config.d.ts.map +1 -1
  6. package/dest/config.js +3 -4
  7. package/dest/publisher/config.d.ts +5 -0
  8. package/dest/publisher/config.d.ts.map +1 -1
  9. package/dest/publisher/config.js +9 -2
  10. package/dest/publisher/index.d.ts +1 -1
  11. package/dest/publisher/index.d.ts.map +1 -1
  12. package/dest/publisher/index.js +2 -2
  13. package/dest/publisher/{l1-publisher-metrics.d.ts → sequencer-publisher-metrics.d.ts} +6 -2
  14. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -0
  15. package/dest/publisher/sequencer-publisher-metrics.js +111 -0
  16. package/dest/publisher/sequencer-publisher.d.ts +158 -0
  17. package/dest/publisher/sequencer-publisher.d.ts.map +1 -0
  18. package/dest/publisher/sequencer-publisher.js +555 -0
  19. package/dest/sequencer/allowed.d.ts +1 -1
  20. package/dest/sequencer/allowed.d.ts.map +1 -1
  21. package/dest/sequencer/allowed.js +6 -6
  22. package/dest/sequencer/metrics.d.ts +1 -1
  23. package/dest/sequencer/metrics.d.ts.map +1 -1
  24. package/dest/sequencer/metrics.js +3 -4
  25. package/dest/sequencer/sequencer.d.ts +18 -12
  26. package/dest/sequencer/sequencer.d.ts.map +1 -1
  27. package/dest/sequencer/sequencer.js +118 -125
  28. package/dest/sequencer/utils.d.ts +1 -1
  29. package/dest/sequencer/utils.d.ts.map +1 -1
  30. package/dest/sequencer/utils.js +3 -3
  31. package/dest/slasher/slasher_client.d.ts.map +1 -1
  32. package/dest/slasher/slasher_client.js +6 -3
  33. package/dest/test/index.d.ts +3 -3
  34. package/dest/test/index.d.ts.map +1 -1
  35. package/dest/test/index.js +1 -2
  36. package/dest/tx_validator/gas_validator.d.ts +1 -1
  37. package/dest/tx_validator/gas_validator.d.ts.map +1 -1
  38. package/dest/tx_validator/gas_validator.js +10 -5
  39. package/dest/tx_validator/test_utils.d.ts +4 -4
  40. package/dest/tx_validator/test_utils.d.ts.map +1 -1
  41. package/dest/tx_validator/test_utils.js +3 -3
  42. package/package.json +22 -21
  43. package/src/client/sequencer-client.ts +60 -14
  44. package/src/config.ts +3 -3
  45. package/src/publisher/config.ts +13 -1
  46. package/src/publisher/index.ts +1 -1
  47. package/src/publisher/{l1-publisher-metrics.ts → sequencer-publisher-metrics.ts} +41 -2
  48. package/src/publisher/sequencer-publisher.ts +730 -0
  49. package/src/sequencer/allowed.ts +5 -5
  50. package/src/sequencer/metrics.ts +2 -3
  51. package/src/sequencer/sequencer.ts +153 -150
  52. package/src/sequencer/utils.ts +5 -2
  53. package/src/slasher/slasher_client.ts +7 -2
  54. package/src/test/index.ts +2 -4
  55. package/src/tx_validator/gas_validator.ts +17 -4
  56. package/src/tx_validator/test_utils.ts +5 -5
  57. package/dest/publisher/l1-publisher-metrics.d.ts.map +0 -1
  58. package/dest/publisher/l1-publisher-metrics.js +0 -85
  59. package/dest/publisher/l1-publisher.d.ts +0 -195
  60. package/dest/publisher/l1-publisher.d.ts.map +0 -1
  61. package/dest/publisher/l1-publisher.js +0 -864
  62. package/dest/test/test-l1-publisher.d.ts +0 -9
  63. package/dest/test/test-l1-publisher.d.ts.map +0 -1
  64. package/dest/test/test-l1-publisher.js +0 -11
  65. package/src/publisher/l1-publisher.ts +0 -1208
  66. package/src/test/test-l1-publisher.ts +0 -20
@@ -1,864 +0,0 @@
1
- var _a;
2
- import { createBlobSinkClient } from '@aztec/blob-sink/client';
3
- import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload, } from '@aztec/circuit-types';
4
- import { AGGREGATION_OBJECT_LENGTH, AZTEC_MAX_EPOCH_DURATION, EthAddress, } from '@aztec/circuits.js';
5
- import { L1TxUtils, createEthereumChain, formatViemError, } from '@aztec/ethereum';
6
- import { makeTuple } from '@aztec/foundation/array';
7
- import { toHex } from '@aztec/foundation/bigint-buffer';
8
- import { Blob } from '@aztec/foundation/blob';
9
- import { areArraysEqual, compactArray, times } from '@aztec/foundation/collection';
10
- import { Fr } from '@aztec/foundation/fields';
11
- import { createLogger } from '@aztec/foundation/log';
12
- import { serializeToBuffer } from '@aztec/foundation/serialize';
13
- import { InterruptibleSleep } from '@aztec/foundation/sleep';
14
- import { Timer } from '@aztec/foundation/timer';
15
- import { EmpireBaseAbi, RollupAbi, SlasherAbi } from '@aztec/l1-artifacts';
16
- import { getTelemetryClient } from '@aztec/telemetry-client';
17
- import pick from 'lodash.pick';
18
- import { ContractFunctionRevertedError, createPublicClient, createWalletClient, encodeFunctionData, getAbiItem, getAddress, getContract, getContractError, hexToBytes, http, publicActions, } from 'viem';
19
- import { privateKeyToAccount } from 'viem/accounts';
20
- import { L1PublisherMetrics } from './l1-publisher-metrics.js';
21
- export var VoteType;
22
- (function (VoteType) {
23
- VoteType[VoteType["GOVERNANCE"] = 0] = "GOVERNANCE";
24
- VoteType[VoteType["SLASHING"] = 1] = "SLASHING";
25
- })(VoteType || (VoteType = {}));
26
- /**
27
- * Publishes L2 blocks to L1. This implementation does *not* retry a transaction in
28
- * the event of network congestion, but should work for local development.
29
- * - If sending (not mining) a tx fails, it retries indefinitely at 1-minute intervals.
30
- * - If the tx is not mined, keeps polling indefinitely at 1-second intervals.
31
- *
32
- * Adapted from https://github.com/AztecProtocol/aztec2-internal/blob/master/falafel/src/rollup_publisher.ts.
33
- */
34
- export class L1Publisher {
35
- constructor(config, deps = {}) {
36
- this.interruptibleSleep = new InterruptibleSleep();
37
- this.interrupted = false;
38
- this.governanceLog = createLogger('sequencer:publisher:governance');
39
- this.governancePayload = EthAddress.ZERO;
40
- this.slashingLog = createLogger('sequencer:publisher:slashing');
41
- this.getSlashPayload = undefined;
42
- this.myLastVotes = {
43
- [VoteType.GOVERNANCE]: 0n,
44
- [VoteType.SLASHING]: 0n,
45
- };
46
- this.log = createLogger('sequencer:publisher');
47
- this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60000;
48
- this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
49
- const telemetry = deps.telemetry ?? getTelemetryClient();
50
- this.blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config.blobSinkUrl);
51
- this.metrics = new L1PublisherMetrics(telemetry, 'L1Publisher');
52
- const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey, l1Contracts } = config;
53
- const chain = createEthereumChain(rpcUrl, chainId);
54
- this.account = privateKeyToAccount(publisherPrivateKey);
55
- this.log.debug(`Publishing from address ${this.account.address}`);
56
- this.walletClient = this.createWalletClient(this.account, chain);
57
- this.publicClient = createPublicClient({
58
- chain: chain.chainInfo,
59
- transport: http(chain.rpcUrl),
60
- pollingInterval: config.viemPollingIntervalMS,
61
- });
62
- this.rollupContract = getContract({
63
- address: getAddress(l1Contracts.rollupAddress.toString()),
64
- abi: RollupAbi,
65
- client: this.walletClient,
66
- });
67
- if (l1Contracts.governanceProposerAddress) {
68
- this.governanceProposerAddress = EthAddress.fromString(l1Contracts.governanceProposerAddress.toString());
69
- }
70
- this.l1TxUtils = new L1TxUtils(this.publicClient, this.walletClient, this.log, config);
71
- }
72
- registerSlashPayloadGetter(callback) {
73
- this.getSlashPayload = callback;
74
- }
75
- async getSlashingProposerAddress() {
76
- if (this.slashingProposerAddress) {
77
- return this.slashingProposerAddress;
78
- }
79
- const slasherAddress = await this.rollupContract.read.SLASHER();
80
- const slasher = getContract({
81
- address: getAddress(slasherAddress.toString()),
82
- abi: SlasherAbi,
83
- client: this.walletClient,
84
- });
85
- this.slashingProposerAddress = EthAddress.fromString(await slasher.read.PROPOSER());
86
- return this.slashingProposerAddress;
87
- }
88
- get publisherAddress() {
89
- return this.account.address;
90
- }
91
- createWalletClient(account, chain) {
92
- return createWalletClient({
93
- account,
94
- chain: chain.chainInfo,
95
- transport: http(chain.rpcUrl),
96
- });
97
- }
98
- getGovernancePayload() {
99
- return this.governancePayload;
100
- }
101
- setGovernancePayload(payload) {
102
- this.governancePayload = payload;
103
- }
104
- getSenderAddress() {
105
- return EthAddress.fromString(this.account.address);
106
- }
107
- getClient() {
108
- return this.walletClient.extend(publicActions);
109
- }
110
- getRollupContract() {
111
- return this.rollupContract;
112
- }
113
- /**
114
- * @notice Calls `canProposeAtTime` with the time of the next Ethereum block and the sender address
115
- *
116
- * @dev Throws if unable to propose
117
- *
118
- * @param archive - The archive that we expect to be current state
119
- * @return slot - The L2 slot number of the next Ethereum block,
120
- * @return blockNumber - The L2 block number of the next L2 block
121
- */
122
- async canProposeAtNextEthBlock(archive) {
123
- // FIXME: This should not throw if unable to propose but return a falsey value, so
124
- // we can differentiate between errors when hitting the L1 rollup contract (eg RPC error)
125
- // which may require a retry, vs actually not being the turn for proposing.
126
- const timeOfNextL1Slot = BigInt((await this.publicClient.getBlock()).timestamp + this.ethereumSlotDuration);
127
- const [slot, blockNumber] = await this.rollupContract.read.canProposeAtTime([
128
- timeOfNextL1Slot,
129
- `0x${archive.toString('hex')}`,
130
- ]);
131
- return [slot, blockNumber];
132
- }
133
- async getClaimableEpoch() {
134
- try {
135
- return await this.rollupContract.read.getClaimableEpoch();
136
- }
137
- catch (err) {
138
- const errorName = tryGetCustomErrorName(err);
139
- // getting the error name from the abi is redundant,
140
- // but it enforces that the error name is correct.
141
- // That is, if the error name is not found, this will not compile.
142
- const acceptedErrors = ['Rollup__NoEpochToProve', 'Rollup__ProofRightAlreadyClaimed'].map(name => getAbiItem({ abi: RollupAbi, name }).name);
143
- if (errorName && acceptedErrors.includes(errorName)) {
144
- return undefined;
145
- }
146
- throw err;
147
- }
148
- }
149
- async getEpochForSlotNumber(slotNumber) {
150
- return await this.rollupContract.read.getEpochAtSlot([slotNumber]);
151
- }
152
- async getEpochToProve() {
153
- try {
154
- return await this.rollupContract.read.getEpochToProve();
155
- }
156
- catch (err) {
157
- // If this is a revert with Rollup__NoEpochToProve, it means there is no epoch to prove, so we return undefined
158
- // See https://viem.sh/docs/contract/simulateContract#handling-custom-errors
159
- const errorName = tryGetCustomErrorName(err);
160
- if (errorName === getAbiItem({ abi: RollupAbi, name: 'Rollup__NoEpochToProve' }).name) {
161
- return undefined;
162
- }
163
- throw err;
164
- }
165
- }
166
- async getProofClaim() {
167
- const { epochToProve, basisPointFee, bondAmount, bondProvider: bondProviderHex, proposerClaimant: proposerClaimantHex, } = await this.rollupContract.read.getProofClaim();
168
- const bondProvider = EthAddress.fromString(bondProviderHex);
169
- const proposerClaimant = EthAddress.fromString(proposerClaimantHex);
170
- if (bondProvider.isZero() && proposerClaimant.isZero() && epochToProve === 0n) {
171
- return undefined;
172
- }
173
- return {
174
- epochToProve,
175
- basisPointFee,
176
- bondAmount,
177
- bondProvider,
178
- proposerClaimant,
179
- };
180
- }
181
- async validateProofQuote(quote) {
182
- const timeOfNextL1Slot = BigInt((await this.publicClient.getBlock()).timestamp + this.ethereumSlotDuration);
183
- const args = [timeOfNextL1Slot, quote.toViemArgs()];
184
- try {
185
- await this.rollupContract.read.validateEpochProofRightClaimAtTime(args, { account: this.account });
186
- }
187
- catch (err) {
188
- let errorName = tryGetCustomErrorName(err);
189
- if (!errorName) {
190
- errorName = tryGetCustomErrorNameContractFunction(err);
191
- }
192
- this.log.warn(`Proof quote validation failed: ${errorName}`, quote);
193
- return undefined;
194
- }
195
- return quote;
196
- }
197
- /**
198
- * @notice Will call `validateHeader` to make sure that it is possible to propose
199
- *
200
- * @dev Throws if unable to propose
201
- *
202
- * @param header - The header to propose
203
- * @param digest - The digest that attestations are signing over
204
- *
205
- */
206
- async validateBlockForSubmission(header, attestationData = {
207
- digest: Buffer.alloc(32),
208
- signatures: [],
209
- }) {
210
- const ts = BigInt((await this.publicClient.getBlock()).timestamp + this.ethereumSlotDuration);
211
- const formattedSignatures = attestationData.signatures.map(attest => attest.toViemSignature());
212
- const flags = { ignoreDA: true, ignoreSignatures: formattedSignatures.length == 0 };
213
- const args = [
214
- `0x${header.toBuffer().toString('hex')}`,
215
- formattedSignatures,
216
- `0x${attestationData.digest.toString('hex')}`,
217
- ts,
218
- `0x${header.contentCommitment.blobsHash.toString('hex')}`,
219
- flags,
220
- ];
221
- try {
222
- await this.rollupContract.read.validateHeader(args, { account: this.account });
223
- }
224
- catch (error) {
225
- // Specify the type of error
226
- if (error instanceof ContractFunctionRevertedError) {
227
- const err = error;
228
- this.log.debug(`Validation failed: ${err.message}`, err.data);
229
- }
230
- throw error;
231
- }
232
- }
233
- async getCurrentEpochCommittee() {
234
- const committee = await this.rollupContract.read.getCurrentEpochCommittee();
235
- return committee.map(EthAddress.fromString);
236
- }
237
- async getTransactionStats(txHash) {
238
- const tx = await this.publicClient.getTransaction({ hash: txHash });
239
- if (!tx) {
240
- return undefined;
241
- }
242
- const calldata = hexToBytes(tx.input);
243
- return {
244
- sender: tx.from.toString(),
245
- transactionHash: tx.hash,
246
- calldataSize: calldata.length,
247
- calldataGas: getCalldataGasUsage(calldata),
248
- };
249
- }
250
- async castVote(slotNumber, timestamp, voteType) {
251
- // @todo This function can be optimized by doing some of the computations locally instead of calling the L1 contracts
252
- if (this.myLastVotes[voteType] >= slotNumber) {
253
- return false;
254
- }
255
- const voteConfig = async () => {
256
- if (voteType === VoteType.GOVERNANCE) {
257
- if (this.governancePayload.equals(EthAddress.ZERO)) {
258
- return undefined;
259
- }
260
- if (!this.governanceProposerAddress) {
261
- return undefined;
262
- }
263
- return {
264
- payload: this.governancePayload,
265
- voteContractAddress: this.governanceProposerAddress,
266
- logger: this.governanceLog,
267
- };
268
- }
269
- else if (voteType === VoteType.SLASHING) {
270
- if (!this.getSlashPayload) {
271
- return undefined;
272
- }
273
- const slashingProposerAddress = await this.getSlashingProposerAddress();
274
- if (!slashingProposerAddress) {
275
- return undefined;
276
- }
277
- const slashPayload = await this.getSlashPayload(slotNumber);
278
- if (!slashPayload) {
279
- return undefined;
280
- }
281
- return {
282
- payload: slashPayload,
283
- voteContractAddress: slashingProposerAddress,
284
- logger: this.slashingLog,
285
- };
286
- }
287
- else {
288
- throw new Error('Invalid vote type');
289
- }
290
- };
291
- const vConfig = await voteConfig();
292
- if (!vConfig) {
293
- return false;
294
- }
295
- const { payload, voteContractAddress, logger } = vConfig;
296
- const voteContract = getContract({
297
- address: getAddress(voteContractAddress.toString()),
298
- abi: EmpireBaseAbi,
299
- client: this.walletClient,
300
- });
301
- const [proposer, roundNumber] = await Promise.all([
302
- this.rollupContract.read.getProposerAt([timestamp]),
303
- voteContract.read.computeRound([slotNumber]),
304
- ]);
305
- if (proposer.toLowerCase() !== this.account.address.toLowerCase()) {
306
- return false;
307
- }
308
- const [slotForLastVote] = await voteContract.read.rounds([this.rollupContract.address, roundNumber]);
309
- if (slotForLastVote >= slotNumber) {
310
- return false;
311
- }
312
- const cachedMyLastVote = this.myLastVotes[voteType];
313
- this.myLastVotes[voteType] = slotNumber;
314
- let txHash;
315
- try {
316
- txHash = await voteContract.write.vote([payload.toString()], {
317
- account: this.account,
318
- });
319
- }
320
- catch (err) {
321
- const msg = formatViemError(err);
322
- logger.error(`Failed to vote`, msg);
323
- this.myLastVotes[voteType] = cachedMyLastVote;
324
- return false;
325
- }
326
- if (txHash) {
327
- const receipt = await this.getTransactionReceipt(txHash);
328
- if (!receipt) {
329
- logger.warn(`Failed to get receipt for tx ${txHash}`);
330
- this.myLastVotes[voteType] = cachedMyLastVote;
331
- return false;
332
- }
333
- }
334
- logger.info(`Cast vote for ${payload}`);
335
- return true;
336
- }
337
- /**
338
- * Proposes a L2 block on L1.
339
- * @param block - L2 block to propose.
340
- * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise.
341
- */
342
- async proposeL2Block(block, attestations, txHashes, proofQuote, opts = {}) {
343
- const ctx = {
344
- blockNumber: block.number,
345
- slotNumber: block.header.globalVariables.slotNumber.toBigInt(),
346
- blockHash: block.hash().toString(),
347
- };
348
- const consensusPayload = new ConsensusPayload(block.header, block.archive.root, txHashes ?? []);
349
- const digest = getHashedSignaturePayload(consensusPayload, SignatureDomainSeparator.blockAttestation);
350
- const blobs = Blob.getBlobs(block.body.toBlobFields());
351
- const proposeTxArgs = {
352
- header: block.header.toBuffer(),
353
- archive: block.archive.root.toBuffer(),
354
- blockHash: block.header.hash().toBuffer(),
355
- body: block.body.toBuffer(),
356
- blobs,
357
- attestations,
358
- txHashes: txHashes ?? [],
359
- };
360
- // Publish body and propose block (if not already published)
361
- if (this.interrupted) {
362
- this.log.verbose('L2 block data syncing interrupted while processing blocks.', ctx);
363
- return false;
364
- }
365
- const timer = new Timer();
366
- // @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available
367
- // This means that we can avoid the simulation issues in later checks.
368
- // By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
369
- // make time consistency checks break.
370
- await this.validateBlockForSubmission(block.header, {
371
- digest: digest.toBuffer(),
372
- signatures: attestations ?? [],
373
- });
374
- this.log.debug(`Submitting propose transaction`);
375
- const result = proofQuote
376
- ? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote, opts)
377
- : await this.sendProposeTx(proposeTxArgs, opts);
378
- if (!result?.receipt) {
379
- this.log.info(`Failed to publish block ${block.number} to L1`, ctx);
380
- return false;
381
- }
382
- const { receipt, args, functionName, data, gasPrice } = result;
383
- // Tx was mined successfully
384
- if (receipt.status === 'success') {
385
- const tx = await this.getTransactionStats(receipt.transactionHash);
386
- const stats = {
387
- gasPrice: receipt.effectiveGasPrice,
388
- gasUsed: receipt.gasUsed,
389
- blobGasUsed: receipt.blobGasUsed ?? 0n,
390
- blobDataGas: receipt.blobGasPrice ?? 0n,
391
- transactionHash: receipt.transactionHash,
392
- ...pick(tx, 'calldataGas', 'calldataSize', 'sender'),
393
- ...block.getStats(),
394
- eventName: 'rollup-published-to-l1',
395
- };
396
- this.log.verbose(`Published L2 block to L1 rollup contract`, { ...stats, ...ctx });
397
- this.metrics.recordProcessBlockTx(timer.ms(), stats);
398
- // Send the blobs to the blob sink
399
- this.sendBlobsToBlobSink(receipt.blockHash, blobs).catch(_err => {
400
- this.log.error('Failed to send blobs to blob sink');
401
- });
402
- return true;
403
- }
404
- this.metrics.recordFailedTx('process');
405
- const kzg = Blob.getViemKzgInstance();
406
- const errorMsg = await this.tryGetErrorFromRevertedTx(data, {
407
- args,
408
- functionName,
409
- abi: RollupAbi,
410
- address: this.rollupContract.address,
411
- }, {
412
- blobs: proposeTxArgs.blobs.map(b => b.dataWithZeros),
413
- kzg,
414
- maxFeePerBlobGas: gasPrice.maxFeePerBlobGas ?? 10000000000n,
415
- });
416
- this.log.error(`Rollup process tx reverted. ${errorMsg}`, undefined, {
417
- ...ctx,
418
- txHash: receipt.transactionHash,
419
- });
420
- await this.sleepOrInterrupted();
421
- return false;
422
- }
423
- /** Calls claimEpochProofRight in the Rollup contract to submit a chosen prover quote for the previous epoch. */
424
- async claimEpochProofRight(proofQuote) {
425
- const timer = new Timer();
426
- let result;
427
- try {
428
- this.log.debug(`Submitting claimEpochProofRight transaction`);
429
- result = await this.l1TxUtils.sendAndMonitorTransaction({
430
- to: this.rollupContract.address,
431
- data: encodeFunctionData({
432
- abi: RollupAbi,
433
- functionName: 'claimEpochProofRight',
434
- args: [proofQuote.toViemArgs()],
435
- }),
436
- });
437
- }
438
- catch (err) {
439
- this.log.error(`Failed to claim epoch proof right`, err, {
440
- proofQuote: proofQuote.toInspect(),
441
- });
442
- return false;
443
- }
444
- const { receipt } = result;
445
- if (receipt.status === 'success') {
446
- const tx = await this.getTransactionStats(receipt.transactionHash);
447
- const stats = {
448
- gasPrice: receipt.effectiveGasPrice,
449
- gasUsed: receipt.gasUsed,
450
- transactionHash: receipt.transactionHash,
451
- blobDataGas: 0n,
452
- blobGasUsed: 0n,
453
- ...pick(tx, 'calldataGas', 'calldataSize', 'sender'),
454
- };
455
- this.log.verbose(`Submitted claim epoch proof right to L1 rollup contract`, {
456
- ...stats,
457
- ...proofQuote.toInspect(),
458
- });
459
- this.metrics.recordClaimEpochProofRightTx(timer.ms(), stats);
460
- return true;
461
- }
462
- else {
463
- this.metrics.recordFailedTx('claimEpochProofRight');
464
- // TODO: Get the error message from the reverted tx
465
- this.log.error(`Claim epoch proof right tx reverted`, {
466
- txHash: receipt.transactionHash,
467
- ...proofQuote.toInspect(),
468
- });
469
- return false;
470
- }
471
- }
472
- async tryGetErrorFromRevertedTx(data, args, _blobInputs) {
473
- const blobInputs = _blobInputs || {};
474
- try {
475
- // NB: If this fn starts unexpectedly giving incorrect blob hash errors, it may be because the checkBlob
476
- // bool is no longer at the slot below. To find the slot, run: forge inspect src/core/Rollup.sol:Rollup storage
477
- const checkBlobSlot = 9n;
478
- await this.publicClient.simulateContract({
479
- ...args,
480
- account: this.walletClient.account,
481
- stateOverride: [
482
- {
483
- address: args.address,
484
- stateDiff: [
485
- {
486
- slot: toHex(checkBlobSlot, true),
487
- value: toHex(0n, true),
488
- },
489
- ],
490
- },
491
- ],
492
- });
493
- // If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors.
494
- // Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
495
- // See: https://github.com/wevm/viem/issues/2075
496
- // This throws a EstimateGasExecutionError with the custom error information:
497
- await this.walletClient.prepareTransactionRequest({
498
- account: this.walletClient.account,
499
- to: this.rollupContract.address,
500
- data,
501
- ...blobInputs,
502
- });
503
- return undefined;
504
- }
505
- catch (simulationErr) {
506
- // If we don't have a ContractFunctionExecutionError, we have a blob related error => use getContractError to get the error msg.
507
- const contractErr = simulationErr.name === 'ContractFunctionExecutionError'
508
- ? simulationErr
509
- : getContractError(simulationErr, {
510
- args: [],
511
- abi: RollupAbi,
512
- functionName: args.functionName,
513
- address: args.address,
514
- sender: this.account.address,
515
- });
516
- if (contractErr.name === 'ContractFunctionExecutionError') {
517
- const execErr = contractErr;
518
- return tryGetCustomErrorNameContractFunction(execErr);
519
- }
520
- this.log.error(`Error getting error from simulation`, simulationErr);
521
- }
522
- }
523
- async submitEpochProof(args) {
524
- const { epochNumber, fromBlock, toBlock } = args;
525
- const ctx = { epochNumber, fromBlock, toBlock };
526
- if (!this.interrupted) {
527
- const timer = new Timer();
528
- // Validate epoch proof range and hashes are correct before submitting
529
- await this.validateEpochProofSubmission(args);
530
- const txHash = await this.sendSubmitEpochProofTx(args);
531
- if (!txHash) {
532
- return false;
533
- }
534
- const receipt = await this.getTransactionReceipt(txHash);
535
- if (!receipt) {
536
- return false;
537
- }
538
- // Tx was mined successfully
539
- if (receipt.status) {
540
- const tx = await this.getTransactionStats(txHash);
541
- const stats = {
542
- ...pick(receipt, 'gasPrice', 'gasUsed', 'transactionHash'),
543
- ...pick(tx, 'calldataGas', 'calldataSize', 'sender'),
544
- blobDataGas: 0n,
545
- blobGasUsed: 0n,
546
- eventName: 'proof-published-to-l1',
547
- };
548
- this.log.info(`Published epoch proof to L1 rollup contract`, { ...stats, ...ctx });
549
- this.metrics.recordSubmitProof(timer.ms(), stats);
550
- return true;
551
- }
552
- this.metrics.recordFailedTx('submitProof');
553
- this.log.error(`Rollup.submitEpochProof tx status failed: ${receipt.transactionHash}`, ctx);
554
- await this.sleepOrInterrupted();
555
- }
556
- this.log.verbose('L2 block data syncing interrupted while processing blocks.', ctx);
557
- return false;
558
- }
559
- async validateEpochProofSubmission(args) {
560
- const { fromBlock, toBlock, publicInputs, proof } = args;
561
- // Check that the block numbers match the expected epoch to be proven
562
- const { pendingBlockNumber: pending, provenBlockNumber: proven } = await this.rollupContract.read.getTips();
563
- if (proven !== BigInt(fromBlock) - 1n) {
564
- throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as proven block is ${proven}`);
565
- }
566
- if (toBlock > pending) {
567
- throw new Error(`Cannot submit epoch proof for ${fromBlock}-${toBlock} as pending block is ${pending}`);
568
- }
569
- // Check the block hash and archive for the immediate block before the epoch
570
- const blockLog = await this.rollupContract.read.getBlock([proven]);
571
- if (publicInputs.previousArchive.root.toString() !== blockLog.archive) {
572
- throw new Error(`Previous archive root mismatch: ${publicInputs.previousArchive.root.toString()} !== ${blockLog.archive}`);
573
- }
574
- // TODO: Remove zero check once we inject the proper zero blockhash
575
- if (blockLog.blockHash !== Fr.ZERO.toString() && publicInputs.previousBlockHash.toString() !== blockLog.blockHash) {
576
- throw new Error(`Previous block hash mismatch: ${publicInputs.previousBlockHash.toString()} !== ${blockLog.blockHash}`);
577
- }
578
- // Check the block hash and archive for the last block in the epoch
579
- const endBlockLog = await this.rollupContract.read.getBlock([BigInt(toBlock)]);
580
- if (publicInputs.endArchive.root.toString() !== endBlockLog.archive) {
581
- throw new Error(`End archive root mismatch: ${publicInputs.endArchive.root.toString()} !== ${endBlockLog.archive}`);
582
- }
583
- if (publicInputs.endBlockHash.toString() !== endBlockLog.blockHash) {
584
- throw new Error(`End block hash mismatch: ${publicInputs.endBlockHash.toString()} !== ${endBlockLog.blockHash}`);
585
- }
586
- // Compare the public inputs computed by the contract with the ones injected
587
- const rollupPublicInputs = await this.rollupContract.read.getEpochProofPublicInputs(this.getSubmitEpochProofArgs(args));
588
- const aggregationObject = proof.isEmpty()
589
- ? times(AGGREGATION_OBJECT_LENGTH, Fr.zero)
590
- : proof.extractAggregationObject();
591
- const argsPublicInputs = [...publicInputs.toFields(), ...aggregationObject];
592
- if (!areArraysEqual(rollupPublicInputs.map(Fr.fromHexString), argsPublicInputs, (a, b) => a.equals(b))) {
593
- const fmt = (inputs) => inputs.map(x => x.toString()).join(', ');
594
- throw new Error(`Root rollup public inputs mismatch:\nRollup: ${fmt(rollupPublicInputs)}\nComputed:${fmt(argsPublicInputs)}`);
595
- }
596
- }
597
- /**
598
- * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
599
- * Be warned, the call may return false even if the tx subsequently gets successfully mined.
600
- * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
601
- * A call to `restart` is required before you can continue publishing.
602
- */
603
- interrupt() {
604
- this.interrupted = true;
605
- this.interruptibleSleep.interrupt();
606
- }
607
- /** Restarts the publisher after calling `interrupt`. */
608
- restart() {
609
- this.interrupted = false;
610
- }
611
- async sendSubmitEpochProofTx(args) {
612
- const proofHex = `0x${args.proof.withoutPublicInputs().toString('hex')}`;
613
- const argsArray = this.getSubmitEpochProofArgs(args);
614
- const txArgs = [
615
- {
616
- epochSize: argsArray[0],
617
- args: argsArray[1],
618
- fees: argsArray[2],
619
- blobPublicInputs: argsArray[3],
620
- aggregationObject: argsArray[4],
621
- proof: proofHex,
622
- },
623
- ];
624
- this.log.info(`SubmitEpochProof proofSize=${args.proof.withoutPublicInputs().length} bytes`);
625
- const data = encodeFunctionData({
626
- abi: this.rollupContract.abi,
627
- functionName: 'submitEpochRootProof',
628
- args: txArgs,
629
- });
630
- try {
631
- const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({
632
- to: this.rollupContract.address,
633
- data,
634
- });
635
- return receipt.transactionHash;
636
- }
637
- catch (err) {
638
- this.log.error(`Rollup submit epoch proof failed`, err);
639
- const errorMsg = await this.tryGetErrorFromRevertedTx(data, {
640
- args: [...txArgs],
641
- functionName: 'submitEpochRootProof',
642
- abi: this.rollupContract.abi,
643
- address: this.rollupContract.address,
644
- });
645
- this.log.error(`Rollup submit epoch proof tx reverted. ${errorMsg}`);
646
- return undefined;
647
- }
648
- }
649
- async prepareProposeTx(encodedData) {
650
- const kzg = Blob.getViemKzgInstance();
651
- const blobEvaluationGas = await this.l1TxUtils.estimateGas(this.account, {
652
- to: this.rollupContract.address,
653
- data: encodeFunctionData({
654
- abi: this.rollupContract.abi,
655
- functionName: 'validateBlobs',
656
- args: [Blob.getEthBlobEvaluationInputs(encodedData.blobs)],
657
- }),
658
- }, {}, {
659
- blobs: encodedData.blobs.map(b => b.dataWithZeros),
660
- kzg,
661
- });
662
- // @note We perform this guesstimate instead of the usual `gasEstimate` since
663
- // viem will use the current state to simulate against, which means that
664
- // we will fail estimation in the case where we are simulating for the
665
- // first ethereum block within our slot (as current time is not in the
666
- // slot yet).
667
- const gasGuesstimate = blobEvaluationGas + _a.PROPOSE_GAS_GUESS;
668
- const attestations = encodedData.attestations
669
- ? encodedData.attestations.map(attest => attest.toViemSignature())
670
- : [];
671
- const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.toString()) : [];
672
- const args = [
673
- {
674
- header: `0x${encodedData.header.toString('hex')}`,
675
- archive: `0x${encodedData.archive.toString('hex')}`,
676
- oracleInput: {
677
- // We are currently not modifying these. See #9963
678
- feeAssetPriceModifier: 0n,
679
- provingCostModifier: 0n,
680
- },
681
- blockHash: `0x${encodedData.blockHash.toString('hex')}`,
682
- txHashes,
683
- },
684
- attestations,
685
- // TODO(#9101): Extract blobs from beacon chain => calldata will only contain what's needed to verify blob and body input can be removed
686
- `0x${encodedData.body.toString('hex')}`,
687
- Blob.getEthBlobEvaluationInputs(encodedData.blobs),
688
- ];
689
- return { args, gas: gasGuesstimate };
690
- }
691
- getSubmitEpochProofArgs(args) {
692
- return [
693
- BigInt(args.toBlock - args.fromBlock + 1),
694
- [
695
- args.publicInputs.previousArchive.root.toString(),
696
- args.publicInputs.endArchive.root.toString(),
697
- args.publicInputs.previousBlockHash.toString(),
698
- args.publicInputs.endBlockHash.toString(),
699
- args.publicInputs.endTimestamp.toString(),
700
- args.publicInputs.outHash.toString(),
701
- args.publicInputs.proverId.toString(),
702
- ],
703
- makeTuple(AZTEC_MAX_EPOCH_DURATION * 2, i => i % 2 === 0
704
- ? args.publicInputs.fees[i / 2].recipient.toField().toString()
705
- : args.publicInputs.fees[(i - 1) / 2].value.toString()),
706
- `0x${args.publicInputs.blobPublicInputs
707
- .filter((_, i) => i < args.toBlock - args.fromBlock + 1)
708
- .map(b => b.toString())
709
- .join(``)}`,
710
- `0x${serializeToBuffer(args.proof.extractAggregationObject()).toString('hex')}`,
711
- ];
712
- }
713
- async sendProposeTx(encodedData, opts = {}) {
714
- if (this.interrupted) {
715
- return undefined;
716
- }
717
- try {
718
- const kzg = Blob.getViemKzgInstance();
719
- const { args, gas } = await this.prepareProposeTx(encodedData);
720
- const data = encodeFunctionData({
721
- abi: this.rollupContract.abi,
722
- functionName: 'propose',
723
- args,
724
- });
725
- const result = await this.l1TxUtils.sendAndMonitorTransaction({
726
- to: this.rollupContract.address,
727
- data,
728
- }, {
729
- fixedGas: gas,
730
- ...opts,
731
- }, {
732
- blobs: encodedData.blobs.map(b => b.dataWithZeros),
733
- kzg,
734
- });
735
- return {
736
- receipt: result.receipt,
737
- gasPrice: result.gasPrice,
738
- args,
739
- functionName: 'propose',
740
- data,
741
- };
742
- }
743
- catch (err) {
744
- this.log.error(`Rollup publish failed.`, err);
745
- return undefined;
746
- }
747
- }
748
- async sendProposeAndClaimTx(encodedData, quote, opts = {}) {
749
- if (this.interrupted) {
750
- return undefined;
751
- }
752
- try {
753
- const kzg = Blob.getViemKzgInstance();
754
- const { args, gas } = await this.prepareProposeTx(encodedData);
755
- const data = encodeFunctionData({
756
- abi: this.rollupContract.abi,
757
- functionName: 'proposeAndClaim',
758
- args: [...args, quote.toViemArgs()],
759
- });
760
- const result = await this.l1TxUtils.sendAndMonitorTransaction({
761
- to: this.rollupContract.address,
762
- data,
763
- }, {
764
- fixedGas: gas,
765
- ...opts,
766
- }, {
767
- blobs: encodedData.blobs.map(b => b.dataWithZeros),
768
- kzg,
769
- });
770
- return {
771
- receipt: result.receipt,
772
- gasPrice: result.gasPrice,
773
- args: [...args, quote.toViemArgs()],
774
- functionName: 'proposeAndClaim',
775
- data,
776
- };
777
- }
778
- catch (err) {
779
- this.log.error(`Rollup publish failed.`, err);
780
- return undefined;
781
- }
782
- }
783
- /**
784
- * Returns a tx receipt if the tx has been mined.
785
- * @param txHash - Hash of the tx to look for.
786
- * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise.
787
- */
788
- async getTransactionReceipt(txHash) {
789
- while (!this.interrupted) {
790
- try {
791
- const receipt = await this.publicClient.getTransactionReceipt({
792
- hash: txHash,
793
- });
794
- if (receipt) {
795
- if (receipt.transactionHash !== txHash) {
796
- throw new Error(`Tx hash mismatch: ${receipt.transactionHash} !== ${txHash}`);
797
- }
798
- return {
799
- status: receipt.status === 'success',
800
- transactionHash: txHash,
801
- gasUsed: receipt.gasUsed,
802
- gasPrice: receipt.effectiveGasPrice,
803
- logs: receipt.logs,
804
- blockNumber: receipt.blockNumber,
805
- blockHash: receipt.blockHash,
806
- };
807
- }
808
- this.log.debug(`Receipt not found for tx hash ${txHash}`);
809
- return undefined;
810
- }
811
- catch (err) {
812
- //this.log.error(`Error getting tx receipt`, err);
813
- await this.sleepOrInterrupted();
814
- }
815
- }
816
- }
817
- async sleepOrInterrupted() {
818
- await this.interruptibleSleep.sleep(this.sleepTimeMs);
819
- }
820
- /**
821
- * Send blobs to the blob sink
822
- *
823
- * If a blob sink url is configured, then we send blobs to the blob sink
824
- * - for now we use the blockHash as the identifier for the blobs;
825
- * In the future this will move to be the beacon block id - which takes a bit more work
826
- * to calculate and will need to be mocked in e2e tests
827
- */
828
- sendBlobsToBlobSink(blockHash, blobs) {
829
- return this.blobSinkClient.sendBlobsToBlobSink(blockHash, blobs);
830
- }
831
- }
832
- _a = L1Publisher;
833
- // @note - with blobs, the below estimate seems too large.
834
- // Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
835
- // Total used for emptier block from above test: 429k (of which 84k is 1x blob)
836
- L1Publisher.PROPOSE_GAS_GUESS = 12000000n;
837
- L1Publisher.PROPOSE_AND_CLAIM_GAS_GUESS = _a.PROPOSE_GAS_GUESS + 100000n;
838
- /*
839
- * Returns cost of calldata usage in Ethereum.
840
- * @param data - Calldata.
841
- * @returns 4 for each zero byte, 16 for each nonzero.
842
- */
843
- function getCalldataGasUsage(data) {
844
- return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16;
845
- }
846
- function tryGetCustomErrorNameContractFunction(err) {
847
- return compactArray([err.shortMessage, ...(err.metaMessages ?? []).slice(0, 2).map(s => s.trim())]).join(' ');
848
- }
849
- function tryGetCustomErrorName(err) {
850
- try {
851
- // See https://viem.sh/docs/contract/simulateContract#handling-custom-errors
852
- if (err.name === 'ViemError' || err.name === 'ContractFunctionExecutionError') {
853
- const baseError = err;
854
- const revertError = baseError.walk(err => err.name === 'ContractFunctionRevertedError');
855
- if (revertError) {
856
- return revertError.data?.errorName;
857
- }
858
- }
859
- }
860
- catch (_e) {
861
- return undefined;
862
- }
863
- }
864
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibDEtcHVibGlzaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3B1Ymxpc2hlci9sMS1wdWJsaXNoZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBZ0Msb0JBQW9CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RixPQUFPLEVBQ0wsZ0JBQWdCLEVBSWhCLHdCQUF3QixFQUV4Qix5QkFBeUIsR0FDMUIsTUFBTSxzQkFBc0IsQ0FBQztBQUU5QixPQUFPLEVBQ0wseUJBQXlCLEVBQ3pCLHdCQUF3QixFQUV4QixVQUFVLEdBRVgsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QixPQUFPLEVBSUwsU0FBUyxFQUNULG1CQUFtQixFQUNuQixlQUFlLEdBQ2hCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFbkYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlDLE9BQU8sRUFBZSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRSxPQUFPLEVBQWMsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0UsT0FBTyxFQUF3QixrQkFBa0IsRUFBRSxNQUFNLHlCQUF5QixDQUFD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