@aztec/sequencer-client 0.0.1-commit.b655e406 → 0.0.1-commit.fce3e4f
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/index.d.ts +1 -1
- package/dest/client/sequencer-client.d.ts +1 -1
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +2 -1
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +9 -0
- package/dest/global_variable_builder/global_builder.d.ts +3 -6
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +9 -6
- package/dest/global_variable_builder/index.d.ts +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/publisher/config.d.ts +3 -1
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +5 -0
- package/dest/publisher/index.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- 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.d.ts +29 -23
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +108 -57
- package/dest/sequencer/block_builder.d.ts +1 -1
- package/dest/sequencer/block_builder.d.ts.map +1 -1
- package/dest/sequencer/block_builder.js +10 -6
- package/dest/sequencer/config.d.ts +1 -1
- package/dest/sequencer/errors.d.ts +1 -1
- package/dest/sequencer/errors.d.ts.map +1 -1
- package/dest/sequencer/index.d.ts +1 -1
- package/dest/sequencer/metrics.d.ts +11 -2
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +38 -0
- package/dest/sequencer/sequencer.d.ts +17 -25
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +169 -46
- package/dest/sequencer/timetable.d.ts +1 -1
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/utils.d.ts +1 -1
- package/dest/test/index.d.ts +1 -1
- package/dest/tx_validator/nullifier_cache.d.ts +1 -1
- package/dest/tx_validator/nullifier_cache.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.d.ts +2 -2
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/package.json +31 -30
- package/src/client/sequencer-client.ts +2 -2
- package/src/config.ts +10 -0
- package/src/global_variable_builder/global_builder.ts +12 -8
- package/src/publisher/config.ts +8 -0
- package/src/publisher/sequencer-publisher-factory.ts +2 -1
- package/src/publisher/sequencer-publisher.ts +125 -70
- package/src/sequencer/block_builder.ts +10 -6
- package/src/sequencer/metrics.ts +51 -2
- package/src/sequencer/sequencer.ts +204 -60
|
@@ -18,13 +18,14 @@ import {
|
|
|
18
18
|
type TransactionStats,
|
|
19
19
|
type ViemCommitteeAttestations,
|
|
20
20
|
type ViemHeader,
|
|
21
|
-
|
|
21
|
+
WEI_CONST,
|
|
22
22
|
formatViemError,
|
|
23
23
|
tryExtractEvent,
|
|
24
24
|
} from '@aztec/ethereum';
|
|
25
25
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
26
26
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
27
27
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
28
|
+
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
28
29
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
29
30
|
import { Signature, type ViemSignature } from '@aztec/foundation/eth-signature';
|
|
30
31
|
import type { Fr } from '@aztec/foundation/fields';
|
|
@@ -37,10 +38,9 @@ import { CommitteeAttestation, CommitteeAttestationsAndSigners, type ValidateBlo
|
|
|
37
38
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
38
39
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
39
40
|
import type { L1PublishBlockStats } from '@aztec/stdlib/stats';
|
|
40
|
-
import { StateReference } from '@aztec/stdlib/tx';
|
|
41
41
|
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
42
42
|
|
|
43
|
-
import { type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
|
|
43
|
+
import { type StateOverride, type TransactionReceipt, type TypedDataDefinition, encodeFunctionData, toHex } from 'viem';
|
|
44
44
|
|
|
45
45
|
import type { PublisherConfig, TxSenderConfig } from './config.js';
|
|
46
46
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
@@ -51,8 +51,6 @@ type L1ProcessArgs = {
|
|
|
51
51
|
header: CheckpointHeader;
|
|
52
52
|
/** A root of the archive tree after the L2 block is applied. */
|
|
53
53
|
archive: Buffer;
|
|
54
|
-
/** State reference after the L2 block is applied. */
|
|
55
|
-
stateReference: StateReference;
|
|
56
54
|
/** L2 block blobs containing all tx effects. */
|
|
57
55
|
blobs: Blob[];
|
|
58
56
|
/** Attestations */
|
|
@@ -91,7 +89,7 @@ export type InvalidateBlockRequest = {
|
|
|
91
89
|
interface RequestWithExpiry {
|
|
92
90
|
action: Action;
|
|
93
91
|
request: L1TxRequest;
|
|
94
|
-
lastValidL2Slot:
|
|
92
|
+
lastValidL2Slot: SlotNumber;
|
|
95
93
|
gasConfig?: Pick<L1TxConfig, 'txTimeoutAt' | 'gasLimit'>;
|
|
96
94
|
blobConfig?: L1BlobInputs;
|
|
97
95
|
checkSuccess: (
|
|
@@ -108,12 +106,15 @@ export class SequencerPublisher {
|
|
|
108
106
|
protected governanceLog = createLogger('sequencer:publisher:governance');
|
|
109
107
|
protected slashingLog = createLogger('sequencer:publisher:slashing');
|
|
110
108
|
|
|
111
|
-
protected lastActions: Partial<Record<Action,
|
|
109
|
+
protected lastActions: Partial<Record<Action, SlotNumber>> = {};
|
|
112
110
|
|
|
113
111
|
protected log: Logger;
|
|
114
112
|
protected ethereumSlotDuration: bigint;
|
|
115
113
|
|
|
116
114
|
private blobSinkClient: BlobSinkClientInterface;
|
|
115
|
+
|
|
116
|
+
/** Address to use for simulations in fisherman mode (actual proposer's address) */
|
|
117
|
+
private proposerAddressForSimulation?: EthAddress;
|
|
117
118
|
// @note - with blobs, the below estimate seems too large.
|
|
118
119
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
119
120
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -146,7 +147,7 @@ export class SequencerPublisher {
|
|
|
146
147
|
epochCache: EpochCache;
|
|
147
148
|
dateProvider: DateProvider;
|
|
148
149
|
metrics: SequencerPublisherMetrics;
|
|
149
|
-
lastActions: Partial<Record<Action,
|
|
150
|
+
lastActions: Partial<Record<Action, SlotNumber>>;
|
|
150
151
|
log?: Logger;
|
|
151
152
|
},
|
|
152
153
|
) {
|
|
@@ -183,14 +184,33 @@ export class SequencerPublisher {
|
|
|
183
184
|
return this.l1TxUtils.getSenderAddress();
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Sets the proposer address to use for simulations in fisherman mode.
|
|
189
|
+
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
190
|
+
*/
|
|
191
|
+
public setProposerAddressForSimulation(proposerAddress: EthAddress | undefined) {
|
|
192
|
+
this.proposerAddressForSimulation = proposerAddress;
|
|
193
|
+
}
|
|
194
|
+
|
|
186
195
|
public addRequest(request: RequestWithExpiry) {
|
|
187
196
|
this.requests.push(request);
|
|
188
197
|
}
|
|
189
198
|
|
|
190
|
-
public getCurrentL2Slot():
|
|
199
|
+
public getCurrentL2Slot(): SlotNumber {
|
|
191
200
|
return this.epochCache.getEpochAndSlotNow().slot;
|
|
192
201
|
}
|
|
193
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Clears all pending requests without sending them.
|
|
205
|
+
*/
|
|
206
|
+
public clearPendingRequests(): void {
|
|
207
|
+
const count = this.requests.length;
|
|
208
|
+
this.requests = [];
|
|
209
|
+
if (count > 0) {
|
|
210
|
+
this.log.debug(`Cleared ${count} pending request(s)`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
194
214
|
/**
|
|
195
215
|
* Sends all requests that are still valid.
|
|
196
216
|
* @returns one of:
|
|
@@ -321,7 +341,9 @@ export class SequencerPublisher {
|
|
|
321
341
|
const ignoredErrors = ['SlotAlreadyInChain', 'InvalidProposer', 'InvalidArchive'];
|
|
322
342
|
|
|
323
343
|
return this.rollupContract
|
|
324
|
-
.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), this.ethereumSlotDuration,
|
|
344
|
+
.canProposeAtNextEthBlock(tipArchive.toBuffer(), msgSender.toString(), Number(this.ethereumSlotDuration), {
|
|
345
|
+
forcePendingCheckpointNumber: opts.forcePendingBlockNumber,
|
|
346
|
+
})
|
|
325
347
|
.catch(err => {
|
|
326
348
|
if (err instanceof FormattedViemError && ignoredErrors.find(e => err.message.includes(e))) {
|
|
327
349
|
this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find(e => err.message.includes(e))}`, {
|
|
@@ -353,10 +375,20 @@ export class SequencerPublisher {
|
|
|
353
375
|
] as const;
|
|
354
376
|
|
|
355
377
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
378
|
+
const stateOverrides = await this.rollupContract.makePendingCheckpointNumberOverride(opts?.forcePendingBlockNumber);
|
|
379
|
+
let balance = 0n;
|
|
380
|
+
if (this.config.fishermanMode) {
|
|
381
|
+
// In fisherman mode, we can't know where the proposer is publishing from
|
|
382
|
+
// so we just add sufficient balance to the multicall3 address
|
|
383
|
+
balance = 10n * WEI_CONST * WEI_CONST; // 10 ETH
|
|
384
|
+
} else {
|
|
385
|
+
balance = await this.l1TxUtils.getSenderBalance();
|
|
386
|
+
}
|
|
387
|
+
stateOverrides.push({
|
|
388
|
+
address: MULTI_CALL_3_ADDRESS,
|
|
389
|
+
balance,
|
|
390
|
+
});
|
|
356
391
|
|
|
357
|
-
// use sender balance to simulate
|
|
358
|
-
const balance = await this.l1TxUtils.getSenderBalance();
|
|
359
|
-
this.log.debug(`Simulating validateHeader with balance: ${balance}`);
|
|
360
392
|
await this.l1TxUtils.simulate(
|
|
361
393
|
{
|
|
362
394
|
to: this.rollupContract.address,
|
|
@@ -364,10 +396,7 @@ export class SequencerPublisher {
|
|
|
364
396
|
from: MULTI_CALL_3_ADDRESS,
|
|
365
397
|
},
|
|
366
398
|
{ time: ts + 1n },
|
|
367
|
-
|
|
368
|
-
{ address: MULTI_CALL_3_ADDRESS, balance },
|
|
369
|
-
...(await this.rollupContract.makePendingBlockNumberOverride(opts?.forcePendingBlockNumber)),
|
|
370
|
-
],
|
|
399
|
+
stateOverrides,
|
|
371
400
|
);
|
|
372
401
|
this.log.debug(`Simulated validateHeader`);
|
|
373
402
|
}
|
|
@@ -387,7 +416,7 @@ export class SequencerPublisher {
|
|
|
387
416
|
const blockNumber = block.blockNumber;
|
|
388
417
|
const logData = { ...block, reason };
|
|
389
418
|
|
|
390
|
-
const currentBlockNumber = await this.rollupContract.
|
|
419
|
+
const currentBlockNumber = await this.rollupContract.getCheckpointNumber();
|
|
391
420
|
if (currentBlockNumber < validationResult.block.blockNumber) {
|
|
392
421
|
this.log.verbose(
|
|
393
422
|
`Skipping block ${blockNumber} invalidation since it has already been removed from the pending chain`,
|
|
@@ -414,7 +443,7 @@ export class SequencerPublisher {
|
|
|
414
443
|
`Simulation for invalidate block ${blockNumber} failed due to block not being in pending chain`,
|
|
415
444
|
{ ...logData, request, error: viemError.message },
|
|
416
445
|
);
|
|
417
|
-
const latestPendingBlockNumber = await this.rollupContract.
|
|
446
|
+
const latestPendingBlockNumber = await this.rollupContract.getCheckpointNumber();
|
|
418
447
|
if (latestPendingBlockNumber < blockNumber) {
|
|
419
448
|
this.log.verbose(`Block number ${blockNumber} has already been invalidated`, { ...logData });
|
|
420
449
|
return undefined;
|
|
@@ -489,10 +518,10 @@ export class SequencerPublisher {
|
|
|
489
518
|
// so that the committee is recalculated correctly
|
|
490
519
|
const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
491
520
|
if (ignoreSignatures) {
|
|
492
|
-
const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber
|
|
521
|
+
const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
|
|
493
522
|
if (!committee) {
|
|
494
|
-
this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber
|
|
495
|
-
throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber
|
|
523
|
+
this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
524
|
+
throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
496
525
|
}
|
|
497
526
|
attestationsAndSigners.attestations = committee.map(committeeMember =>
|
|
498
527
|
CommitteeAttestation.fromAddress(committeeMember),
|
|
@@ -507,7 +536,6 @@ export class SequencerPublisher {
|
|
|
507
536
|
{
|
|
508
537
|
header: block.getCheckpointHeader().toViem(),
|
|
509
538
|
archive: toHex(block.archive.root.toBuffer()),
|
|
510
|
-
stateReference: block.header.state.toViem(),
|
|
511
539
|
oracleInput: {
|
|
512
540
|
feeAssetPriceModifier: 0n,
|
|
513
541
|
},
|
|
@@ -523,7 +551,7 @@ export class SequencerPublisher {
|
|
|
523
551
|
}
|
|
524
552
|
|
|
525
553
|
private async enqueueCastSignalHelper(
|
|
526
|
-
slotNumber:
|
|
554
|
+
slotNumber: SlotNumber,
|
|
527
555
|
timestamp: bigint,
|
|
528
556
|
signalType: GovernanceSignalAction,
|
|
529
557
|
payload: EthAddress,
|
|
@@ -616,7 +644,7 @@ export class SequencerPublisher {
|
|
|
616
644
|
*/
|
|
617
645
|
public enqueueGovernanceCastSignal(
|
|
618
646
|
governancePayload: EthAddress,
|
|
619
|
-
slotNumber:
|
|
647
|
+
slotNumber: SlotNumber,
|
|
620
648
|
timestamp: bigint,
|
|
621
649
|
signerAddress: EthAddress,
|
|
622
650
|
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
@@ -635,7 +663,7 @@ export class SequencerPublisher {
|
|
|
635
663
|
/** Enqueues all slashing actions as returned by the slasher client. */
|
|
636
664
|
public async enqueueSlashingActions(
|
|
637
665
|
actions: ProposerSlashAction[],
|
|
638
|
-
slotNumber:
|
|
666
|
+
slotNumber: SlotNumber,
|
|
639
667
|
timestamp: bigint,
|
|
640
668
|
signerAddress: EthAddress,
|
|
641
669
|
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
@@ -775,7 +803,6 @@ export class SequencerPublisher {
|
|
|
775
803
|
const proposeTxArgs = {
|
|
776
804
|
header: checkpointHeader,
|
|
777
805
|
archive: block.archive.root.toBuffer(),
|
|
778
|
-
stateReference: block.header.state,
|
|
779
806
|
body: block.body.toBuffer(),
|
|
780
807
|
blobs,
|
|
781
808
|
attestationsAndSigners,
|
|
@@ -794,7 +821,7 @@ export class SequencerPublisher {
|
|
|
794
821
|
} catch (err: any) {
|
|
795
822
|
this.log.error(`Block validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
796
823
|
...block.getStats(),
|
|
797
|
-
slotNumber: block.header.globalVariables.slotNumber
|
|
824
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
798
825
|
forcePendingBlockNumber: opts.forcePendingBlockNumber,
|
|
799
826
|
});
|
|
800
827
|
throw err;
|
|
@@ -820,13 +847,13 @@ export class SequencerPublisher {
|
|
|
820
847
|
action: `invalidate-by-${request.reason}`,
|
|
821
848
|
request: request.request,
|
|
822
849
|
gasConfig: { gasLimit, txTimeoutAt: opts.txTimeoutAt },
|
|
823
|
-
lastValidL2Slot: this.getCurrentL2Slot() +
|
|
850
|
+
lastValidL2Slot: SlotNumber(this.getCurrentL2Slot() + 2),
|
|
824
851
|
checkSuccess: (_req, result) => {
|
|
825
852
|
const success =
|
|
826
853
|
result &&
|
|
827
854
|
result.receipt &&
|
|
828
855
|
result.receipt.status === 'success' &&
|
|
829
|
-
tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, '
|
|
856
|
+
tryExtractEvent(result.receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointInvalidated');
|
|
830
857
|
if (!success) {
|
|
831
858
|
this.log.warn(`Invalidate block ${request.blockNumber} failed`, { ...result, ...logData });
|
|
832
859
|
} else {
|
|
@@ -841,7 +868,7 @@ export class SequencerPublisher {
|
|
|
841
868
|
action: Action,
|
|
842
869
|
request: L1TxRequest,
|
|
843
870
|
checkSuccess: (receipt: TransactionReceipt) => boolean | undefined,
|
|
844
|
-
slotNumber:
|
|
871
|
+
slotNumber: SlotNumber,
|
|
845
872
|
timestamp: bigint,
|
|
846
873
|
) {
|
|
847
874
|
const logData = { slotNumber, timestamp, gasLimit: undefined as bigint | undefined };
|
|
@@ -914,36 +941,45 @@ export class SequencerPublisher {
|
|
|
914
941
|
const kzg = Blob.getViemKzgInstance();
|
|
915
942
|
const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
|
|
916
943
|
this.log.debug('Validating blob input', { blobInput });
|
|
917
|
-
const blobEvaluationGas = await this.l1TxUtils
|
|
918
|
-
.estimateGas(
|
|
919
|
-
this.getSenderAddress().toString(),
|
|
920
|
-
{
|
|
921
|
-
to: this.rollupContract.address,
|
|
922
|
-
data: encodeFunctionData({
|
|
923
|
-
abi: RollupAbi,
|
|
924
|
-
functionName: 'validateBlobs',
|
|
925
|
-
args: [blobInput],
|
|
926
|
-
}),
|
|
927
|
-
},
|
|
928
|
-
{},
|
|
929
|
-
{
|
|
930
|
-
blobs: encodedData.blobs.map(b => b.data),
|
|
931
|
-
kzg,
|
|
932
|
-
},
|
|
933
|
-
)
|
|
934
|
-
.catch(err => {
|
|
935
|
-
const { message, metaMessages } = formatViemError(err);
|
|
936
|
-
this.log.error(`Failed to validate blobs`, message, { metaMessages });
|
|
937
|
-
throw new Error('Failed to validate blobs');
|
|
938
|
-
});
|
|
939
944
|
|
|
945
|
+
// Get blob evaluation gas
|
|
946
|
+
let blobEvaluationGas: bigint;
|
|
947
|
+
if (this.config.fishermanMode) {
|
|
948
|
+
// In fisherman mode, we can't estimate blob gas because estimateGas doesn't support state overrides
|
|
949
|
+
// Use a fixed estimate.
|
|
950
|
+
blobEvaluationGas = BigInt(encodedData.blobs.length) * 21_000n;
|
|
951
|
+
this.log.debug(`Using fixed blob evaluation gas estimate in fisherman mode: ${blobEvaluationGas}`);
|
|
952
|
+
} else {
|
|
953
|
+
// Normal mode - use estimateGas with blob inputs
|
|
954
|
+
blobEvaluationGas = await this.l1TxUtils
|
|
955
|
+
.estimateGas(
|
|
956
|
+
this.getSenderAddress().toString(),
|
|
957
|
+
{
|
|
958
|
+
to: this.rollupContract.address,
|
|
959
|
+
data: encodeFunctionData({
|
|
960
|
+
abi: RollupAbi,
|
|
961
|
+
functionName: 'validateBlobs',
|
|
962
|
+
args: [blobInput],
|
|
963
|
+
}),
|
|
964
|
+
},
|
|
965
|
+
{},
|
|
966
|
+
{
|
|
967
|
+
blobs: encodedData.blobs.map(b => b.data),
|
|
968
|
+
kzg,
|
|
969
|
+
},
|
|
970
|
+
)
|
|
971
|
+
.catch(err => {
|
|
972
|
+
const { message, metaMessages } = formatViemError(err);
|
|
973
|
+
this.log.error(`Failed to validate blobs`, message, { metaMessages });
|
|
974
|
+
throw new Error('Failed to validate blobs');
|
|
975
|
+
});
|
|
976
|
+
}
|
|
940
977
|
const signers = encodedData.attestationsAndSigners.getSigners().map(signer => signer.toString());
|
|
941
978
|
|
|
942
979
|
const args = [
|
|
943
980
|
{
|
|
944
981
|
header: encodedData.header.toViem(),
|
|
945
982
|
archive: toHex(encodedData.archive),
|
|
946
|
-
stateReference: encodedData.stateReference.toViem(),
|
|
947
983
|
oracleInput: {
|
|
948
984
|
// We are currently not modifying these. See #9963
|
|
949
985
|
feeAssetPriceModifier: 0n,
|
|
@@ -971,7 +1007,6 @@ export class SequencerPublisher {
|
|
|
971
1007
|
{
|
|
972
1008
|
readonly header: ViemHeader;
|
|
973
1009
|
readonly archive: `0x${string}`;
|
|
974
|
-
readonly stateReference: ViemStateReference;
|
|
975
1010
|
readonly oracleInput: {
|
|
976
1011
|
readonly feeAssetPriceModifier: 0n;
|
|
977
1012
|
};
|
|
@@ -993,16 +1028,35 @@ export class SequencerPublisher {
|
|
|
993
1028
|
// override the pending block number if requested
|
|
994
1029
|
const forcePendingBlockNumberStateDiff = (
|
|
995
1030
|
options.forcePendingBlockNumber !== undefined
|
|
996
|
-
? await this.rollupContract.
|
|
1031
|
+
? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingBlockNumber)
|
|
997
1032
|
: []
|
|
998
1033
|
).flatMap(override => override.stateDiff ?? []);
|
|
999
1034
|
|
|
1035
|
+
const stateOverrides: StateOverride = [
|
|
1036
|
+
{
|
|
1037
|
+
address: this.rollupContract.address,
|
|
1038
|
+
// @note we override checkBlob to false since blobs are not part simulate()
|
|
1039
|
+
stateDiff: [
|
|
1040
|
+
{ slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true), value: toPaddedHex(0n, true) },
|
|
1041
|
+
...forcePendingBlockNumberStateDiff,
|
|
1042
|
+
],
|
|
1043
|
+
},
|
|
1044
|
+
];
|
|
1045
|
+
// In fisherman mode, simulate as the proposer but with sufficient balance
|
|
1046
|
+
if (this.proposerAddressForSimulation) {
|
|
1047
|
+
stateOverrides.push({
|
|
1048
|
+
address: this.proposerAddressForSimulation.toString(),
|
|
1049
|
+
balance: 10n * WEI_CONST * WEI_CONST, // 10 ETH
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1000
1053
|
const simulationResult = await this.l1TxUtils
|
|
1001
1054
|
.simulate(
|
|
1002
1055
|
{
|
|
1003
1056
|
to: this.rollupContract.address,
|
|
1004
1057
|
data: rollupData,
|
|
1005
1058
|
gas: SequencerPublisher.PROPOSE_GAS_GUESS,
|
|
1059
|
+
...(this.proposerAddressForSimulation && { from: this.proposerAddressForSimulation.toString() }),
|
|
1006
1060
|
},
|
|
1007
1061
|
{
|
|
1008
1062
|
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
@@ -1010,16 +1064,7 @@ export class SequencerPublisher {
|
|
|
1010
1064
|
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
1011
1065
|
gasLimit: SequencerPublisher.PROPOSE_GAS_GUESS * 2n,
|
|
1012
1066
|
},
|
|
1013
|
-
|
|
1014
|
-
{
|
|
1015
|
-
address: this.rollupContract.address,
|
|
1016
|
-
// @note we override checkBlob to false since blobs are not part simulate()
|
|
1017
|
-
stateDiff: [
|
|
1018
|
-
{ slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true), value: toPaddedHex(0n, true) },
|
|
1019
|
-
...forcePendingBlockNumberStateDiff,
|
|
1020
|
-
],
|
|
1021
|
-
},
|
|
1022
|
-
],
|
|
1067
|
+
stateOverrides,
|
|
1023
1068
|
RollupAbi,
|
|
1024
1069
|
{
|
|
1025
1070
|
// @note fallback gas estimate to use if the node doesn't support simulation API
|
|
@@ -1027,7 +1072,17 @@ export class SequencerPublisher {
|
|
|
1027
1072
|
},
|
|
1028
1073
|
)
|
|
1029
1074
|
.catch(err => {
|
|
1030
|
-
|
|
1075
|
+
// In fisherman mode, we expect ValidatorSelection__MissingProposerSignature since fisherman doesn't have proposer signature
|
|
1076
|
+
const viemError = formatViemError(err);
|
|
1077
|
+
if (this.config.fishermanMode && viemError.message?.includes('ValidatorSelection__MissingProposerSignature')) {
|
|
1078
|
+
this.log.debug(`Ignoring expected ValidatorSelection__MissingProposerSignature error in fisherman mode`);
|
|
1079
|
+
// Return a minimal simulation result with the fallback gas estimate
|
|
1080
|
+
return {
|
|
1081
|
+
gasUsed: SequencerPublisher.PROPOSE_GAS_GUESS,
|
|
1082
|
+
logs: [],
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
this.log.error(`Failed to simulate propose tx`, viemError);
|
|
1031
1086
|
throw err;
|
|
1032
1087
|
});
|
|
1033
1088
|
|
|
@@ -1066,7 +1121,7 @@ export class SequencerPublisher {
|
|
|
1066
1121
|
to: this.rollupContract.address,
|
|
1067
1122
|
data: rollupData,
|
|
1068
1123
|
},
|
|
1069
|
-
lastValidL2Slot: block.header.globalVariables.slotNumber
|
|
1124
|
+
lastValidL2Slot: block.header.globalVariables.slotNumber,
|
|
1070
1125
|
gasConfig: { ...opts, gasLimit },
|
|
1071
1126
|
blobConfig: {
|
|
1072
1127
|
blobs: encodedData.blobs.map(b => b.data),
|
|
@@ -1080,7 +1135,7 @@ export class SequencerPublisher {
|
|
|
1080
1135
|
const success =
|
|
1081
1136
|
receipt &&
|
|
1082
1137
|
receipt.status === 'success' &&
|
|
1083
|
-
tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, '
|
|
1138
|
+
tryExtractEvent(receipt.logs, this.rollupContract.address, RollupAbi, 'CheckpointProposed');
|
|
1084
1139
|
if (success) {
|
|
1085
1140
|
const endBlock = receipt.blockNumber;
|
|
1086
1141
|
const inclusionBlocks = Number(endBlock - startBlock);
|
|
@@ -1109,7 +1164,7 @@ export class SequencerPublisher {
|
|
|
1109
1164
|
...block.getStats(),
|
|
1110
1165
|
receipt,
|
|
1111
1166
|
txHash: receipt.transactionHash,
|
|
1112
|
-
slotNumber: block.header.globalVariables.slotNumber
|
|
1167
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
1113
1168
|
});
|
|
1114
1169
|
return false;
|
|
1115
1170
|
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
PublicProcessor,
|
|
14
14
|
TelemetryPublicTxSimulator,
|
|
15
15
|
} from '@aztec/simulator/server';
|
|
16
|
+
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
16
17
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
17
18
|
import { type L1RollupConstants, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
18
19
|
import { Gas } from '@aztec/stdlib/gas';
|
|
@@ -46,7 +47,7 @@ export async function buildBlock(
|
|
|
46
47
|
): Promise<BuildBlockResult> {
|
|
47
48
|
const blockBuildingTimer = new Timer();
|
|
48
49
|
const blockNumber = newGlobalVariables.blockNumber;
|
|
49
|
-
const slot = newGlobalVariables.slotNumber
|
|
50
|
+
const slot = newGlobalVariables.slotNumber;
|
|
50
51
|
const msgCount = l1ToL2Messages.length;
|
|
51
52
|
const stateReference = await worldStateFork.getStateReference();
|
|
52
53
|
const archiveTree = await worldStateFork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
@@ -125,11 +126,14 @@ export class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
|
|
|
125
126
|
contractsDB,
|
|
126
127
|
globalVariables,
|
|
127
128
|
this.telemetryClient,
|
|
128
|
-
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
PublicSimulatorConfig.from({
|
|
130
|
+
skipFeeEnforcement: false,
|
|
131
|
+
collectDebugLogs: false,
|
|
132
|
+
collectHints: false,
|
|
133
|
+
maxDebugLogMemoryReads: 0,
|
|
134
|
+
collectStatistics: false,
|
|
135
|
+
collectCallMetadata: false,
|
|
136
|
+
}),
|
|
133
137
|
);
|
|
134
138
|
|
|
135
139
|
const processor = new PublicProcessor(
|
package/src/sequencer/metrics.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EthAddress } from '@aztec/aztec.js/addresses';
|
|
2
2
|
import type { RollupContract } from '@aztec/ethereum';
|
|
3
|
+
import type { SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
4
|
import {
|
|
4
5
|
Attributes,
|
|
5
6
|
type Gauge,
|
|
@@ -36,7 +37,12 @@ export class SequencerMetrics {
|
|
|
36
37
|
private slots: UpDownCounter;
|
|
37
38
|
private filledSlots: UpDownCounter;
|
|
38
39
|
|
|
39
|
-
private
|
|
40
|
+
private blockProposalFailed: UpDownCounter;
|
|
41
|
+
private blockProposalSuccess: UpDownCounter;
|
|
42
|
+
private blockProposalPrecheckFailed: UpDownCounter;
|
|
43
|
+
private slashingAttempts: UpDownCounter;
|
|
44
|
+
|
|
45
|
+
private lastSeenSlot?: SlotNumber;
|
|
40
46
|
|
|
41
47
|
constructor(
|
|
42
48
|
client: TelemetryClient,
|
|
@@ -121,6 +127,29 @@ export class SequencerMetrics {
|
|
|
121
127
|
valueType: ValueType.INT,
|
|
122
128
|
description: 'The minimum number of attestations required to publish a block',
|
|
123
129
|
});
|
|
130
|
+
|
|
131
|
+
this.blockProposalFailed = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_FAILED_COUNT, {
|
|
132
|
+
valueType: ValueType.INT,
|
|
133
|
+
description: 'The number of times block proposal failed (including validation builds)',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
this.blockProposalSuccess = this.meter.createUpDownCounter(Metrics.SEQUENCER_BLOCK_PROPOSAL_SUCCESS_COUNT, {
|
|
137
|
+
valueType: ValueType.INT,
|
|
138
|
+
description: 'The number of times block proposal succeeded (including validation builds)',
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
this.blockProposalPrecheckFailed = this.meter.createUpDownCounter(
|
|
142
|
+
Metrics.SEQUENCER_BLOCK_PROPOSAL_PRECHECK_FAILED_COUNT,
|
|
143
|
+
{
|
|
144
|
+
valueType: ValueType.INT,
|
|
145
|
+
description: 'The number of times block proposal pre-build checks failed',
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
this.slashingAttempts = this.meter.createUpDownCounter(Metrics.SEQUENCER_SLASHING_ATTEMPTS_COUNT, {
|
|
150
|
+
valueType: ValueType.INT,
|
|
151
|
+
description: 'The number of slashing action attempts',
|
|
152
|
+
});
|
|
124
153
|
}
|
|
125
154
|
|
|
126
155
|
public recordRequiredAttestations(requiredAttestationsCount: number, allowanceMs: number) {
|
|
@@ -157,7 +186,7 @@ export class SequencerMetrics {
|
|
|
157
186
|
});
|
|
158
187
|
}
|
|
159
188
|
|
|
160
|
-
incOpenSlot(slot:
|
|
189
|
+
incOpenSlot(slot: SlotNumber, proposer: string) {
|
|
161
190
|
// sequencer went through the loop a second time. Noop
|
|
162
191
|
if (slot === this.lastSeenSlot) {
|
|
163
192
|
return;
|
|
@@ -188,4 +217,24 @@ export class SequencerMetrics {
|
|
|
188
217
|
}
|
|
189
218
|
}
|
|
190
219
|
}
|
|
220
|
+
|
|
221
|
+
recordBlockProposalFailed(reason?: string) {
|
|
222
|
+
this.blockProposalFailed.add(1, {
|
|
223
|
+
...(reason && { [Attributes.ERROR_TYPE]: reason }),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
recordBlockProposalSuccess() {
|
|
228
|
+
this.blockProposalSuccess.add(1);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
recordBlockProposalPrecheckFailed(checkType: string) {
|
|
232
|
+
this.blockProposalPrecheckFailed.add(1, {
|
|
233
|
+
[Attributes.ERROR_TYPE]: checkType,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
recordSlashingAttempt(actionCount: number) {
|
|
238
|
+
this.slashingAttempts.add(actionCount);
|
|
239
|
+
}
|
|
191
240
|
}
|