@aztec/sequencer-client 0.0.1-commit.c7c42ec → 0.0.1-commit.f295ac2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/sequencer-client.d.ts +4 -5
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +8 -1
- package/dest/global_variable_builder/global_builder.d.ts +4 -4
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +12 -12
- package/dest/index.d.ts +2 -3
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/sequencer-publisher-metrics.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-metrics.js +15 -86
- package/dest/publisher/sequencer-publisher.d.ts +17 -16
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +442 -49
- package/dest/sequencer/checkpoint_proposal_job.d.ts +14 -9
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +551 -38
- package/dest/sequencer/checkpoint_voter.d.ts +3 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +34 -10
- package/dest/sequencer/index.d.ts +1 -3
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +0 -2
- package/dest/sequencer/metrics.d.ts +3 -3
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +30 -121
- package/dest/sequencer/sequencer.d.ts +24 -14
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +485 -41
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +16 -7
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.js +32 -3
- package/dest/test/utils.d.ts +8 -4
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +23 -14
- package/package.json +30 -28
- package/src/client/sequencer-client.ts +3 -4
- package/src/config.ts +7 -0
- package/src/global_variable_builder/global_builder.ts +12 -12
- package/src/index.ts +1 -9
- package/src/publisher/sequencer-publisher-metrics.ts +14 -70
- package/src/publisher/sequencer-publisher.ts +84 -73
- package/src/sequencer/checkpoint_proposal_job.ts +183 -53
- package/src/sequencer/checkpoint_voter.ts +32 -7
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/metrics.ts +23 -131
- package/src/sequencer/sequencer.ts +122 -39
- package/src/test/index.ts +1 -2
- package/src/test/mock_checkpoint_builder.ts +62 -14
- package/src/test/utils.ts +42 -21
- package/dest/sequencer/block_builder.d.ts +0 -26
- package/dest/sequencer/block_builder.d.ts.map +0 -1
- package/dest/sequencer/block_builder.js +0 -129
- package/dest/sequencer/checkpoint_builder.d.ts +0 -63
- package/dest/sequencer/checkpoint_builder.d.ts.map +0 -1
- package/dest/sequencer/checkpoint_builder.js +0 -131
- package/dest/tx_validator/nullifier_cache.d.ts +0 -14
- package/dest/tx_validator/nullifier_cache.d.ts.map +0 -1
- package/dest/tx_validator/nullifier_cache.js +0 -24
- package/dest/tx_validator/tx_validator_factory.d.ts +0 -18
- package/dest/tx_validator/tx_validator_factory.d.ts.map +0 -1
- package/dest/tx_validator/tx_validator_factory.js +0 -53
- package/src/sequencer/block_builder.ts +0 -217
- package/src/sequencer/checkpoint_builder.ts +0 -217
- package/src/tx_validator/nullifier_cache.ts +0 -30
- package/src/tx_validator/tx_validator_factory.ts +0 -133
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
Metrics,
|
|
8
8
|
type TelemetryClient,
|
|
9
9
|
type UpDownCounter,
|
|
10
|
-
ValueType,
|
|
11
10
|
} from '@aztec/telemetry-client';
|
|
12
11
|
|
|
13
12
|
import { formatEther } from 'viem/utils';
|
|
@@ -40,88 +39,33 @@ export class SequencerPublisherMetrics {
|
|
|
40
39
|
) {
|
|
41
40
|
const meter = client.getMeter(name);
|
|
42
41
|
|
|
43
|
-
this.gasPrice = meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE
|
|
44
|
-
description: 'The gas price used for transactions',
|
|
45
|
-
unit: 'gwei',
|
|
46
|
-
valueType: ValueType.DOUBLE,
|
|
47
|
-
});
|
|
42
|
+
this.gasPrice = meter.createHistogram(Metrics.L1_PUBLISHER_GAS_PRICE);
|
|
48
43
|
|
|
49
|
-
this.txCount = meter.createUpDownCounter(Metrics.L1_PUBLISHER_TX_COUNT
|
|
50
|
-
description: 'The number of transactions processed',
|
|
51
|
-
});
|
|
44
|
+
this.txCount = meter.createUpDownCounter(Metrics.L1_PUBLISHER_TX_COUNT);
|
|
52
45
|
|
|
53
|
-
this.txDuration = meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION
|
|
54
|
-
description: 'The duration of transaction processing',
|
|
55
|
-
unit: 'ms',
|
|
56
|
-
valueType: ValueType.INT,
|
|
57
|
-
});
|
|
46
|
+
this.txDuration = meter.createHistogram(Metrics.L1_PUBLISHER_TX_DURATION);
|
|
58
47
|
|
|
59
|
-
this.txGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS
|
|
60
|
-
description: 'The gas consumed by transactions',
|
|
61
|
-
unit: 'gas',
|
|
62
|
-
valueType: ValueType.INT,
|
|
63
|
-
});
|
|
48
|
+
this.txGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_GAS);
|
|
64
49
|
|
|
65
|
-
this.txCalldataSize = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE
|
|
66
|
-
description: 'The size of the calldata in transactions',
|
|
67
|
-
unit: 'By',
|
|
68
|
-
valueType: ValueType.INT,
|
|
69
|
-
});
|
|
50
|
+
this.txCalldataSize = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_SIZE);
|
|
70
51
|
|
|
71
|
-
this.txCalldataGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS
|
|
72
|
-
description: 'The gas consumed by the calldata in transactions',
|
|
73
|
-
unit: 'gas',
|
|
74
|
-
valueType: ValueType.INT,
|
|
75
|
-
});
|
|
52
|
+
this.txCalldataGas = meter.createHistogram(Metrics.L1_PUBLISHER_TX_CALLDATA_GAS);
|
|
76
53
|
|
|
77
|
-
this.txBlobDataGasUsed = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED
|
|
78
|
-
description: 'The amount of blob gas used in transactions',
|
|
79
|
-
unit: 'gas',
|
|
80
|
-
valueType: ValueType.INT,
|
|
81
|
-
});
|
|
54
|
+
this.txBlobDataGasUsed = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_USED);
|
|
82
55
|
|
|
83
|
-
this.txBlobDataGasCost = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST
|
|
84
|
-
description: 'The gas cost of blobs in transactions',
|
|
85
|
-
unit: 'gwei',
|
|
86
|
-
valueType: ValueType.INT,
|
|
87
|
-
});
|
|
56
|
+
this.txBlobDataGasCost = meter.createHistogram(Metrics.L1_PUBLISHER_TX_BLOBDATA_GAS_COST);
|
|
88
57
|
|
|
89
|
-
this.blobCountHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_COUNT
|
|
90
|
-
description: 'Number of blobs in L1 transactions',
|
|
91
|
-
unit: 'blobs',
|
|
92
|
-
valueType: ValueType.INT,
|
|
93
|
-
});
|
|
58
|
+
this.blobCountHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_COUNT);
|
|
94
59
|
|
|
95
|
-
this.blobInclusionBlocksHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_INCLUSION_BLOCKS
|
|
96
|
-
description: 'Number of L1 blocks between blob tx submission and inclusion',
|
|
97
|
-
unit: 'blocks',
|
|
98
|
-
valueType: ValueType.INT,
|
|
99
|
-
});
|
|
60
|
+
this.blobInclusionBlocksHistogram = meter.createHistogram(Metrics.L1_PUBLISHER_BLOB_INCLUSION_BLOCKS);
|
|
100
61
|
|
|
101
|
-
this.blobTxSuccessCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_SUCCESS
|
|
102
|
-
description: 'Number of successful L1 transactions with blobs',
|
|
103
|
-
});
|
|
62
|
+
this.blobTxSuccessCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_SUCCESS);
|
|
104
63
|
|
|
105
|
-
this.blobTxFailureCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_FAILURE
|
|
106
|
-
description: 'Number of failed L1 transactions with blobs',
|
|
107
|
-
});
|
|
64
|
+
this.blobTxFailureCounter = meter.createUpDownCounter(Metrics.L1_PUBLISHER_BLOB_TX_FAILURE);
|
|
108
65
|
|
|
109
|
-
this.txTotalFee = meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE
|
|
110
|
-
description: 'How much L1 tx costs',
|
|
111
|
-
unit: 'eth',
|
|
112
|
-
valueType: ValueType.DOUBLE,
|
|
113
|
-
advice: {
|
|
114
|
-
explicitBucketBoundaries: [
|
|
115
|
-
0.001, 0.002, 0.004, 0.008, 0.01, 0.02, 0.04, 0.08, 0.1, 0.2, 0.4, 0.8, 1, 1.2, 1.4, 1.8, 2,
|
|
116
|
-
],
|
|
117
|
-
},
|
|
118
|
-
});
|
|
66
|
+
this.txTotalFee = meter.createHistogram(Metrics.L1_PUBLISHER_TX_TOTAL_FEE);
|
|
119
67
|
|
|
120
|
-
this.senderBalance = meter.createGauge(Metrics.L1_PUBLISHER_BALANCE
|
|
121
|
-
unit: 'eth',
|
|
122
|
-
description: 'The balance of the sender address',
|
|
123
|
-
valueType: ValueType.DOUBLE,
|
|
124
|
-
});
|
|
68
|
+
this.senderBalance = meter.createGauge(Metrics.L1_PUBLISHER_BALANCE);
|
|
125
69
|
}
|
|
126
70
|
|
|
127
71
|
recordFailedTx(txType: L1TxType) {
|
|
@@ -25,7 +25,7 @@ import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs'
|
|
|
25
25
|
import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
26
26
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
27
27
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
28
|
-
import {
|
|
28
|
+
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
29
29
|
import { pick } from '@aztec/foundation/collection';
|
|
30
30
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
31
31
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -35,12 +35,12 @@ import { bufferToHex } from '@aztec/foundation/string';
|
|
|
35
35
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
36
36
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
37
37
|
import { type ProposerSlashAction, encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
38
|
-
import { CommitteeAttestationsAndSigners, type
|
|
38
|
+
import { CommitteeAttestationsAndSigners, type ValidateCheckpointResult } from '@aztec/stdlib/block';
|
|
39
39
|
import type { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
40
40
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
41
41
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
42
42
|
import type { L1PublishCheckpointStats } from '@aztec/stdlib/stats';
|
|
43
|
-
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
43
|
+
import { type TelemetryClient, type Tracer, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
44
44
|
|
|
45
45
|
import { type StateOverride, type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
|
|
46
46
|
|
|
@@ -80,12 +80,12 @@ type GovernanceSignalAction = Extract<Action, 'governance-signal' | 'empire-slas
|
|
|
80
80
|
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
81
81
|
export const compareActions = (a: Action, b: Action) => Actions.indexOf(a) - Actions.indexOf(b);
|
|
82
82
|
|
|
83
|
-
export type
|
|
83
|
+
export type InvalidateCheckpointRequest = {
|
|
84
84
|
request: L1TxRequest;
|
|
85
85
|
reason: 'invalid-attestation' | 'insufficient-attestations';
|
|
86
86
|
gasUsed: bigint;
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
checkpointNumber: CheckpointNumber;
|
|
88
|
+
forcePendingCheckpointNumber: CheckpointNumber;
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
interface RequestWithExpiry {
|
|
@@ -139,6 +139,8 @@ export class SequencerPublisher {
|
|
|
139
139
|
public slashingProposerContract: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
|
|
140
140
|
public slashFactoryContract: SlashFactoryContract;
|
|
141
141
|
|
|
142
|
+
public readonly tracer: Tracer;
|
|
143
|
+
|
|
142
144
|
protected requests: RequestWithExpiry[] = [];
|
|
143
145
|
|
|
144
146
|
constructor(
|
|
@@ -167,6 +169,7 @@ export class SequencerPublisher {
|
|
|
167
169
|
|
|
168
170
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
169
171
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
172
|
+
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
170
173
|
this.l1TxUtils = deps.l1TxUtils;
|
|
171
174
|
|
|
172
175
|
this.rollupContract = deps.rollupContract;
|
|
@@ -296,6 +299,7 @@ export class SequencerPublisher {
|
|
|
296
299
|
* - a receipt and errorMsg if it failed on L1
|
|
297
300
|
* - undefined if no valid requests are found OR the tx failed to send.
|
|
298
301
|
*/
|
|
302
|
+
@trackSpan('SequencerPublisher.sendRequests')
|
|
299
303
|
public async sendRequests() {
|
|
300
304
|
const requestsToProcess = [...this.requests];
|
|
301
305
|
this.requests = [];
|
|
@@ -413,17 +417,14 @@ export class SequencerPublisher {
|
|
|
413
417
|
public canProposeAtNextEthBlock(
|
|
414
418
|
tipArchive: Fr,
|
|
415
419
|
msgSender: EthAddress,
|
|
416
|
-
opts: {
|
|
420
|
+
opts: { forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
417
421
|
) {
|
|
418
422
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
419
423
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
420
424
|
|
|
421
425
|
return this.rollupContract
|
|
422
426
|
.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
|
|
423
|
-
forcePendingCheckpointNumber:
|
|
424
|
-
opts.forcePendingBlockNumber !== undefined
|
|
425
|
-
? CheckpointNumber.fromBlockNumber(opts.forcePendingBlockNumber)
|
|
426
|
-
: undefined,
|
|
427
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber,
|
|
427
428
|
})
|
|
428
429
|
.catch(err => {
|
|
429
430
|
if (err instanceof FormattedViemError && ignoredErrors.find(e => err.message.includes(e))) {
|
|
@@ -442,10 +443,11 @@ export class SequencerPublisher {
|
|
|
442
443
|
* It will throw if the block header is invalid.
|
|
443
444
|
* @param header - The block header to validate
|
|
444
445
|
*/
|
|
446
|
+
@trackSpan('SequencerPublisher.validateBlockHeader')
|
|
445
447
|
public async validateBlockHeader(
|
|
446
448
|
header: CheckpointHeader,
|
|
447
|
-
opts?: {
|
|
448
|
-
) {
|
|
449
|
+
opts?: { forcePendingCheckpointNumber: CheckpointNumber | undefined },
|
|
450
|
+
): Promise<void> {
|
|
449
451
|
const flags = { ignoreDA: true, ignoreSignatures: true };
|
|
450
452
|
|
|
451
453
|
const args = [
|
|
@@ -454,17 +456,13 @@ export class SequencerPublisher {
|
|
|
454
456
|
[], // no signers
|
|
455
457
|
Signature.empty().toViemSignature(),
|
|
456
458
|
`0x${'0'.repeat(64)}`, // 32 empty bytes
|
|
457
|
-
header.
|
|
459
|
+
header.blobsHash.toString(),
|
|
458
460
|
flags,
|
|
459
461
|
] as const;
|
|
460
462
|
|
|
461
463
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
462
|
-
const optsForcePendingCheckpointNumber =
|
|
463
|
-
opts?.forcePendingBlockNumber !== undefined
|
|
464
|
-
? CheckpointNumber.fromBlockNumber(opts.forcePendingBlockNumber)
|
|
465
|
-
: undefined;
|
|
466
464
|
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(
|
|
467
|
-
|
|
465
|
+
opts?.forcePendingCheckpointNumber,
|
|
468
466
|
);
|
|
469
467
|
let balance = 0n;
|
|
470
468
|
if (this.config.fishermanMode) {
|
|
@@ -492,77 +490,90 @@ export class SequencerPublisher {
|
|
|
492
490
|
}
|
|
493
491
|
|
|
494
492
|
/**
|
|
495
|
-
* Simulate making a call to invalidate a
|
|
496
|
-
* @param
|
|
493
|
+
* Simulate making a call to invalidate a checkpoint with invalid attestations. Returns undefined if no need to invalidate.
|
|
494
|
+
* @param validationResult - The validation result indicating which checkpoint to invalidate (as returned by the archiver)
|
|
497
495
|
*/
|
|
498
|
-
public async
|
|
499
|
-
validationResult:
|
|
500
|
-
): Promise<
|
|
496
|
+
public async simulateInvalidateCheckpoint(
|
|
497
|
+
validationResult: ValidateCheckpointResult,
|
|
498
|
+
): Promise<InvalidateCheckpointRequest | undefined> {
|
|
501
499
|
if (validationResult.valid) {
|
|
502
500
|
return undefined;
|
|
503
501
|
}
|
|
504
502
|
|
|
505
|
-
const { reason,
|
|
506
|
-
const
|
|
507
|
-
const logData = { ...
|
|
503
|
+
const { reason, checkpoint } = validationResult;
|
|
504
|
+
const checkpointNumber = checkpoint.checkpointNumber;
|
|
505
|
+
const logData = { ...checkpoint, reason };
|
|
508
506
|
|
|
509
|
-
const
|
|
510
|
-
if (
|
|
507
|
+
const currentCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
508
|
+
if (currentCheckpointNumber < checkpointNumber) {
|
|
511
509
|
this.log.verbose(
|
|
512
|
-
`Skipping
|
|
513
|
-
{
|
|
510
|
+
`Skipping checkpoint ${checkpointNumber} invalidation since it has already been removed from the pending chain`,
|
|
511
|
+
{ currentCheckpointNumber, ...logData },
|
|
514
512
|
);
|
|
515
513
|
return undefined;
|
|
516
514
|
}
|
|
517
515
|
|
|
518
|
-
const request = this.
|
|
519
|
-
this.log.debug(`Simulating invalidate
|
|
516
|
+
const request = this.buildInvalidateCheckpointRequest(validationResult);
|
|
517
|
+
this.log.debug(`Simulating invalidate checkpoint ${checkpointNumber}`, { ...logData, request });
|
|
520
518
|
|
|
521
519
|
try {
|
|
522
520
|
const { gasUsed } = await this.l1TxUtils.simulate(request, undefined, undefined, ErrorsAbi);
|
|
523
|
-
this.log.verbose(`Simulation for invalidate
|
|
521
|
+
this.log.verbose(`Simulation for invalidate checkpoint ${checkpointNumber} succeeded`, {
|
|
522
|
+
...logData,
|
|
523
|
+
request,
|
|
524
|
+
gasUsed,
|
|
525
|
+
});
|
|
524
526
|
|
|
525
|
-
return {
|
|
527
|
+
return {
|
|
528
|
+
request,
|
|
529
|
+
gasUsed,
|
|
530
|
+
checkpointNumber,
|
|
531
|
+
forcePendingCheckpointNumber: CheckpointNumber(checkpointNumber - 1),
|
|
532
|
+
reason,
|
|
533
|
+
};
|
|
526
534
|
} catch (err) {
|
|
527
535
|
const viemError = formatViemError(err);
|
|
528
536
|
|
|
529
|
-
// If the error is due to the
|
|
530
|
-
// we can safely ignore it and return undefined so we go ahead with
|
|
537
|
+
// If the error is due to the checkpoint not being in the pending chain, and it was indeed removed by someone else,
|
|
538
|
+
// we can safely ignore it and return undefined so we go ahead with checkpoint building.
|
|
531
539
|
if (viemError.message?.includes('Rollup__BlockNotInPendingChain')) {
|
|
532
540
|
this.log.verbose(
|
|
533
|
-
`Simulation for invalidate
|
|
541
|
+
`Simulation for invalidate checkpoint ${checkpointNumber} failed due to checkpoint not being in pending chain`,
|
|
534
542
|
{ ...logData, request, error: viemError.message },
|
|
535
543
|
);
|
|
536
|
-
const
|
|
537
|
-
if (
|
|
538
|
-
this.log.verbose(`
|
|
544
|
+
const latestPendingCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
545
|
+
if (latestPendingCheckpointNumber < checkpointNumber) {
|
|
546
|
+
this.log.verbose(`Checkpoint ${checkpointNumber} has already been invalidated`, { ...logData });
|
|
539
547
|
return undefined;
|
|
540
548
|
} else {
|
|
541
549
|
this.log.error(
|
|
542
|
-
`Simulation for invalidate ${
|
|
550
|
+
`Simulation for invalidate checkpoint ${checkpointNumber} failed and it is still in pending chain`,
|
|
543
551
|
viemError,
|
|
544
552
|
logData,
|
|
545
553
|
);
|
|
546
|
-
throw new Error(
|
|
547
|
-
|
|
548
|
-
|
|
554
|
+
throw new Error(
|
|
555
|
+
`Failed to simulate invalidate checkpoint ${checkpointNumber} while it is still in pending chain`,
|
|
556
|
+
{
|
|
557
|
+
cause: viemError,
|
|
558
|
+
},
|
|
559
|
+
);
|
|
549
560
|
}
|
|
550
561
|
}
|
|
551
562
|
|
|
552
|
-
// Otherwise, throw. We cannot build the next
|
|
553
|
-
this.log.error(`Simulation for invalidate
|
|
554
|
-
throw new Error(`Failed to simulate invalidate
|
|
563
|
+
// Otherwise, throw. We cannot build the next checkpoint if we cannot invalidate the previous one.
|
|
564
|
+
this.log.error(`Simulation for invalidate checkpoint ${checkpointNumber} failed`, viemError, logData);
|
|
565
|
+
throw new Error(`Failed to simulate invalidate checkpoint ${checkpointNumber}`, { cause: viemError });
|
|
555
566
|
}
|
|
556
567
|
}
|
|
557
568
|
|
|
558
|
-
private
|
|
569
|
+
private buildInvalidateCheckpointRequest(validationResult: ValidateCheckpointResult) {
|
|
559
570
|
if (validationResult.valid) {
|
|
560
|
-
throw new Error('Cannot invalidate a valid
|
|
571
|
+
throw new Error('Cannot invalidate a valid checkpoint');
|
|
561
572
|
}
|
|
562
573
|
|
|
563
|
-
const {
|
|
564
|
-
const logData = { ...
|
|
565
|
-
this.log.debug(`
|
|
574
|
+
const { checkpoint, committee, reason } = validationResult;
|
|
575
|
+
const logData = { ...checkpoint, reason };
|
|
576
|
+
this.log.debug(`Building invalidate checkpoint ${checkpoint.checkpointNumber} request`, logData);
|
|
566
577
|
|
|
567
578
|
const attestationsAndSigners = new CommitteeAttestationsAndSigners(
|
|
568
579
|
validationResult.attestations,
|
|
@@ -570,14 +581,14 @@ export class SequencerPublisher {
|
|
|
570
581
|
|
|
571
582
|
if (reason === 'invalid-attestation') {
|
|
572
583
|
return this.rollupContract.buildInvalidateBadAttestationRequest(
|
|
573
|
-
|
|
584
|
+
checkpoint.checkpointNumber,
|
|
574
585
|
attestationsAndSigners,
|
|
575
586
|
committee,
|
|
576
587
|
validationResult.invalidIndex,
|
|
577
588
|
);
|
|
578
589
|
} else if (reason === 'insufficient-attestations') {
|
|
579
590
|
return this.rollupContract.buildInvalidateInsufficientAttestationsRequest(
|
|
580
|
-
|
|
591
|
+
checkpoint.checkpointNumber,
|
|
581
592
|
attestationsAndSigners,
|
|
582
593
|
committee,
|
|
583
594
|
);
|
|
@@ -588,11 +599,12 @@ export class SequencerPublisher {
|
|
|
588
599
|
}
|
|
589
600
|
|
|
590
601
|
/** Simulates `propose` to make sure that the checkpoint is valid for submission */
|
|
602
|
+
@trackSpan('SequencerPublisher.validateCheckpointForSubmission')
|
|
591
603
|
public async validateCheckpointForSubmission(
|
|
592
604
|
checkpoint: Checkpoint,
|
|
593
605
|
attestationsAndSigners: CommitteeAttestationsAndSigners,
|
|
594
606
|
attestationsAndSignersSignature: Signature,
|
|
595
|
-
options: {
|
|
607
|
+
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
596
608
|
): Promise<bigint> {
|
|
597
609
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
598
610
|
|
|
@@ -891,7 +903,7 @@ export class SequencerPublisher {
|
|
|
891
903
|
checkpoint: Checkpoint,
|
|
892
904
|
attestationsAndSigners: CommitteeAttestationsAndSigners,
|
|
893
905
|
attestationsAndSignersSignature: Signature,
|
|
894
|
-
opts: { txTimeoutAt?: Date;
|
|
906
|
+
opts: { txTimeoutAt?: Date; forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
895
907
|
): Promise<void> {
|
|
896
908
|
const checkpointHeader = checkpoint.header;
|
|
897
909
|
|
|
@@ -924,7 +936,7 @@ export class SequencerPublisher {
|
|
|
924
936
|
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
925
937
|
...checkpoint.getStats(),
|
|
926
938
|
slotNumber: checkpoint.header.slotNumber,
|
|
927
|
-
|
|
939
|
+
forcePendingCheckpointNumber: opts.forcePendingCheckpointNumber,
|
|
928
940
|
});
|
|
929
941
|
throw err;
|
|
930
942
|
}
|
|
@@ -933,7 +945,10 @@ export class SequencerPublisher {
|
|
|
933
945
|
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
934
946
|
}
|
|
935
947
|
|
|
936
|
-
public
|
|
948
|
+
public enqueueInvalidateCheckpoint(
|
|
949
|
+
request: InvalidateCheckpointRequest | undefined,
|
|
950
|
+
opts: { txTimeoutAt?: Date } = {},
|
|
951
|
+
) {
|
|
937
952
|
if (!request) {
|
|
938
953
|
return;
|
|
939
954
|
}
|
|
@@ -941,9 +956,9 @@ export class SequencerPublisher {
|
|
|
941
956
|
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
942
957
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil((Number(request.gasUsed) * 64) / 63)));
|
|
943
958
|
|
|
944
|
-
const { gasUsed,
|
|
945
|
-
const logData = { gasUsed,
|
|
946
|
-
this.log.verbose(`Enqueuing invalidate
|
|
959
|
+
const { gasUsed, checkpointNumber } = request;
|
|
960
|
+
const logData = { gasUsed, checkpointNumber, gasLimit, opts };
|
|
961
|
+
this.log.verbose(`Enqueuing invalidate checkpoint request`, logData);
|
|
947
962
|
this.addRequest({
|
|
948
963
|
action: `invalidate-by-${request.reason}`,
|
|
949
964
|
request: request.request,
|
|
@@ -956,9 +971,9 @@ export class SequencerPublisher {
|
|
|
956
971
|
result.receipt.status === 'success' &&
|
|
957
972
|
tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
|
|
958
973
|
if (!success) {
|
|
959
|
-
this.log.warn(`Invalidate
|
|
974
|
+
this.log.warn(`Invalidate checkpoint ${request.checkpointNumber} failed`, { ...result, ...logData });
|
|
960
975
|
} else {
|
|
961
|
-
this.log.info(`Invalidate
|
|
976
|
+
this.log.info(`Invalidate checkpoint ${request.checkpointNumber} succeeded`, { ...result, ...logData });
|
|
962
977
|
}
|
|
963
978
|
return !!success;
|
|
964
979
|
},
|
|
@@ -1037,7 +1052,7 @@ export class SequencerPublisher {
|
|
|
1037
1052
|
private async prepareProposeTx(
|
|
1038
1053
|
encodedData: L1ProcessArgs,
|
|
1039
1054
|
timestamp: bigint,
|
|
1040
|
-
options: {
|
|
1055
|
+
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
1041
1056
|
) {
|
|
1042
1057
|
const kzg = Blob.getViemKzgInstance();
|
|
1043
1058
|
const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
|
|
@@ -1118,7 +1133,7 @@ export class SequencerPublisher {
|
|
|
1118
1133
|
`0x${string}`,
|
|
1119
1134
|
],
|
|
1120
1135
|
timestamp: bigint,
|
|
1121
|
-
options: {
|
|
1136
|
+
options: { forcePendingCheckpointNumber?: CheckpointNumber },
|
|
1122
1137
|
) {
|
|
1123
1138
|
const rollupData = encodeFunctionData({
|
|
1124
1139
|
abi: RollupAbi,
|
|
@@ -1127,13 +1142,9 @@ export class SequencerPublisher {
|
|
|
1127
1142
|
});
|
|
1128
1143
|
|
|
1129
1144
|
// override the pending checkpoint number if requested
|
|
1130
|
-
const optsForcePendingCheckpointNumber =
|
|
1131
|
-
options.forcePendingBlockNumber !== undefined
|
|
1132
|
-
? CheckpointNumber.fromBlockNumber(options.forcePendingBlockNumber)
|
|
1133
|
-
: undefined;
|
|
1134
1145
|
const forcePendingCheckpointNumberStateDiff = (
|
|
1135
|
-
|
|
1136
|
-
? await this.rollupContract.makePendingCheckpointNumberOverride(
|
|
1146
|
+
options.forcePendingCheckpointNumber !== undefined
|
|
1147
|
+
? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingCheckpointNumber)
|
|
1137
1148
|
: []
|
|
1138
1149
|
).flatMap(override => override.stateDiff ?? []);
|
|
1139
1150
|
|
|
@@ -1197,7 +1208,7 @@ export class SequencerPublisher {
|
|
|
1197
1208
|
private async addProposeTx(
|
|
1198
1209
|
checkpoint: Checkpoint,
|
|
1199
1210
|
encodedData: L1ProcessArgs,
|
|
1200
|
-
opts: { txTimeoutAt?: Date;
|
|
1211
|
+
opts: { txTimeoutAt?: Date; forcePendingCheckpointNumber?: CheckpointNumber } = {},
|
|
1201
1212
|
timestamp: bigint,
|
|
1202
1213
|
): Promise<void> {
|
|
1203
1214
|
const slot = checkpoint.header.slotNumber;
|