@aztec/sequencer-client 0.66.0 → 0.67.1-devnet
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.js +2 -1
- package/dest/config.d.ts +3 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +5 -58
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +3 -4
- package/dest/index.d.ts +0 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -2
- package/dest/publisher/index.d.ts +0 -1
- package/dest/publisher/index.d.ts.map +1 -1
- package/dest/publisher/index.js +1 -2
- package/dest/publisher/l1-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/l1-publisher-metrics.js +2 -8
- package/dest/publisher/l1-publisher.d.ts +3 -2
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +159 -50
- package/dest/publisher/utils.d.ts.map +1 -1
- package/dest/publisher/utils.js +2 -1
- package/dest/sequencer/allowed.d.ts +3 -0
- package/dest/sequencer/allowed.d.ts.map +1 -0
- package/dest/sequencer/allowed.js +34 -0
- package/dest/sequencer/config.d.ts +1 -1
- package/dest/sequencer/config.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +2 -8
- package/dest/sequencer/sequencer.d.ts +2 -6
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +112 -103
- package/dest/tx_validator/gas_validator.d.ts +3 -4
- package/dest/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/tx_validator/gas_validator.js +27 -10
- package/dest/tx_validator/phases_validator.js +3 -3
- package/dest/tx_validator/tx_validator_factory.d.ts.map +1 -1
- package/dest/tx_validator/tx_validator_factory.js +6 -4
- package/package.json +27 -20
- package/src/client/sequencer-client.ts +1 -1
- package/src/config.ts +7 -62
- package/src/global_variable_builder/global_builder.ts +3 -3
- package/src/index.ts +0 -1
- package/src/publisher/index.ts +0 -1
- package/src/publisher/l1-publisher-metrics.ts +1 -7
- package/src/publisher/l1-publisher.ts +200 -73
- package/src/publisher/utils.ts +1 -0
- package/src/sequencer/allowed.ts +36 -0
- package/src/sequencer/config.ts +1 -1
- package/src/sequencer/metrics.ts +0 -7
- package/src/sequencer/sequencer.ts +136 -149
- package/src/tx_validator/gas_validator.ts +34 -8
- package/src/tx_validator/phases_validator.ts +2 -2
- package/src/tx_validator/tx_validator_factory.ts +11 -3
|
@@ -11,9 +11,9 @@ import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circu
|
|
|
11
11
|
import {
|
|
12
12
|
AGGREGATION_OBJECT_LENGTH,
|
|
13
13
|
AZTEC_MAX_EPOCH_DURATION,
|
|
14
|
+
type BlockHeader,
|
|
14
15
|
EthAddress,
|
|
15
16
|
type FeeRecipient,
|
|
16
|
-
type Header,
|
|
17
17
|
type Proof,
|
|
18
18
|
type RootRollupPublicInputs,
|
|
19
19
|
} from '@aztec/circuits.js';
|
|
@@ -25,14 +25,16 @@ import {
|
|
|
25
25
|
createEthereumChain,
|
|
26
26
|
} from '@aztec/ethereum';
|
|
27
27
|
import { makeTuple } from '@aztec/foundation/array';
|
|
28
|
+
import { toHex } from '@aztec/foundation/bigint-buffer';
|
|
29
|
+
import { Blob } from '@aztec/foundation/blob';
|
|
28
30
|
import { areArraysEqual, compactArray, times } from '@aztec/foundation/collection';
|
|
29
31
|
import { type Signature } from '@aztec/foundation/eth-signature';
|
|
30
32
|
import { Fr } from '@aztec/foundation/fields';
|
|
31
|
-
import {
|
|
33
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
32
34
|
import { type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
33
35
|
import { InterruptibleSleep } from '@aztec/foundation/sleep';
|
|
34
36
|
import { Timer } from '@aztec/foundation/timer';
|
|
35
|
-
import { GovernanceProposerAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
37
|
+
import { ExtRollupLibAbi, GovernanceProposerAbi, LeonidasLibAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
36
38
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
37
39
|
|
|
38
40
|
import pick from 'lodash.pick';
|
|
@@ -41,7 +43,7 @@ import {
|
|
|
41
43
|
type BaseError,
|
|
42
44
|
type Chain,
|
|
43
45
|
type Client,
|
|
44
|
-
|
|
46
|
+
ContractFunctionExecutionError,
|
|
45
47
|
ContractFunctionRevertedError,
|
|
46
48
|
type GetContractReturnType,
|
|
47
49
|
type Hex,
|
|
@@ -60,6 +62,7 @@ import {
|
|
|
60
62
|
getAbiItem,
|
|
61
63
|
getAddress,
|
|
62
64
|
getContract,
|
|
65
|
+
getContractError,
|
|
63
66
|
hexToBytes,
|
|
64
67
|
http,
|
|
65
68
|
publicActions,
|
|
@@ -110,8 +113,10 @@ type L1ProcessArgs = {
|
|
|
110
113
|
archive: Buffer;
|
|
111
114
|
/** The L2 block's leaf in the archive tree. */
|
|
112
115
|
blockHash: Buffer;
|
|
113
|
-
/** L2 block body. */
|
|
116
|
+
/** L2 block body. TODO(#9101): Remove block body once we can extract blobs. */
|
|
114
117
|
body: Buffer;
|
|
118
|
+
/** L2 block blobs containing all tx effects. */
|
|
119
|
+
blobs: Blob[];
|
|
115
120
|
/** L2 block tx hashes */
|
|
116
121
|
txHashes: TxHash[];
|
|
117
122
|
/** Attestations */
|
|
@@ -149,7 +154,8 @@ export class L1Publisher {
|
|
|
149
154
|
private payload: EthAddress = EthAddress.ZERO;
|
|
150
155
|
private myLastVote: bigint = 0n;
|
|
151
156
|
|
|
152
|
-
protected log =
|
|
157
|
+
protected log = createLogger('sequencer:publisher');
|
|
158
|
+
protected governanceLog = createLogger('sequencer:publisher:governance');
|
|
153
159
|
|
|
154
160
|
protected rollupContract: GetContractReturnType<
|
|
155
161
|
typeof RollupAbi,
|
|
@@ -165,6 +171,9 @@ export class L1Publisher {
|
|
|
165
171
|
protected account: PrivateKeyAccount;
|
|
166
172
|
protected ethereumSlotDuration: bigint;
|
|
167
173
|
|
|
174
|
+
// @note - with blobs, the below estimate seems too large.
|
|
175
|
+
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
176
|
+
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
168
177
|
public static PROPOSE_GAS_GUESS: bigint = 12_000_000n;
|
|
169
178
|
public static PROPOSE_AND_CLAIM_GAS_GUESS: bigint = this.PROPOSE_GAS_GUESS + 100_000n;
|
|
170
179
|
|
|
@@ -341,8 +350,11 @@ export class L1Publisher {
|
|
|
341
350
|
try {
|
|
342
351
|
await this.rollupContract.read.validateEpochProofRightClaimAtTime(args, { account: this.account });
|
|
343
352
|
} catch (err) {
|
|
344
|
-
|
|
345
|
-
|
|
353
|
+
let errorName = tryGetCustomErrorName(err);
|
|
354
|
+
if (!errorName) {
|
|
355
|
+
errorName = tryGetCustomErrorNameContractFunction(err as ContractFunctionExecutionError);
|
|
356
|
+
}
|
|
357
|
+
this.log.warn(`Proof quote validation failed: ${errorName}`, quote);
|
|
346
358
|
return undefined;
|
|
347
359
|
}
|
|
348
360
|
return quote;
|
|
@@ -358,7 +370,7 @@ export class L1Publisher {
|
|
|
358
370
|
*
|
|
359
371
|
*/
|
|
360
372
|
public async validateBlockForSubmission(
|
|
361
|
-
header:
|
|
373
|
+
header: BlockHeader,
|
|
362
374
|
attestationData: { digest: Buffer; signatures: Signature[] } = {
|
|
363
375
|
digest: Buffer.alloc(32),
|
|
364
376
|
signatures: [],
|
|
@@ -374,7 +386,7 @@ export class L1Publisher {
|
|
|
374
386
|
formattedSignatures,
|
|
375
387
|
`0x${attestationData.digest.toString('hex')}`,
|
|
376
388
|
ts,
|
|
377
|
-
`0x${header.contentCommitment.
|
|
389
|
+
`0x${header.contentCommitment.blobsHash.toString('hex')}`,
|
|
378
390
|
flags,
|
|
379
391
|
] as const;
|
|
380
392
|
|
|
@@ -385,6 +397,36 @@ export class L1Publisher {
|
|
|
385
397
|
if (error instanceof ContractFunctionRevertedError) {
|
|
386
398
|
const err = error as ContractFunctionRevertedError;
|
|
387
399
|
this.log.debug(`Validation failed: ${err.message}`, err.data);
|
|
400
|
+
} else if (error instanceof ContractFunctionExecutionError) {
|
|
401
|
+
let err = error as ContractFunctionRevertedError;
|
|
402
|
+
if (!tryGetCustomErrorName(err)) {
|
|
403
|
+
// If we get here, it's because the custom error no longer exists in Rollup.sol,
|
|
404
|
+
// but in another lib. The below reconstructs the error message.
|
|
405
|
+
try {
|
|
406
|
+
await this.publicClient.estimateGas({
|
|
407
|
+
data: encodeFunctionData({
|
|
408
|
+
abi: this.rollupContract.abi,
|
|
409
|
+
functionName: 'validateHeader',
|
|
410
|
+
args,
|
|
411
|
+
}),
|
|
412
|
+
account: this.account,
|
|
413
|
+
to: this.rollupContract.address,
|
|
414
|
+
});
|
|
415
|
+
} catch (estGasErr: unknown) {
|
|
416
|
+
const possibleAbis = [ExtRollupLibAbi, LeonidasLibAbi];
|
|
417
|
+
possibleAbis.forEach(abi => {
|
|
418
|
+
const possibleErr = getContractError(estGasErr as BaseError, {
|
|
419
|
+
args: [],
|
|
420
|
+
abi: abi,
|
|
421
|
+
functionName: 'validateHeader',
|
|
422
|
+
address: this.rollupContract.address,
|
|
423
|
+
sender: this.account.address,
|
|
424
|
+
});
|
|
425
|
+
err = tryGetCustomErrorName(possibleErr) ? possibleErr : err;
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
throw err;
|
|
429
|
+
}
|
|
388
430
|
} else {
|
|
389
431
|
this.log.debug(`Unexpected error during validation: ${error}`);
|
|
390
432
|
}
|
|
@@ -432,7 +474,7 @@ export class L1Publisher {
|
|
|
432
474
|
this.governanceProposerContract.read.computeRound([slotNumber]),
|
|
433
475
|
]);
|
|
434
476
|
|
|
435
|
-
if (proposer
|
|
477
|
+
if (proposer.toLowerCase() !== this.account.address.toLowerCase()) {
|
|
436
478
|
return false;
|
|
437
479
|
}
|
|
438
480
|
|
|
@@ -450,14 +492,14 @@ export class L1Publisher {
|
|
|
450
492
|
const cachedMyLastVote = this.myLastVote;
|
|
451
493
|
this.myLastVote = slotNumber;
|
|
452
494
|
|
|
495
|
+
this.governanceLog.verbose(`Casting vote for ${this.payload}`);
|
|
496
|
+
|
|
453
497
|
let txHash;
|
|
454
498
|
try {
|
|
455
|
-
txHash = await this.governanceProposerContract.write.vote([this.payload.toString()], {
|
|
456
|
-
account: this.account,
|
|
457
|
-
});
|
|
499
|
+
txHash = await this.governanceProposerContract.write.vote([this.payload.toString()], { account: this.account });
|
|
458
500
|
} catch (err) {
|
|
459
501
|
const msg = prettyLogViemErrorMsg(err);
|
|
460
|
-
this.
|
|
502
|
+
this.governanceLog.error(`Failed to vote`, msg);
|
|
461
503
|
this.myLastVote = cachedMyLastVote;
|
|
462
504
|
return false;
|
|
463
505
|
}
|
|
@@ -465,14 +507,13 @@ export class L1Publisher {
|
|
|
465
507
|
if (txHash) {
|
|
466
508
|
const receipt = await this.getTransactionReceipt(txHash);
|
|
467
509
|
if (!receipt) {
|
|
468
|
-
this.
|
|
510
|
+
this.governanceLog.warn(`Failed to get receipt for tx ${txHash}`);
|
|
469
511
|
this.myLastVote = cachedMyLastVote;
|
|
470
512
|
return false;
|
|
471
513
|
}
|
|
472
514
|
}
|
|
473
515
|
|
|
474
|
-
this.
|
|
475
|
-
|
|
516
|
+
this.governanceLog.info(`Cast vote for ${this.payload}`);
|
|
476
517
|
return true;
|
|
477
518
|
}
|
|
478
519
|
|
|
@@ -501,10 +542,10 @@ export class L1Publisher {
|
|
|
501
542
|
archive: block.archive.root.toBuffer(),
|
|
502
543
|
blockHash: block.header.hash().toBuffer(),
|
|
503
544
|
body: block.body.toBuffer(),
|
|
545
|
+
blobs: Blob.getBlobs(block.body.toBlobFields()),
|
|
504
546
|
attestations,
|
|
505
547
|
txHashes: txHashes ?? [],
|
|
506
548
|
};
|
|
507
|
-
|
|
508
549
|
// Publish body and propose block (if not already published)
|
|
509
550
|
if (this.interrupted) {
|
|
510
551
|
this.log.verbose('L2 block data syncing interrupted while processing blocks.', ctx);
|
|
@@ -522,7 +563,7 @@ export class L1Publisher {
|
|
|
522
563
|
signatures: attestations ?? [],
|
|
523
564
|
});
|
|
524
565
|
|
|
525
|
-
this.log.
|
|
566
|
+
this.log.debug(`Submitting propose transaction`);
|
|
526
567
|
const result = proofQuote
|
|
527
568
|
? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote)
|
|
528
569
|
: await this.sendProposeTx(proposeTxArgs);
|
|
@@ -532,7 +573,7 @@ export class L1Publisher {
|
|
|
532
573
|
return false;
|
|
533
574
|
}
|
|
534
575
|
|
|
535
|
-
const { receipt, args, functionName } = result;
|
|
576
|
+
const { receipt, args, functionName, data } = result;
|
|
536
577
|
|
|
537
578
|
// Tx was mined successfully
|
|
538
579
|
if (receipt.status === 'success') {
|
|
@@ -545,20 +586,27 @@ export class L1Publisher {
|
|
|
545
586
|
...block.getStats(),
|
|
546
587
|
eventName: 'rollup-published-to-l1',
|
|
547
588
|
};
|
|
548
|
-
this.log.
|
|
589
|
+
this.log.verbose(`Published L2 block to L1 rollup contract`, { ...stats, ...ctx });
|
|
549
590
|
this.metrics.recordProcessBlockTx(timer.ms(), stats);
|
|
550
591
|
return true;
|
|
551
592
|
}
|
|
552
593
|
|
|
553
594
|
this.metrics.recordFailedTx('process');
|
|
554
|
-
|
|
555
|
-
const errorMsg = await this.tryGetErrorFromRevertedTx(
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
595
|
+
const kzg = Blob.getViemKzgInstance();
|
|
596
|
+
const errorMsg = await this.tryGetErrorFromRevertedTx(
|
|
597
|
+
data,
|
|
598
|
+
{
|
|
599
|
+
args,
|
|
600
|
+
functionName,
|
|
601
|
+
abi: RollupAbi,
|
|
602
|
+
address: this.rollupContract.address,
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
blobs: proposeTxArgs.blobs.map(b => b.data),
|
|
606
|
+
kzg,
|
|
607
|
+
maxFeePerBlobGas: 10000000000n,
|
|
608
|
+
},
|
|
609
|
+
);
|
|
562
610
|
this.log.error(`Rollup process tx reverted. ${errorMsg}`, undefined, {
|
|
563
611
|
...ctx,
|
|
564
612
|
txHash: receipt.transactionHash,
|
|
@@ -567,25 +615,69 @@ export class L1Publisher {
|
|
|
567
615
|
return false;
|
|
568
616
|
}
|
|
569
617
|
|
|
570
|
-
private async tryGetErrorFromRevertedTx(
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
618
|
+
private async tryGetErrorFromRevertedTx(
|
|
619
|
+
data: Hex,
|
|
620
|
+
args: {
|
|
621
|
+
args: any[];
|
|
622
|
+
functionName: string;
|
|
623
|
+
abi: any;
|
|
624
|
+
address: Hex;
|
|
625
|
+
},
|
|
626
|
+
_blobInputs?: {
|
|
627
|
+
blobs: Uint8Array[];
|
|
628
|
+
kzg: any;
|
|
629
|
+
maxFeePerBlobGas: bigint;
|
|
630
|
+
},
|
|
631
|
+
) {
|
|
632
|
+
const blobInputs = _blobInputs || {};
|
|
577
633
|
try {
|
|
578
|
-
|
|
634
|
+
// NB: If this fn starts unexpectedly giving incorrect blob hash errors, it may be because the checkBlob
|
|
635
|
+
// bool is no longer at the slot below. To find the slot, run: forge inspect src/core/Rollup.sol:Rollup storage
|
|
636
|
+
const checkBlobSlot = 9n;
|
|
637
|
+
await this.publicClient.simulateContract({
|
|
638
|
+
...args,
|
|
639
|
+
account: this.walletClient.account,
|
|
640
|
+
stateOverride: [
|
|
641
|
+
{
|
|
642
|
+
address: args.address,
|
|
643
|
+
stateDiff: [
|
|
644
|
+
{
|
|
645
|
+
slot: toHex(checkBlobSlot, true),
|
|
646
|
+
value: toHex(0n, true),
|
|
647
|
+
},
|
|
648
|
+
],
|
|
649
|
+
},
|
|
650
|
+
],
|
|
651
|
+
});
|
|
652
|
+
// If the above passes, we have a blob error. We cannot simulate blob txs, and failed txs no longer throw errors,
|
|
653
|
+
// and viem provides no way to get the revert reason from a given tx.
|
|
654
|
+
// Strangely, the only way to throw the revert reason as an error and provide blobs is prepareTransactionRequest.
|
|
655
|
+
// See: https://github.com/wevm/viem/issues/2075
|
|
656
|
+
// This throws a EstimateGasExecutionError with the custom error information:
|
|
657
|
+
await this.walletClient.prepareTransactionRequest({
|
|
658
|
+
account: this.walletClient.account,
|
|
659
|
+
to: this.rollupContract.address,
|
|
660
|
+
data,
|
|
661
|
+
...blobInputs,
|
|
662
|
+
});
|
|
579
663
|
return undefined;
|
|
580
|
-
} catch (
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
664
|
+
} catch (simulationErr: any) {
|
|
665
|
+
// If we don't have a ContractFunctionExecutionError, we have a blob related error => use ExtRollupLibAbi to get the error msg.
|
|
666
|
+
const contractErr =
|
|
667
|
+
simulationErr.name === 'ContractFunctionExecutionError'
|
|
668
|
+
? simulationErr
|
|
669
|
+
: getContractError(simulationErr as BaseError, {
|
|
670
|
+
args: [],
|
|
671
|
+
abi: ExtRollupLibAbi,
|
|
672
|
+
functionName: args.functionName,
|
|
673
|
+
address: args.address,
|
|
674
|
+
sender: this.account.address,
|
|
675
|
+
});
|
|
676
|
+
if (contractErr.name === 'ContractFunctionExecutionError') {
|
|
677
|
+
const execErr = contractErr as ContractFunctionExecutionError;
|
|
678
|
+
return tryGetCustomErrorNameContractFunction(execErr);
|
|
587
679
|
}
|
|
588
|
-
this.log.error(`Error getting error from simulation`,
|
|
680
|
+
this.log.error(`Error getting error from simulation`, simulationErr);
|
|
589
681
|
}
|
|
590
682
|
}
|
|
591
683
|
|
|
@@ -687,7 +779,7 @@ export class L1Publisher {
|
|
|
687
779
|
: proof.extractAggregationObject();
|
|
688
780
|
const argsPublicInputs = [...publicInputs.toFields(), ...aggregationObject];
|
|
689
781
|
|
|
690
|
-
if (!areArraysEqual(rollupPublicInputs.map(Fr.
|
|
782
|
+
if (!areArraysEqual(rollupPublicInputs.map(Fr.fromHexString), argsPublicInputs, (a, b) => a.equals(b))) {
|
|
691
783
|
const fmt = (inputs: Fr[] | readonly string[]) => inputs.map(x => x.toString()).join(', ');
|
|
692
784
|
throw new Error(
|
|
693
785
|
`Root rollup public inputs mismatch:\nRollup: ${fmt(rollupPublicInputs)}\nComputed:${fmt(argsPublicInputs)}`,
|
|
@@ -726,7 +818,8 @@ export class L1Publisher {
|
|
|
726
818
|
epochSize: argsArray[0],
|
|
727
819
|
args: argsArray[1],
|
|
728
820
|
fees: argsArray[2],
|
|
729
|
-
|
|
821
|
+
blobPublicInputs: argsArray[3],
|
|
822
|
+
aggregationObject: argsArray[4],
|
|
730
823
|
proof: proofHex,
|
|
731
824
|
},
|
|
732
825
|
] as const;
|
|
@@ -750,22 +843,31 @@ export class L1Publisher {
|
|
|
750
843
|
}
|
|
751
844
|
|
|
752
845
|
private async prepareProposeTx(encodedData: L1ProcessArgs) {
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
846
|
+
const kzg = Blob.getViemKzgInstance();
|
|
847
|
+
const blobEvaluationGas = await this.l1TxUtils.estimateGas(
|
|
848
|
+
this.account,
|
|
849
|
+
{
|
|
850
|
+
to: this.rollupContract.address,
|
|
851
|
+
data: encodeFunctionData({
|
|
852
|
+
abi: this.rollupContract.abi,
|
|
853
|
+
functionName: 'validateBlobs',
|
|
854
|
+
args: [Blob.getEthBlobEvaluationInputs(encodedData.blobs)],
|
|
855
|
+
}),
|
|
856
|
+
},
|
|
857
|
+
{},
|
|
858
|
+
{
|
|
859
|
+
blobs: encodedData.blobs.map(b => b.data),
|
|
860
|
+
kzg,
|
|
861
|
+
maxFeePerBlobGas: 10000000000n, //This is 10 gwei, taken from DEFAULT_MAX_FEE_PER_GAS
|
|
862
|
+
},
|
|
863
|
+
);
|
|
761
864
|
|
|
762
865
|
// @note We perform this guesstimate instead of the usual `gasEstimate` since
|
|
763
866
|
// viem will use the current state to simulate against, which means that
|
|
764
867
|
// we will fail estimation in the case where we are simulating for the
|
|
765
868
|
// first ethereum block within our slot (as current time is not in the
|
|
766
869
|
// slot yet).
|
|
767
|
-
const gasGuesstimate =
|
|
768
|
-
|
|
870
|
+
const gasGuesstimate = blobEvaluationGas + L1Publisher.PROPOSE_GAS_GUESS;
|
|
769
871
|
const attestations = encodedData.attestations
|
|
770
872
|
? encodedData.attestations.map(attest => attest.toViemSignature())
|
|
771
873
|
: [];
|
|
@@ -783,7 +885,9 @@ export class L1Publisher {
|
|
|
783
885
|
txHashes,
|
|
784
886
|
},
|
|
785
887
|
attestations,
|
|
888
|
+
// TODO(#9101): Extract blobs from beacon chain => calldata will only contain what's needed to verify blob and body input can be removed
|
|
786
889
|
`0x${encodedData.body.toString('hex')}`,
|
|
890
|
+
Blob.getEthBlobEvaluationInputs(encodedData.blobs),
|
|
787
891
|
] as const;
|
|
788
892
|
|
|
789
893
|
return { args, gas: gasGuesstimate };
|
|
@@ -811,40 +915,51 @@ export class L1Publisher {
|
|
|
811
915
|
? args.publicInputs.fees[i / 2].recipient.toField().toString()
|
|
812
916
|
: args.publicInputs.fees[(i - 1) / 2].value.toString(),
|
|
813
917
|
),
|
|
918
|
+
`0x${args.publicInputs.blobPublicInputs
|
|
919
|
+
.filter((_, i) => i < args.toBlock - args.fromBlock + 1)
|
|
920
|
+
.map(b => b.toString())
|
|
921
|
+
.join(``)}`,
|
|
814
922
|
`0x${serializeToBuffer(args.proof.extractAggregationObject()).toString('hex')}`,
|
|
815
923
|
] as const;
|
|
816
924
|
}
|
|
817
925
|
|
|
818
926
|
private async sendProposeTx(
|
|
819
927
|
encodedData: L1ProcessArgs,
|
|
820
|
-
): Promise<{ receipt: TransactionReceipt; args: any; functionName: string } | undefined> {
|
|
928
|
+
): Promise<{ receipt: TransactionReceipt | undefined; args: any; functionName: string; data: Hex } | undefined> {
|
|
821
929
|
if (this.interrupted) {
|
|
822
930
|
return undefined;
|
|
823
931
|
}
|
|
824
932
|
try {
|
|
933
|
+
const kzg = Blob.getViemKzgInstance();
|
|
825
934
|
const { args, gas } = await this.prepareProposeTx(encodedData);
|
|
935
|
+
const data = encodeFunctionData({
|
|
936
|
+
abi: this.rollupContract.abi,
|
|
937
|
+
functionName: 'propose',
|
|
938
|
+
args,
|
|
939
|
+
});
|
|
826
940
|
const receipt = await this.l1TxUtils.sendAndMonitorTransaction(
|
|
827
941
|
{
|
|
828
942
|
to: this.rollupContract.address,
|
|
829
|
-
data
|
|
830
|
-
abi: this.rollupContract.abi,
|
|
831
|
-
functionName: 'propose',
|
|
832
|
-
args,
|
|
833
|
-
}),
|
|
943
|
+
data,
|
|
834
944
|
},
|
|
835
945
|
{
|
|
836
946
|
fixedGas: gas,
|
|
837
947
|
},
|
|
948
|
+
{
|
|
949
|
+
blobs: encodedData.blobs.map(b => b.data),
|
|
950
|
+
kzg,
|
|
951
|
+
maxFeePerBlobGas: 10000000000n, //This is 10 gwei, taken from DEFAULT_MAX_FEE_PER_GAS
|
|
952
|
+
},
|
|
838
953
|
);
|
|
839
954
|
return {
|
|
840
955
|
receipt,
|
|
841
956
|
args,
|
|
842
957
|
functionName: 'propose',
|
|
958
|
+
data,
|
|
843
959
|
};
|
|
844
960
|
} catch (err) {
|
|
845
961
|
prettyLogViemError(err, this.log);
|
|
846
|
-
|
|
847
|
-
this.log.error(`Rollup publish failed`, errorMessage);
|
|
962
|
+
this.log.error(`Rollup publish failed`, err);
|
|
848
963
|
return undefined;
|
|
849
964
|
}
|
|
850
965
|
}
|
|
@@ -852,7 +967,7 @@ export class L1Publisher {
|
|
|
852
967
|
private async sendProposeAndClaimTx(
|
|
853
968
|
encodedData: L1ProcessArgs,
|
|
854
969
|
quote: EpochProofQuote,
|
|
855
|
-
): Promise<{ receipt: TransactionReceipt; args: any; functionName: string } | undefined> {
|
|
970
|
+
): Promise<{ receipt: TransactionReceipt | undefined; args: any; functionName: string; data: Hex } | undefined> {
|
|
856
971
|
if (this.interrupted) {
|
|
857
972
|
return undefined;
|
|
858
973
|
}
|
|
@@ -860,23 +975,31 @@ export class L1Publisher {
|
|
|
860
975
|
this.log.info(`ProposeAndClaim`);
|
|
861
976
|
this.log.info(inspect(quote.payload));
|
|
862
977
|
|
|
978
|
+
const kzg = Blob.getViemKzgInstance();
|
|
863
979
|
const { args, gas } = await this.prepareProposeTx(encodedData);
|
|
980
|
+
const data = encodeFunctionData({
|
|
981
|
+
abi: this.rollupContract.abi,
|
|
982
|
+
functionName: 'proposeAndClaim',
|
|
983
|
+
args: [...args, quote.toViemArgs()],
|
|
984
|
+
});
|
|
864
985
|
const receipt = await this.l1TxUtils.sendAndMonitorTransaction(
|
|
865
986
|
{
|
|
866
987
|
to: this.rollupContract.address,
|
|
867
|
-
data
|
|
868
|
-
abi: this.rollupContract.abi,
|
|
869
|
-
functionName: 'proposeAndClaim',
|
|
870
|
-
args: [...args, quote.toViemArgs()],
|
|
871
|
-
}),
|
|
988
|
+
data,
|
|
872
989
|
},
|
|
873
990
|
{ fixedGas: gas },
|
|
991
|
+
{
|
|
992
|
+
blobs: encodedData.blobs.map(b => b.data),
|
|
993
|
+
kzg,
|
|
994
|
+
maxFeePerBlobGas: 10000000000n, //This is 10 gwei, taken from DEFAULT_MAX_FEE_PER_GAS
|
|
995
|
+
},
|
|
874
996
|
);
|
|
875
997
|
|
|
876
998
|
return {
|
|
877
999
|
receipt,
|
|
878
|
-
args,
|
|
1000
|
+
args: [...args, quote.toViemArgs()],
|
|
879
1001
|
functionName: 'proposeAndClaim',
|
|
1002
|
+
data,
|
|
880
1003
|
};
|
|
881
1004
|
} catch (err) {
|
|
882
1005
|
prettyLogViemError(err, this.log);
|
|
@@ -936,6 +1059,10 @@ function getCalldataGasUsage(data: Uint8Array) {
|
|
|
936
1059
|
return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16;
|
|
937
1060
|
}
|
|
938
1061
|
|
|
1062
|
+
function tryGetCustomErrorNameContractFunction(err: ContractFunctionExecutionError) {
|
|
1063
|
+
return compactArray([err.shortMessage, ...(err.metaMessages ?? []).slice(0, 2).map(s => s.trim())]).join(' ');
|
|
1064
|
+
}
|
|
1065
|
+
|
|
939
1066
|
function tryGetCustomErrorName(err: any) {
|
|
940
1067
|
try {
|
|
941
1068
|
// See https://viem.sh/docs/contract/simulateContract#handling-custom-errors
|
package/src/publisher/utils.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type AllowedElement } from '@aztec/circuit-types';
|
|
2
|
+
import { getContractClassFromArtifact } from '@aztec/circuits.js';
|
|
3
|
+
import { FPCContract } from '@aztec/noir-contracts.js/FPC';
|
|
4
|
+
import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
|
|
5
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
6
|
+
|
|
7
|
+
let defaultAllowedSetupFunctions: AllowedElement[] | undefined = undefined;
|
|
8
|
+
|
|
9
|
+
export function getDefaultAllowedSetupFunctions(): AllowedElement[] {
|
|
10
|
+
if (defaultAllowedSetupFunctions === undefined) {
|
|
11
|
+
defaultAllowedSetupFunctions = [
|
|
12
|
+
// needed for authwit support
|
|
13
|
+
{
|
|
14
|
+
address: ProtocolContractAddress.AuthRegistry,
|
|
15
|
+
},
|
|
16
|
+
// needed for claiming on the same tx as a spend
|
|
17
|
+
{
|
|
18
|
+
address: ProtocolContractAddress.FeeJuice,
|
|
19
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
20
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'),
|
|
21
|
+
},
|
|
22
|
+
// needed for private transfers via FPC
|
|
23
|
+
{
|
|
24
|
+
classId: getContractClassFromArtifact(TokenContractArtifact).id,
|
|
25
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
26
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
classId: getContractClassFromArtifact(FPCContract.artifact).id,
|
|
30
|
+
// We can't restrict the selector because public functions get routed via dispatch.
|
|
31
|
+
// selector: FunctionSelector.fromSignature('prepare_fee((Field),Field,(Field),Field)'),
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
return defaultAllowedSetupFunctions;
|
|
36
|
+
}
|
package/src/sequencer/config.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { SequencerConfig } from '@aztec/circuit-types';
|
|
1
|
+
export { type SequencerConfig } from '@aztec/circuit-types/config';
|
package/src/sequencer/metrics.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
type Tracer,
|
|
8
8
|
type UpDownCounter,
|
|
9
9
|
ValueType,
|
|
10
|
-
millisecondBuckets,
|
|
11
10
|
} from '@aztec/telemetry-client';
|
|
12
11
|
|
|
13
12
|
import { type SequencerState, type SequencerStateCallback, sequencerStateToNumber } from './utils.js';
|
|
@@ -32,18 +31,12 @@ export class SequencerMetrics {
|
|
|
32
31
|
unit: 'ms',
|
|
33
32
|
description: 'Duration to build a block',
|
|
34
33
|
valueType: ValueType.INT,
|
|
35
|
-
advice: {
|
|
36
|
-
explicitBucketBoundaries: millisecondBuckets(2),
|
|
37
|
-
},
|
|
38
34
|
});
|
|
39
35
|
this.stateTransitionBufferDuration = meter.createHistogram(Metrics.SEQUENCER_STATE_TRANSITION_BUFFER_DURATION, {
|
|
40
36
|
unit: 'ms',
|
|
41
37
|
description:
|
|
42
38
|
'The time difference between when the sequencer needed to transition to a new state and when it actually did.',
|
|
43
39
|
valueType: ValueType.INT,
|
|
44
|
-
advice: {
|
|
45
|
-
explicitBucketBoundaries: millisecondBuckets(2),
|
|
46
|
-
},
|
|
47
40
|
});
|
|
48
41
|
|
|
49
42
|
const currentState = meter.createObservableGauge(Metrics.SEQUENCER_CURRENT_STATE, {
|