@aztec/sequencer-client 0.76.4-devnet-test-rc3 → 0.77.0-testnet-ignition.17

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