@aztec/sequencer-client 0.74.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2

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 (85) hide show
  1. package/dest/client/index.js +0 -1
  2. package/dest/client/sequencer-client.js +52 -57
  3. package/dest/config.js +40 -42
  4. package/dest/global_variable_builder/global_builder.js +39 -26
  5. package/dest/global_variable_builder/index.js +0 -1
  6. package/dest/index.js +0 -1
  7. package/dest/publisher/config.js +49 -50
  8. package/dest/publisher/index.js +0 -1
  9. package/dest/publisher/sequencer-publisher-metrics.js +32 -23
  10. package/dest/publisher/sequencer-publisher.js +216 -191
  11. package/dest/sequencer/allowed.js +5 -12
  12. package/dest/sequencer/config.js +1 -2
  13. package/dest/sequencer/index.js +0 -1
  14. package/dest/sequencer/metrics.js +26 -18
  15. package/dest/sequencer/sequencer.js +648 -607
  16. package/dest/sequencer/timetable.js +33 -19
  17. package/dest/sequencer/utils.js +22 -32
  18. package/dest/slasher/factory.js +5 -4
  19. package/dest/slasher/index.js +0 -1
  20. package/dest/slasher/slasher_client.js +107 -110
  21. package/dest/test/index.js +4 -1
  22. package/dest/tx_validator/archive_cache.js +7 -7
  23. package/dest/tx_validator/gas_validator.js +76 -64
  24. package/dest/tx_validator/nullifier_cache.js +8 -8
  25. package/dest/tx_validator/phases_validator.js +27 -19
  26. package/dest/tx_validator/test_utils.js +1 -2
  27. package/dest/tx_validator/tx_validator_factory.js +5 -5
  28. package/package.json +23 -22
  29. package/src/config.ts +1 -1
  30. package/src/publisher/sequencer-publisher.ts +1 -1
  31. package/src/sequencer/sequencer.ts +29 -13
  32. package/dest/client/index.d.ts +0 -2
  33. package/dest/client/index.d.ts.map +0 -1
  34. package/dest/client/sequencer-client.d.ts +0 -68
  35. package/dest/client/sequencer-client.d.ts.map +0 -1
  36. package/dest/config.d.ts +0 -37
  37. package/dest/config.d.ts.map +0 -1
  38. package/dest/global_variable_builder/global_builder.d.ts +0 -29
  39. package/dest/global_variable_builder/global_builder.d.ts.map +0 -1
  40. package/dest/global_variable_builder/index.d.ts +0 -2
  41. package/dest/global_variable_builder/index.d.ts.map +0 -1
  42. package/dest/index.d.ts +0 -8
  43. package/dest/index.d.ts.map +0 -1
  44. package/dest/publisher/config.d.ts +0 -38
  45. package/dest/publisher/config.d.ts.map +0 -1
  46. package/dest/publisher/index.d.ts +0 -2
  47. package/dest/publisher/index.d.ts.map +0 -1
  48. package/dest/publisher/sequencer-publisher-metrics.d.ts +0 -24
  49. package/dest/publisher/sequencer-publisher-metrics.d.ts.map +0 -1
  50. package/dest/publisher/sequencer-publisher.d.ts +0 -163
  51. package/dest/publisher/sequencer-publisher.d.ts.map +0 -1
  52. package/dest/sequencer/allowed.d.ts +0 -3
  53. package/dest/sequencer/allowed.d.ts.map +0 -1
  54. package/dest/sequencer/config.d.ts +0 -2
  55. package/dest/sequencer/config.d.ts.map +0 -1
  56. package/dest/sequencer/index.d.ts +0 -4
  57. package/dest/sequencer/index.d.ts.map +0 -1
  58. package/dest/sequencer/metrics.d.ts +0 -24
  59. package/dest/sequencer/metrics.d.ts.map +0 -1
  60. package/dest/sequencer/sequencer.d.ts +0 -172
  61. package/dest/sequencer/sequencer.d.ts.map +0 -1
  62. package/dest/sequencer/timetable.d.ts +0 -38
  63. package/dest/sequencer/timetable.d.ts.map +0 -1
  64. package/dest/sequencer/utils.d.ts +0 -47
  65. package/dest/sequencer/utils.d.ts.map +0 -1
  66. package/dest/slasher/factory.d.ts +0 -11
  67. package/dest/slasher/factory.d.ts.map +0 -1
  68. package/dest/slasher/index.d.ts +0 -3
  69. package/dest/slasher/index.d.ts.map +0 -1
  70. package/dest/slasher/slasher_client.d.ts +0 -127
  71. package/dest/slasher/slasher_client.d.ts.map +0 -1
  72. package/dest/test/index.d.ts +0 -17
  73. package/dest/test/index.d.ts.map +0 -1
  74. package/dest/tx_validator/archive_cache.d.ts +0 -14
  75. package/dest/tx_validator/archive_cache.d.ts.map +0 -1
  76. package/dest/tx_validator/gas_validator.d.ts +0 -12
  77. package/dest/tx_validator/gas_validator.d.ts.map +0 -1
  78. package/dest/tx_validator/nullifier_cache.d.ts +0 -16
  79. package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
  80. package/dest/tx_validator/phases_validator.d.ts +0 -11
  81. package/dest/tx_validator/phases_validator.d.ts.map +0 -1
  82. package/dest/tx_validator/test_utils.d.ts +0 -21
  83. package/dest/tx_validator/test_utils.d.ts.map +0 -1
  84. package/dest/tx_validator/tx_validator_factory.d.ts +0 -16
  85. package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
@@ -1,10 +1,9 @@
1
- var _a;
1
+ import { Blob } from '@aztec/blob-lib';
2
2
  import { createBlobSinkClient } from '@aztec/blob-sink/client';
3
- import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload, } from '@aztec/circuit-types';
3
+ import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/circuit-types';
4
4
  import { EthAddress } from '@aztec/circuits.js';
5
- import { FormattedViemError, RollupContract, formatViemError, } from '@aztec/ethereum';
5
+ import { FormattedViemError, RollupContract, formatViemError } from '@aztec/ethereum';
6
6
  import { toHex } from '@aztec/foundation/bigint-buffer';
7
- import { Blob } from '@aztec/foundation/blob';
8
7
  import { createLogger } from '@aztec/foundation/log';
9
8
  import { Timer } from '@aztec/foundation/timer';
10
9
  import { ForwarderAbi, RollupAbi } from '@aztec/l1-artifacts';
@@ -12,24 +11,40 @@ import { getTelemetryClient } from '@aztec/telemetry-client';
12
11
  import pick from 'lodash.pick';
13
12
  import { encodeFunctionData } from 'viem';
14
13
  import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
15
- export var VoteType;
16
- (function (VoteType) {
14
+ export var VoteType = /*#__PURE__*/ function(VoteType) {
17
15
  VoteType[VoteType["GOVERNANCE"] = 0] = "GOVERNANCE";
18
16
  VoteType[VoteType["SLASHING"] = 1] = "SLASHING";
19
- })(VoteType || (VoteType = {}));
17
+ return VoteType;
18
+ }({});
20
19
  export class SequencerPublisher {
21
- constructor(config, deps) {
22
- this.interrupted = false;
23
- this.governanceLog = createLogger('sequencer:publisher:governance');
24
- this.governancePayload = EthAddress.ZERO;
25
- this.slashingLog = createLogger('sequencer:publisher:slashing');
26
- this.getSlashPayload = undefined;
27
- this.myLastVotes = {
28
- [VoteType.GOVERNANCE]: 0n,
29
- [VoteType.SLASHING]: 0n,
30
- };
31
- this.log = createLogger('sequencer:publisher');
32
- this.requests = [];
20
+ interrupted = false;
21
+ metrics;
22
+ epochCache;
23
+ forwarderContract;
24
+ governanceLog = createLogger('sequencer:publisher:governance');
25
+ governanceProposerAddress;
26
+ governancePayload = EthAddress.ZERO;
27
+ slashingLog = createLogger('sequencer:publisher:slashing');
28
+ slashingProposerAddress;
29
+ getSlashPayload = undefined;
30
+ myLastVotes = {
31
+ [0]: 0n,
32
+ [1]: 0n
33
+ };
34
+ log = createLogger('sequencer:publisher');
35
+ ethereumSlotDuration;
36
+ blobSinkClient;
37
+ // @note - with blobs, the below estimate seems too large.
38
+ // Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
39
+ // Total used for emptier block from above test: 429k (of which 84k is 1x blob)
40
+ static PROPOSE_GAS_GUESS = 12_000_000n;
41
+ static PROPOSE_AND_CLAIM_GAS_GUESS = this.PROPOSE_GAS_GUESS + 100_000n;
42
+ l1TxUtils;
43
+ rollupContract;
44
+ govProposerContract;
45
+ slashingProposerContract;
46
+ requests = [];
47
+ constructor(config, deps){
33
48
  this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
34
49
  this.epochCache = deps.epochCache;
35
50
  this.blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config);
@@ -63,31 +78,32 @@ export class SequencerPublisher {
63
78
  return this.epochCache.getEpochAndSlotNow().slot;
64
79
  }
65
80
  /**
66
- * Sends all requests that are still valid.
67
- * @returns one of:
68
- * - A receipt and stats if the tx succeeded
69
- * - a receipt and errorMsg if it failed on L1
70
- * - undefined if no valid requests are found OR the tx failed to send.
71
- */
72
- async sendRequests() {
73
- const requestsToProcess = [...this.requests];
81
+ * Sends all requests that are still valid.
82
+ * @returns one of:
83
+ * - A receipt and stats if the tx succeeded
84
+ * - a receipt and errorMsg if it failed on L1
85
+ * - undefined if no valid requests are found OR the tx failed to send.
86
+ */ async sendRequests() {
87
+ const requestsToProcess = [
88
+ ...this.requests
89
+ ];
74
90
  this.requests = [];
75
91
  if (this.interrupted) {
76
92
  return undefined;
77
93
  }
78
94
  const currentL2Slot = this.getCurrentL2Slot();
79
95
  this.log.debug(`Current L2 slot: ${currentL2Slot}`);
80
- const validRequests = requestsToProcess.filter(request => request.lastValidL2Slot >= currentL2Slot);
96
+ const validRequests = requestsToProcess.filter((request)=>request.lastValidL2Slot >= currentL2Slot);
81
97
  if (validRequests.length !== requestsToProcess.length) {
82
98
  this.log.warn(`Some requests were expired for slot ${currentL2Slot}`, {
83
- validRequests: validRequests.map(request => ({
84
- action: request.action,
85
- lastValidL2Slot: request.lastValidL2Slot,
86
- })),
87
- requests: requestsToProcess.map(request => ({
88
- action: request.action,
89
- lastValidL2Slot: request.lastValidL2Slot,
90
- })),
99
+ validRequests: validRequests.map((request)=>({
100
+ action: request.action,
101
+ lastValidL2Slot: request.lastValidL2Slot
102
+ })),
103
+ requests: requestsToProcess.map((request)=>({
104
+ action: request.action,
105
+ lastValidL2Slot: request.lastValidL2Slot
106
+ }))
91
107
  });
92
108
  }
93
109
  if (validRequests.length === 0) {
@@ -97,8 +113,8 @@ export class SequencerPublisher {
97
113
  // @note - we can only have one gas config and one blob config per bundle
98
114
  // find requests with gas and blob configs
99
115
  // See https://github.com/AztecProtocol/aztec-packages/issues/11513
100
- const gasConfigs = requestsToProcess.filter(request => request.gasConfig);
101
- const blobConfigs = requestsToProcess.filter(request => request.blobConfig);
116
+ const gasConfigs = requestsToProcess.filter((request)=>request.gasConfig);
117
+ const blobConfigs = requestsToProcess.filter((request)=>request.blobConfig);
102
118
  if (gasConfigs.length > 1 || blobConfigs.length > 1) {
103
119
  throw new Error('Multiple gas or blob configs found');
104
120
  }
@@ -106,13 +122,12 @@ export class SequencerPublisher {
106
122
  const blobConfig = blobConfigs[0]?.blobConfig;
107
123
  try {
108
124
  this.log.debug('Forwarding transactions', {
109
- validRequests: validRequests.map(request => request.action),
125
+ validRequests: validRequests.map((request)=>request.action)
110
126
  });
111
- const result = await this.forwarderContract.forward(validRequests.map(request => request.request), this.l1TxUtils, gasConfig, blobConfig, this.log);
127
+ const result = await this.forwarderContract.forward(validRequests.map((request)=>request.request), this.l1TxUtils, gasConfig, blobConfig, this.log);
112
128
  this.callbackBundledTransactions(validRequests, result);
113
129
  return result;
114
- }
115
- catch (err) {
130
+ } catch (err) {
116
131
  const viemError = formatViemError(err);
117
132
  this.log.error(`Failed to publish bundled transactions`, viemError);
118
133
  return undefined;
@@ -121,81 +136,83 @@ export class SequencerPublisher {
121
136
  callbackBundledTransactions(requests, result) {
122
137
  const success = result?.receipt.status === 'success';
123
138
  const logger = success ? this.log.info : this.log.error;
124
- for (const request of requests) {
139
+ for (const request of requests){
125
140
  logger(`Bundled [${request.action}] transaction [${success ? 'succeeded' : 'failed'}]`);
126
141
  request.onResult?.(request.request, result);
127
142
  }
128
143
  }
129
144
  /**
130
- * @notice Will call `canProposeAtNextEthBlock` to make sure that it is possible to propose
131
- * @param tipArchive - The archive to check
132
- * @returns The slot and block number if it is possible to propose, undefined otherwise
133
- */
134
- canProposeAtNextEthBlock(tipArchive) {
135
- const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
136
- return this.rollupContract
137
- .canProposeAtNextEthBlock(tipArchive, this.getForwarderAddress().toString(), this.ethereumSlotDuration)
138
- .catch(err => {
139
- if (err instanceof FormattedViemError && ignoredErrors.find(e => err.message.includes(e))) {
145
+ * @notice Will call `canProposeAtNextEthBlock` to make sure that it is possible to propose
146
+ * @param tipArchive - The archive to check
147
+ * @returns The slot and block number if it is possible to propose, undefined otherwise
148
+ */ canProposeAtNextEthBlock(tipArchive) {
149
+ const ignoredErrors = [
150
+ 'SlotAlreadyInChain',
151
+ 'InvalidProposer',
152
+ 'InvalidArchive'
153
+ ];
154
+ return this.rollupContract.canProposeAtNextEthBlock(tipArchive, this.getForwarderAddress().toString(), this.ethereumSlotDuration).catch((err)=>{
155
+ if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
140
156
  this.log.debug(err.message);
141
- }
142
- else {
157
+ } else {
143
158
  this.log.error(err.name, err);
144
159
  }
145
160
  return undefined;
146
161
  });
147
162
  }
148
163
  /**
149
- * @returns The epoch that is currently claimable, undefined otherwise
150
- */
151
- getClaimableEpoch() {
152
- const acceptedErrors = ['Rollup__NoEpochToProve', 'Rollup__ProofRightAlreadyClaimed'];
153
- return this.rollupContract.getClaimableEpoch().catch(err => {
154
- if (acceptedErrors.find(e => err.message.includes(e))) {
164
+ * @returns The epoch that is currently claimable, undefined otherwise
165
+ */ getClaimableEpoch() {
166
+ const acceptedErrors = [
167
+ 'Rollup__NoEpochToProve',
168
+ 'Rollup__ProofRightAlreadyClaimed'
169
+ ];
170
+ return this.rollupContract.getClaimableEpoch().catch((err)=>{
171
+ if (acceptedErrors.find((e)=>err.message.includes(e))) {
155
172
  return undefined;
156
173
  }
157
174
  throw err;
158
175
  });
159
176
  }
160
177
  /**
161
- * @notice Will filter out invalid quotes according to L1
162
- * @param quotes - The quotes to filter
163
- * @returns The filtered quotes
164
- */
165
- filterValidQuotes(quotes) {
166
- return Promise.all(quotes.map(x => this.rollupContract
167
- // validate throws if the quote is not valid
178
+ * @notice Will filter out invalid quotes according to L1
179
+ * @param quotes - The quotes to filter
180
+ * @returns The filtered quotes
181
+ */ filterValidQuotes(quotes) {
182
+ return Promise.all(quotes.map((x)=>this.rollupContract// validate throws if the quote is not valid
168
183
  // else returns void
169
- .validateProofQuote(x.toViemArgs(), this.getForwarderAddress().toString(), this.ethereumSlotDuration)
170
- .then(() => x)
171
- .catch(err => {
172
- this.log.error(`Failed to validate proof quote`, err, { quote: x.toInspect() });
173
- return undefined;
174
- }))).then(quotes => quotes.filter((q) => !!q));
184
+ .validateProofQuote(x.toViemArgs(), this.getForwarderAddress().toString(), this.ethereumSlotDuration).then(()=>x).catch((err)=>{
185
+ this.log.error(`Failed to validate proof quote`, err, {
186
+ quote: x.toInspect()
187
+ });
188
+ return undefined;
189
+ }))).then((quotes)=>quotes.filter((q)=>!!q));
175
190
  }
176
191
  /**
177
- * @notice Will call `validateHeader` to make sure that it is possible to propose
178
- *
179
- * @dev Throws if unable to propose
180
- *
181
- * @param header - The header to propose
182
- * @param digest - The digest that attestations are signing over
183
- *
184
- */
185
- async validateBlockForSubmission(header, attestationData = {
192
+ * @notice Will call `validateHeader` to make sure that it is possible to propose
193
+ *
194
+ * @dev Throws if unable to propose
195
+ *
196
+ * @param header - The header to propose
197
+ * @param digest - The digest that attestations are signing over
198
+ *
199
+ */ async validateBlockForSubmission(header, attestationData = {
186
200
  digest: Buffer.alloc(32),
187
- signatures: [],
201
+ signatures: []
188
202
  }) {
189
203
  const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
190
- const formattedSignatures = attestationData.signatures.map(attest => attest.toViemSignature());
191
- const flags = { ignoreDA: true, ignoreSignatures: formattedSignatures.length == 0 };
204
+ const formattedSignatures = attestationData.signatures.map((attest)=>attest.toViemSignature());
205
+ const flags = {
206
+ ignoreDA: true,
207
+ ignoreSignatures: formattedSignatures.length == 0
208
+ };
192
209
  const args = [
193
210
  `0x${header.toBuffer().toString('hex')}`,
194
211
  formattedSignatures,
195
212
  `0x${attestationData.digest.toString('hex')}`,
196
213
  ts,
197
214
  `0x${header.contentCommitment.blobsHash.toString('hex')}`,
198
- flags,
215
+ flags
199
216
  ];
200
217
  await this.rollupContract.validateHeader(args, this.getForwarderAddress().toString());
201
218
  return ts;
@@ -214,7 +231,7 @@ export class SequencerPublisher {
214
231
  const round = await base.computeRound(slotNumber);
215
232
  const [proposer, roundInfo] = await Promise.all([
216
233
  this.rollupContract.getProposerAt(timestamp),
217
- base.getRoundInfo(this.rollupContract.address, round),
234
+ base.getRoundInfo(this.rollupContract.address, round)
218
235
  ]);
219
236
  if (proposer.toLowerCase() !== this.getForwarderAddress().toString().toLowerCase()) {
220
237
  return false;
@@ -225,25 +242,26 @@ export class SequencerPublisher {
225
242
  const cachedLastVote = this.myLastVotes[voteType];
226
243
  this.myLastVotes[voteType] = slotNumber;
227
244
  this.addRequest({
228
- action: voteType === VoteType.GOVERNANCE ? 'governance-vote' : 'slashing-vote',
245
+ action: voteType === 0 ? 'governance-vote' : 'slashing-vote',
229
246
  request: base.createVoteRequest(payload.toString()),
230
247
  lastValidL2Slot: slotNumber,
231
- onResult: (_request, result) => {
248
+ onResult: (_request, result)=>{
232
249
  if (!result || result.receipt.status !== 'success') {
233
250
  this.myLastVotes[voteType] = cachedLastVote;
234
- }
235
- else {
251
+ } else {
236
252
  this.log.info(`Cast [${voteType}] vote for slot ${slotNumber}`);
237
253
  }
238
- },
254
+ }
239
255
  });
240
256
  return true;
241
257
  }
242
258
  async getVoteConfig(slotNumber, voteType) {
243
- if (voteType === VoteType.GOVERNANCE) {
244
- return { payload: this.governancePayload, base: this.govProposerContract };
245
- }
246
- else if (voteType === VoteType.SLASHING) {
259
+ if (voteType === 0) {
260
+ return {
261
+ payload: this.governancePayload,
262
+ base: this.govProposerContract
263
+ };
264
+ } else if (voteType === 1) {
247
265
  if (!this.getSlashPayload) {
248
266
  return undefined;
249
267
  }
@@ -251,18 +269,20 @@ export class SequencerPublisher {
251
269
  if (!slashPayload) {
252
270
  return undefined;
253
271
  }
254
- return { payload: slashPayload, base: this.slashingProposerContract };
272
+ return {
273
+ payload: slashPayload,
274
+ base: this.slashingProposerContract
275
+ };
255
276
  }
256
277
  throw new Error('Unreachable: Invalid vote type');
257
278
  }
258
279
  /**
259
- * Enqueues a castVote transaction to cast a vote for a given slot number.
260
- * @param slotNumber - The slot number to cast a vote for.
261
- * @param timestamp - The timestamp of the slot to cast a vote for.
262
- * @param voteType - The type of vote to cast.
263
- * @returns True if the vote was successfully enqueued, false otherwise.
264
- */
265
- async enqueueCastVote(slotNumber, timestamp, voteType) {
280
+ * Enqueues a castVote transaction to cast a vote for a given slot number.
281
+ * @param slotNumber - The slot number to cast a vote for.
282
+ * @param timestamp - The timestamp of the slot to cast a vote for.
283
+ * @param voteType - The type of vote to cast.
284
+ * @returns True if the vote was successfully enqueued, false otherwise.
285
+ */ async enqueueCastVote(slotNumber, timestamp, voteType) {
266
286
  const voteConfig = await this.getVoteConfig(slotNumber, voteType);
267
287
  if (!voteConfig) {
268
288
  return false;
@@ -271,12 +291,11 @@ export class SequencerPublisher {
271
291
  return this.enqueueCastVoteHelper(slotNumber, timestamp, voteType, payload, base);
272
292
  }
273
293
  /**
274
- * Proposes a L2 block on L1.
275
- *
276
- * @param block - L2 block to propose.
277
- * @returns True if the tx has been enqueued, throws otherwise. See #9315
278
- */
279
- async enqueueProposeL2Block(block, attestations, txHashes, opts = {}) {
294
+ * Proposes a L2 block on L1.
295
+ *
296
+ * @param block - L2 block to propose.
297
+ * @returns True if the tx has been enqueued, throws otherwise. See #9315
298
+ */ async enqueueProposeL2Block(block, attestations, txHashes, opts = {}) {
280
299
  const consensusPayload = new ConsensusPayload(block.header, block.archive.root, txHashes ?? []);
281
300
  const digest = await getHashedSignaturePayload(consensusPayload, SignatureDomainSeparator.blockAttestation);
282
301
  const blobs = await Blob.getBlobs(block.body.toBlobFields());
@@ -287,7 +306,7 @@ export class SequencerPublisher {
287
306
  body: block.body.toBuffer(),
288
307
  blobs,
289
308
  attestations,
290
- txHashes: txHashes ?? [],
309
+ txHashes: txHashes ?? []
291
310
  };
292
311
  // @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available
293
312
  // This means that we can avoid the simulation issues in later checks.
@@ -295,14 +314,13 @@ export class SequencerPublisher {
295
314
  // make time consistency checks break.
296
315
  const ts = await this.validateBlockForSubmission(block.header, {
297
316
  digest: digest.toBuffer(),
298
- signatures: attestations ?? [],
317
+ signatures: attestations ?? []
299
318
  });
300
319
  this.log.debug(`Submitting propose transaction`);
301
320
  await this.addProposeTx(block, proposeTxArgs, opts, ts);
302
321
  return true;
303
322
  }
304
- /** Enqueues a claimEpochProofRight transaction to submit a chosen prover quote for the previous epoch. */
305
- enqueueClaimEpochProofRight(proofQuote) {
323
+ /** Enqueues a claimEpochProofRight transaction to submit a chosen prover quote for the previous epoch. */ enqueueClaimEpochProofRight(proofQuote) {
306
324
  const timer = new Timer();
307
325
  this.addRequest({
308
326
  action: 'claim',
@@ -311,11 +329,13 @@ export class SequencerPublisher {
311
329
  data: encodeFunctionData({
312
330
  abi: RollupAbi,
313
331
  functionName: 'claimEpochProofRight',
314
- args: [proofQuote.toViemArgs()],
315
- }),
332
+ args: [
333
+ proofQuote.toViemArgs()
334
+ ]
335
+ })
316
336
  },
317
337
  lastValidL2Slot: this.getCurrentL2Slot(),
318
- onResult: (_request, result) => {
338
+ onResult: (_request, result)=>{
319
339
  if (!result) {
320
340
  return;
321
341
  }
@@ -327,66 +347,65 @@ export class SequencerPublisher {
327
347
  transactionHash: receipt.transactionHash,
328
348
  blobDataGas: 0n,
329
349
  blobGasUsed: 0n,
330
- ...pick(stats, 'calldataGas', 'calldataSize', 'sender'),
350
+ ...pick(stats, 'calldataGas', 'calldataSize', 'sender')
331
351
  };
332
352
  this.log.verbose(`Submitted claim epoch proof right to L1 rollup contract`, {
333
353
  ...publishStats,
334
- ...proofQuote.toInspect(),
354
+ ...proofQuote.toInspect()
335
355
  });
336
356
  this.metrics.recordClaimEpochProofRightTx(timer.ms(), publishStats);
337
- }
338
- else {
357
+ } else {
339
358
  this.metrics.recordFailedTx('claimEpochProofRight');
340
359
  // TODO: Get the error message from the reverted tx
341
360
  this.log.error(`Claim epoch proof right tx reverted`, {
342
361
  txHash: receipt.transactionHash,
343
- ...proofQuote.toInspect(),
362
+ ...proofQuote.toInspect()
344
363
  });
345
364
  }
346
- },
365
+ }
347
366
  });
348
367
  return true;
349
368
  }
350
369
  /**
351
- * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
352
- * Be warned, the call may return false even if the tx subsequently gets successfully mined.
353
- * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
354
- * A call to `restart` is required before you can continue publishing.
355
- */
356
- interrupt() {
370
+ * Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
371
+ * Be warned, the call may return false even if the tx subsequently gets successfully mined.
372
+ * In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
373
+ * A call to `restart` is required before you can continue publishing.
374
+ */ interrupt() {
357
375
  this.interrupted = true;
358
376
  this.l1TxUtils.interrupt();
359
377
  }
360
- /** Restarts the publisher after calling `interrupt`. */
361
- restart() {
378
+ /** Restarts the publisher after calling `interrupt`. */ restart() {
362
379
  this.interrupted = false;
363
380
  this.l1TxUtils.restart();
364
381
  }
365
382
  async prepareProposeTx(encodedData, timestamp) {
366
383
  const kzg = Blob.getViemKzgInstance();
367
384
  const blobInput = Blob.getEthBlobEvaluationInputs(encodedData.blobs);
368
- this.log.debug('Validating blob input', { blobInput });
369
- const blobEvaluationGas = await this.l1TxUtils
370
- .estimateGas(this.l1TxUtils.walletClient.account, {
385
+ this.log.debug('Validating blob input', {
386
+ blobInput
387
+ });
388
+ const blobEvaluationGas = await this.l1TxUtils.estimateGas(this.l1TxUtils.walletClient.account, {
371
389
  to: this.rollupContract.address,
372
390
  data: encodeFunctionData({
373
391
  abi: RollupAbi,
374
392
  functionName: 'validateBlobs',
375
- args: [blobInput],
376
- }),
393
+ args: [
394
+ blobInput
395
+ ]
396
+ })
377
397
  }, {}, {
378
- blobs: encodedData.blobs.map(b => b.data),
379
- kzg,
380
- })
381
- .catch(err => {
398
+ blobs: encodedData.blobs.map((b)=>b.data),
399
+ kzg
400
+ }).catch((err)=>{
382
401
  const { message, metaMessages } = formatViemError(err);
383
- this.log.error(`Failed to validate blobs`, message, { metaMessages });
402
+ this.log.error(`Failed to validate blobs`, message, {
403
+ metaMessages
404
+ });
384
405
  throw new Error('Failed to validate blobs');
385
406
  });
386
- const attestations = encodedData.attestations
387
- ? encodedData.attestations.map(attest => attest.toViemSignature())
388
- : [];
389
- const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.toString()) : [];
407
+ const attestations = encodedData.attestations ? encodedData.attestations.map((attest)=>attest.toViemSignature()) : [];
408
+ const txHashes = encodedData.txHashes ? encodedData.txHashes.map((txHash)=>txHash.toString()) : [];
390
409
  const args = [
391
410
  {
392
411
  header: `0x${encodedData.header.toString('hex')}`,
@@ -394,36 +413,42 @@ export class SequencerPublisher {
394
413
  oracleInput: {
395
414
  // We are currently not modifying these. See #9963
396
415
  feeAssetPriceModifier: 0n,
397
- provingCostModifier: 0n,
416
+ provingCostModifier: 0n
398
417
  },
399
418
  blockHash: `0x${encodedData.blockHash.toString('hex')}`,
400
- txHashes,
419
+ txHashes
401
420
  },
402
421
  attestations,
403
422
  // TODO(#9101): Extract blobs from beacon chain => calldata will only contain what's needed to verify blob and body input can be removed
404
423
  `0x${encodedData.body.toString('hex')}`,
405
- blobInput,
424
+ blobInput
406
425
  ];
407
426
  const rollupData = encodeFunctionData({
408
427
  abi: RollupAbi,
409
428
  functionName: 'propose',
410
- args,
429
+ args
411
430
  });
412
431
  const forwarderData = encodeFunctionData({
413
432
  abi: ForwarderAbi,
414
433
  functionName: 'forward',
415
- args: [[this.rollupContract.address], [rollupData]],
434
+ args: [
435
+ [
436
+ this.rollupContract.address
437
+ ],
438
+ [
439
+ rollupData
440
+ ]
441
+ ]
416
442
  });
417
- const simulationResult = await this.l1TxUtils
418
- .simulateGasUsed({
443
+ const simulationResult = await this.l1TxUtils.simulateGasUsed({
419
444
  to: this.getForwarderAddress().toString(),
420
445
  data: forwarderData,
421
- gas: _a.PROPOSE_GAS_GUESS,
446
+ gas: SequencerPublisher.PROPOSE_GAS_GUESS
422
447
  }, {
423
448
  // @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
424
449
  time: timestamp + 1n,
425
450
  // @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit
426
- gasLimit: _a.PROPOSE_GAS_GUESS * 2n,
451
+ gasLimit: SequencerPublisher.PROPOSE_GAS_GUESS * 2n
427
452
  }, [
428
453
  {
429
454
  address: this.rollupContract.address,
@@ -431,20 +456,26 @@ export class SequencerPublisher {
431
456
  stateDiff: [
432
457
  {
433
458
  slot: toHex(RollupContract.checkBlobStorageSlot, true),
434
- value: toHex(0n, true),
435
- },
436
- ],
437
- },
459
+ value: toHex(0n, true)
460
+ }
461
+ ]
462
+ }
438
463
  ], {
439
464
  // @note fallback gas estimate to use if the node doesn't support simulation API
440
- fallbackGasEstimate: _a.PROPOSE_GAS_GUESS,
441
- })
442
- .catch(err => {
465
+ fallbackGasEstimate: SequencerPublisher.PROPOSE_GAS_GUESS
466
+ }).catch((err)=>{
443
467
  const { message, metaMessages } = formatViemError(err);
444
- this.log.error(`Failed to simulate gas used`, message, { metaMessages });
468
+ this.log.error(`Failed to simulate gas used`, message, {
469
+ metaMessages
470
+ });
445
471
  throw new Error('Failed to simulate gas used');
446
472
  });
447
- return { args, blobEvaluationGas, rollupData, simulationResult };
473
+ return {
474
+ args,
475
+ blobEvaluationGas,
476
+ rollupData,
477
+ simulationResult
478
+ };
448
479
  }
449
480
  async addProposeTx(block, encodedData, opts = {}, timestamp) {
450
481
  const timer = new Timer();
@@ -456,18 +487,18 @@ export class SequencerPublisher {
456
487
  action: 'propose',
457
488
  request: {
458
489
  to: this.rollupContract.address,
459
- data: rollupData,
490
+ data: rollupData
460
491
  },
461
492
  lastValidL2Slot: block.header.globalVariables.slotNumber.toBigInt(),
462
493
  gasConfig: {
463
494
  ...opts,
464
- gasLimit: this.l1TxUtils.bumpGasLimit(simulationResult + blobEvaluationGas),
495
+ gasLimit: this.l1TxUtils.bumpGasLimit(simulationResult + blobEvaluationGas)
465
496
  },
466
497
  blobConfig: {
467
- blobs: encodedData.blobs.map(b => b.data),
468
- kzg,
498
+ blobs: encodedData.blobs.map((b)=>b.data),
499
+ kzg
469
500
  },
470
- onResult: (request, result) => {
501
+ onResult: (request, result)=>{
471
502
  if (!result) {
472
503
  return;
473
504
  }
@@ -485,44 +516,38 @@ export class SequencerPublisher {
485
516
  ...block.getStats(),
486
517
  eventName: 'rollup-published-to-l1',
487
518
  blobCount: encodedData.blobs.length,
488
- inclusionBlocks,
519
+ inclusionBlocks
489
520
  };
490
- this.log.verbose(`Published L2 block to L1 rollup contract`, { ...stats, ...block.getStats() });
521
+ this.log.verbose(`Published L2 block to L1 rollup contract`, {
522
+ ...stats,
523
+ ...block.getStats()
524
+ });
491
525
  this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
492
526
  // Send the blobs to the blob sink
493
- this.sendBlobsToBlobSink(receipt.blockHash, encodedData.blobs).catch(_err => {
527
+ this.sendBlobsToBlobSink(receipt.blockHash, encodedData.blobs).catch((_err)=>{
494
528
  this.log.error('Failed to send blobs to blob sink');
495
529
  });
496
530
  return true;
497
- }
498
- else {
531
+ } else {
499
532
  this.metrics.recordFailedTx('process');
500
533
  this.log.error(`Rollup process tx reverted. ${errorMsg ?? 'No error message'}`, undefined, {
501
534
  ...block.getStats(),
502
535
  txHash: receipt.transactionHash,
503
536
  blockHash,
504
- slotNumber: block.header.globalVariables.slotNumber.toBigInt(),
537
+ slotNumber: block.header.globalVariables.slotNumber.toBigInt()
505
538
  });
506
539
  }
507
- },
540
+ }
508
541
  });
509
542
  }
510
543
  /**
511
- * Send blobs to the blob sink
512
- *
513
- * If a blob sink url is configured, then we send blobs to the blob sink
514
- * - for now we use the blockHash as the identifier for the blobs;
515
- * In the future this will move to be the beacon block id - which takes a bit more work
516
- * to calculate and will need to be mocked in e2e tests
517
- */
518
- sendBlobsToBlobSink(blockHash, blobs) {
544
+ * Send blobs to the blob sink
545
+ *
546
+ * If a blob sink url is configured, then we send blobs to the blob sink
547
+ * - for now we use the blockHash as the identifier for the blobs;
548
+ * In the future this will move to be the beacon block id - which takes a bit more work
549
+ * to calculate and will need to be mocked in e2e tests
550
+ */ sendBlobsToBlobSink(blockHash, blobs) {
519
551
  return this.blobSinkClient.sendBlobsToBlobSink(blockHash, blobs);
520
552
  }
521
553
  }
522
- _a = SequencerPublisher;
523
- // @note - with blobs, the below estimate seems too large.
524
- // Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
525
- // Total used for emptier block from above test: 429k (of which 84k is 1x blob)
526
- SequencerPublisher.PROPOSE_GAS_GUESS = 12000000n;
527
- SequencerPublisher.PROPOSE_AND_CLAIM_GAS_GUESS = _a.PROPOSE_GAS_GUESS + 100000n;
528
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VxdWVuY2VyLXB1Ymxpc2hlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wdWJsaXNoZXIvc2VxdWVuY2VyLXB1Ymxpc2hlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFnQyxvQkFBb0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdGLE9BQU8sRUFDTCxnQkFBZ0IsRUFHaEIsd0JBQXdCLEVBRXhCLHlCQUF5QixHQUMxQixNQUFNLHNCQUFzQixDQUFDO0FBRTlCLE9BQU8sRUFBb0IsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFbEUsT0FBTyxFQUNMLGtCQUFrQixFQVVsQixjQUFjLEVBR2QsZUFBZSxHQUNoQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFOUMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzlELE9BQU8sRUFBd0Isa0JBQWtCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUVuRixPQUFPLElBQUksTUFBTSxhQUFhLENBQUM7QUFDL0IsT0FBTyxFQUEyQixrQkFBa0IsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUduRSxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQW9CN0UsTUFBTSxDQUFOLElBQVksUUFHWDtBQUhELFdBQVksUUFBUTtJQUNsQixtREFBVSxDQUFBO0lBQ1YsK0NBQVEsQ0FBQTtBQUNWLENBQUMsRUFIVyxRQUFRLEtBQVIsUUFBUSxRQUduQjtBQWlCRCxNQUFNLE9BQU8sa0JBQWtCO0lBb0M3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