@aztec/sequencer-client 3.0.0-rc.5 → 4.0.0-nightly.20260107
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 +9 -8
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +28 -24
- package/dest/config.d.ts +7 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +63 -26
- package/dest/global_variable_builder/global_builder.d.ts +16 -8
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +37 -28
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/publisher/config.d.ts +3 -3
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +2 -2
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +1 -1
- package/dest/publisher/sequencer-publisher-metrics.d.ts +3 -3
- package/dest/publisher/sequencer-publisher-metrics.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.d.ts +27 -23
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +119 -64
- package/dest/sequencer/block_builder.d.ts +1 -3
- package/dest/sequencer/block_builder.d.ts.map +1 -1
- package/dest/sequencer/block_builder.js +4 -2
- package/dest/sequencer/checkpoint_builder.d.ts +63 -0
- package/dest/sequencer/checkpoint_builder.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_builder.js +131 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +74 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job.js +642 -0
- package/dest/sequencer/checkpoint_voter.d.ts +34 -0
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_voter.js +85 -0
- package/dest/sequencer/events.d.ts +46 -0
- package/dest/sequencer/events.d.ts.map +1 -0
- package/dest/sequencer/events.js +1 -0
- package/dest/sequencer/index.d.ts +5 -1
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +4 -0
- package/dest/sequencer/metrics.d.ts +21 -1
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +154 -0
- package/dest/sequencer/sequencer.d.ts +91 -125
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +581 -582
- package/dest/sequencer/timetable.d.ts +54 -14
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +148 -59
- package/dest/sequencer/types.d.ts +3 -0
- package/dest/sequencer/types.d.ts.map +1 -0
- package/dest/sequencer/types.js +1 -0
- package/dest/sequencer/utils.d.ts +14 -8
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +7 -4
- package/dest/test/index.d.ts +3 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +83 -0
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -0
- package/dest/test/mock_checkpoint_builder.js +179 -0
- package/dest/test/utils.d.ts +49 -0
- package/dest/test/utils.d.ts.map +1 -0
- package/dest/test/utils.js +94 -0
- package/package.json +27 -27
- package/src/client/sequencer-client.ts +24 -31
- package/src/config.ts +68 -25
- package/src/global_variable_builder/global_builder.ts +47 -41
- package/src/index.ts +2 -0
- package/src/publisher/config.ts +3 -3
- package/src/publisher/sequencer-publisher-factory.ts +3 -3
- package/src/publisher/sequencer-publisher-metrics.ts +2 -2
- package/src/publisher/sequencer-publisher.ts +170 -74
- package/src/sequencer/README.md +531 -0
- package/src/sequencer/block_builder.ts +4 -1
- package/src/sequencer/checkpoint_builder.ts +217 -0
- package/src/sequencer/checkpoint_proposal_job.ts +706 -0
- package/src/sequencer/checkpoint_voter.ts +105 -0
- package/src/sequencer/events.ts +27 -0
- package/src/sequencer/index.ts +4 -0
- package/src/sequencer/metrics.ts +202 -0
- package/src/sequencer/sequencer.ts +300 -779
- package/src/sequencer/timetable.ts +173 -79
- package/src/sequencer/types.ts +6 -0
- package/src/sequencer/utils.ts +18 -9
- package/src/test/index.ts +2 -0
- package/src/test/mock_checkpoint_builder.ts +247 -0
- package/src/test/utils.ts +137 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
|
|
2
|
-
import { createBlobSinkClient } from '@aztec/blob-sink/client';
|
|
3
2
|
import { MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
|
|
3
|
+
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
4
4
|
import { WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
5
5
|
import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
6
6
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
7
7
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
8
8
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
9
|
+
import { pick } from '@aztec/foundation/collection';
|
|
9
10
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
10
11
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
11
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -13,7 +14,7 @@ import { bufferToHex } from '@aztec/foundation/string';
|
|
|
13
14
|
import { Timer } from '@aztec/foundation/timer';
|
|
14
15
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
15
16
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
16
|
-
import {
|
|
17
|
+
import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
17
18
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
18
19
|
import { encodeFunctionData, toHex } from 'viem';
|
|
19
20
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
@@ -38,10 +39,12 @@ export class SequencerPublisher {
|
|
|
38
39
|
governanceLog;
|
|
39
40
|
slashingLog;
|
|
40
41
|
lastActions;
|
|
42
|
+
isPayloadEmptyCache;
|
|
41
43
|
log;
|
|
42
44
|
ethereumSlotDuration;
|
|
43
|
-
|
|
45
|
+
blobClient;
|
|
44
46
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
47
|
+
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
45
48
|
// @note - with blobs, the below estimate seems too large.
|
|
46
49
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
47
50
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -62,14 +65,13 @@ export class SequencerPublisher {
|
|
|
62
65
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
63
66
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
64
67
|
this.lastActions = {};
|
|
68
|
+
this.isPayloadEmptyCache = new Map();
|
|
65
69
|
this.requests = [];
|
|
66
70
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
67
71
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
68
72
|
this.epochCache = deps.epochCache;
|
|
69
73
|
this.lastActions = deps.lastActions;
|
|
70
|
-
this.
|
|
71
|
-
logger: createLogger('sequencer:blob-sink:client')
|
|
72
|
-
});
|
|
74
|
+
this.blobClient = deps.blobClient;
|
|
73
75
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
74
76
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
75
77
|
this.l1TxUtils = deps.l1TxUtils;
|
|
@@ -82,6 +84,10 @@ export class SequencerPublisher {
|
|
|
82
84
|
this.slashingProposerContract = newSlashingProposer;
|
|
83
85
|
});
|
|
84
86
|
this.slashFactoryContract = deps.slashFactoryContract;
|
|
87
|
+
// Initialize L1 fee analyzer for fisherman mode
|
|
88
|
+
if (config.fishermanMode) {
|
|
89
|
+
this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
|
|
90
|
+
}
|
|
85
91
|
}
|
|
86
92
|
getRollupContract() {
|
|
87
93
|
return this.rollupContract;
|
|
@@ -90,6 +96,11 @@ export class SequencerPublisher {
|
|
|
90
96
|
return this.l1TxUtils.getSenderAddress();
|
|
91
97
|
}
|
|
92
98
|
/**
|
|
99
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
100
|
+
*/ getL1FeeAnalyzer() {
|
|
101
|
+
return this.l1FeeAnalyzer;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
93
104
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
94
105
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
95
106
|
*/ setProposerAddressForSimulation(proposerAddress) {
|
|
@@ -111,6 +122,46 @@ export class SequencerPublisher {
|
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
/**
|
|
125
|
+
* Analyzes L1 fees for the pending requests without sending them.
|
|
126
|
+
* This is used in fisherman mode to validate fee calculations.
|
|
127
|
+
* @param l2SlotNumber - The L2 slot number for this analysis
|
|
128
|
+
* @param onComplete - Optional callback to invoke when analysis completes (after block is mined)
|
|
129
|
+
* @returns The analysis result (incomplete until block mines), or undefined if no requests
|
|
130
|
+
*/ async analyzeL1Fees(l2SlotNumber, onComplete) {
|
|
131
|
+
if (!this.l1FeeAnalyzer) {
|
|
132
|
+
this.log.warn('L1 fee analyzer not available (not in fisherman mode)');
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const requestsToAnalyze = [
|
|
136
|
+
...this.requests
|
|
137
|
+
];
|
|
138
|
+
if (requestsToAnalyze.length === 0) {
|
|
139
|
+
this.log.debug('No requests to analyze for L1 fees');
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
// Extract blob config from requests (if any)
|
|
143
|
+
const blobConfigs = requestsToAnalyze.filter((request)=>request.blobConfig).map((request)=>request.blobConfig);
|
|
144
|
+
const blobConfig = blobConfigs[0];
|
|
145
|
+
// Get gas configs
|
|
146
|
+
const gasConfigs = requestsToAnalyze.filter((request)=>request.gasConfig).map((request)=>request.gasConfig);
|
|
147
|
+
const gasLimits = gasConfigs.map((g)=>g?.gasLimit).filter((g)=>g !== undefined);
|
|
148
|
+
const gasLimit = gasLimits.length > 0 ? gasLimits.reduce((sum, g)=>sum + g, 0n) : 0n;
|
|
149
|
+
// Get the transaction requests
|
|
150
|
+
const l1Requests = requestsToAnalyze.map((r)=>r.request);
|
|
151
|
+
// Start the analysis
|
|
152
|
+
const analysisId = await this.l1FeeAnalyzer.startAnalysis(l2SlotNumber, gasLimit > 0n ? gasLimit : SequencerPublisher.PROPOSE_GAS_GUESS, l1Requests, blobConfig, onComplete);
|
|
153
|
+
this.log.info('Started L1 fee analysis', {
|
|
154
|
+
analysisId,
|
|
155
|
+
l2SlotNumber: l2SlotNumber.toString(),
|
|
156
|
+
requestCount: requestsToAnalyze.length,
|
|
157
|
+
hasBlobConfig: !!blobConfig,
|
|
158
|
+
gasLimit: gasLimit.toString(),
|
|
159
|
+
actions: requestsToAnalyze.map((r)=>r.action)
|
|
160
|
+
});
|
|
161
|
+
// Return the analysis result (will be incomplete until block mines)
|
|
162
|
+
return this.l1FeeAnalyzer.getAnalysis(analysisId);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
114
165
|
* Sends all requests that are still valid.
|
|
115
166
|
* @returns one of:
|
|
116
167
|
* - A receipt and stats if the tx succeeded
|
|
@@ -121,7 +172,7 @@ export class SequencerPublisher {
|
|
|
121
172
|
...this.requests
|
|
122
173
|
];
|
|
123
174
|
this.requests = [];
|
|
124
|
-
if (this.interrupted) {
|
|
175
|
+
if (this.interrupted || requestsToProcess.length === 0) {
|
|
125
176
|
return undefined;
|
|
126
177
|
}
|
|
127
178
|
const currentL2Slot = this.getCurrentL2Slot();
|
|
@@ -380,34 +431,29 @@ export class SequencerPublisher {
|
|
|
380
431
|
throw new Error(`Unknown reason for invalidation`);
|
|
381
432
|
}
|
|
382
433
|
}
|
|
383
|
-
/**
|
|
384
|
-
* @notice Will simulate `propose` to make sure that the block is valid for submission
|
|
385
|
-
*
|
|
386
|
-
* @dev Throws if unable to propose
|
|
387
|
-
*
|
|
388
|
-
* @param block - The block to propose
|
|
389
|
-
* @param attestationData - The block's attestation data
|
|
390
|
-
*
|
|
391
|
-
*/ async validateBlockForSubmission(block, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
434
|
+
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, options) {
|
|
392
435
|
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
436
|
+
// TODO(palla/mbps): This should not be needed, there's no flow where we propose with zero attestations. Or is there?
|
|
393
437
|
// If we have no attestations, we still need to provide the empty attestations
|
|
394
438
|
// so that the committee is recalculated correctly
|
|
395
|
-
const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
396
|
-
if (ignoreSignatures) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
439
|
+
// const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
440
|
+
// if (ignoreSignatures) {
|
|
441
|
+
// const { committee } = await this.epochCache.getCommittee(block.header.globalVariables.slotNumber);
|
|
442
|
+
// if (!committee) {
|
|
443
|
+
// this.log.warn(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
444
|
+
// throw new Error(`No committee found for slot ${block.header.globalVariables.slotNumber}`);
|
|
445
|
+
// }
|
|
446
|
+
// attestationsAndSigners.attestations = committee.map(committeeMember =>
|
|
447
|
+
// CommitteeAttestation.fromAddress(committeeMember),
|
|
448
|
+
// );
|
|
449
|
+
// }
|
|
450
|
+
const blobFields = checkpoint.toBlobFields();
|
|
405
451
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
406
452
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
407
453
|
const args = [
|
|
408
454
|
{
|
|
409
|
-
header:
|
|
410
|
-
archive: toHex(
|
|
455
|
+
header: checkpoint.header.toViem(),
|
|
456
|
+
archive: toHex(checkpoint.archive.root.toBuffer()),
|
|
411
457
|
oracleInput: {
|
|
412
458
|
feeAssetPriceModifier: 0n
|
|
413
459
|
}
|
|
@@ -434,9 +480,16 @@ export class SequencerPublisher {
|
|
|
434
480
|
}
|
|
435
481
|
const round = await base.computeRound(slotNumber);
|
|
436
482
|
const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
|
|
483
|
+
if (roundInfo.quorumReached) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
437
486
|
if (roundInfo.lastSignalSlot >= slotNumber) {
|
|
438
487
|
return false;
|
|
439
488
|
}
|
|
489
|
+
if (await this.isPayloadEmpty(payload)) {
|
|
490
|
+
this.log.warn(`Skipping vote cast for payload with empty code`);
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
440
493
|
const cachedLastVote = this.lastActions[signalType];
|
|
441
494
|
this.lastActions[signalType] = slotNumber;
|
|
442
495
|
const action = signalType;
|
|
@@ -475,17 +528,27 @@ export class SequencerPublisher {
|
|
|
475
528
|
payload: payload.toString()
|
|
476
529
|
};
|
|
477
530
|
if (!success) {
|
|
478
|
-
this.log.error(`Signaling in
|
|
531
|
+
this.log.error(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
|
|
479
532
|
this.lastActions[signalType] = cachedLastVote;
|
|
480
533
|
return false;
|
|
481
534
|
} else {
|
|
482
|
-
this.log.info(`Signaling in
|
|
535
|
+
this.log.info(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
|
|
483
536
|
return true;
|
|
484
537
|
}
|
|
485
538
|
}
|
|
486
539
|
});
|
|
487
540
|
return true;
|
|
488
541
|
}
|
|
542
|
+
async isPayloadEmpty(payload) {
|
|
543
|
+
const key = payload.toString();
|
|
544
|
+
const cached = this.isPayloadEmptyCache.get(key);
|
|
545
|
+
if (cached) {
|
|
546
|
+
return cached;
|
|
547
|
+
}
|
|
548
|
+
const isEmpty = !await this.l1TxUtils.getCode(payload);
|
|
549
|
+
this.isPayloadEmptyCache.set(key, isEmpty);
|
|
550
|
+
return isEmpty;
|
|
551
|
+
}
|
|
489
552
|
/**
|
|
490
553
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
491
554
|
* @param slotNumber - The slot number to cast a signal for.
|
|
@@ -581,19 +644,13 @@ export class SequencerPublisher {
|
|
|
581
644
|
}
|
|
582
645
|
return true;
|
|
583
646
|
}
|
|
584
|
-
/**
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
* @param block - L2 block to propose.
|
|
588
|
-
* @returns True if the tx has been enqueued, throws otherwise. See #9315
|
|
589
|
-
*/ async enqueueProposeL2Block(block, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
590
|
-
const checkpointHeader = block.getCheckpointHeader();
|
|
591
|
-
const blobFields = block.getCheckpointBlobFields();
|
|
647
|
+
/** Simulates and enqueues a proposal for a checkpoint on L1 */ async enqueueProposeCheckpoint(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
648
|
+
const checkpointHeader = checkpoint.header;
|
|
649
|
+
const blobFields = checkpoint.toBlobFields();
|
|
592
650
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
593
651
|
const proposeTxArgs = {
|
|
594
652
|
header: checkpointHeader,
|
|
595
|
-
archive:
|
|
596
|
-
body: block.body.toBuffer(),
|
|
653
|
+
archive: checkpoint.archive.root.toBuffer(),
|
|
597
654
|
blobs,
|
|
598
655
|
attestationsAndSigners,
|
|
599
656
|
attestationsAndSignersSignature
|
|
@@ -605,21 +662,20 @@ export class SequencerPublisher {
|
|
|
605
662
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
606
663
|
// make time consistency checks break.
|
|
607
664
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
608
|
-
ts = await this.
|
|
665
|
+
ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
|
|
609
666
|
} catch (err) {
|
|
610
|
-
this.log.error(`
|
|
611
|
-
...
|
|
612
|
-
slotNumber:
|
|
667
|
+
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
668
|
+
...checkpoint.getStats(),
|
|
669
|
+
slotNumber: checkpoint.header.slotNumber,
|
|
613
670
|
forcePendingBlockNumber: opts.forcePendingBlockNumber
|
|
614
671
|
});
|
|
615
672
|
throw err;
|
|
616
673
|
}
|
|
617
|
-
this.log.verbose(`Enqueuing
|
|
618
|
-
...
|
|
674
|
+
this.log.verbose(`Enqueuing checkpoint propose transaction`, {
|
|
675
|
+
...checkpoint.toCheckpointInfo(),
|
|
619
676
|
...opts
|
|
620
677
|
});
|
|
621
|
-
await this.addProposeTx(
|
|
622
|
-
return true;
|
|
678
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
623
679
|
}
|
|
624
680
|
enqueueInvalidateBlock(request, opts = {}) {
|
|
625
681
|
if (!request) {
|
|
@@ -857,24 +913,25 @@ export class SequencerPublisher {
|
|
|
857
913
|
simulationResult
|
|
858
914
|
};
|
|
859
915
|
}
|
|
860
|
-
async addProposeTx(
|
|
916
|
+
async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
|
|
917
|
+
const slot = checkpoint.header.slotNumber;
|
|
861
918
|
const timer = new Timer();
|
|
862
919
|
const kzg = Blob.getViemKzgInstance();
|
|
863
920
|
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
|
|
864
921
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
865
922
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
|
|
866
|
-
// Send the blobs to the blob
|
|
867
|
-
// tx fails but it does get mined. We make sure that the blobs are sent to the blob
|
|
868
|
-
void this.
|
|
869
|
-
|
|
870
|
-
|
|
923
|
+
// Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
|
|
924
|
+
// tx fails but it does get mined. We make sure that the blobs are sent to the blob client regardless of the tx outcome.
|
|
925
|
+
void Promise.resolve().then(()=>this.blobClient.sendBlobsToFilestore(encodedData.blobs).catch((_err)=>{
|
|
926
|
+
this.log.error('Failed to send blobs to blob client');
|
|
927
|
+
}));
|
|
871
928
|
return this.addRequest({
|
|
872
929
|
action: 'propose',
|
|
873
930
|
request: {
|
|
874
931
|
to: this.rollupContract.address,
|
|
875
932
|
data: rollupData
|
|
876
933
|
},
|
|
877
|
-
lastValidL2Slot:
|
|
934
|
+
lastValidL2Slot: checkpoint.header.slotNumber,
|
|
878
935
|
gasConfig: {
|
|
879
936
|
...opts,
|
|
880
937
|
gasLimit
|
|
@@ -902,25 +959,23 @@ export class SequencerPublisher {
|
|
|
902
959
|
calldataGas,
|
|
903
960
|
calldataSize,
|
|
904
961
|
sender,
|
|
905
|
-
...
|
|
962
|
+
...checkpoint.getStats(),
|
|
906
963
|
eventName: 'rollup-published-to-l1',
|
|
907
964
|
blobCount: encodedData.blobs.length,
|
|
908
965
|
inclusionBlocks
|
|
909
966
|
};
|
|
910
|
-
this.log.info(`Published
|
|
967
|
+
this.log.info(`Published checkpoint ${checkpoint.number} at slot ${slot} to rollup contract`, {
|
|
911
968
|
...stats,
|
|
912
|
-
...
|
|
913
|
-
...receipt
|
|
969
|
+
...checkpoint.getStats(),
|
|
970
|
+
...pick(receipt, 'transactionHash', 'blockHash')
|
|
914
971
|
});
|
|
915
972
|
this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
|
|
916
973
|
return true;
|
|
917
974
|
} else {
|
|
918
975
|
this.metrics.recordFailedTx('process');
|
|
919
|
-
this.log.error(`
|
|
920
|
-
...
|
|
921
|
-
receipt
|
|
922
|
-
txHash: receipt.transactionHash,
|
|
923
|
-
slotNumber: block.header.globalVariables.slotNumber
|
|
976
|
+
this.log.error(`Publishing checkpoint at slot ${slot} failed with ${errorMsg ?? 'no error message'}`, undefined, {
|
|
977
|
+
...checkpoint.getStats(),
|
|
978
|
+
...receipt
|
|
924
979
|
});
|
|
925
980
|
return false;
|
|
926
981
|
}
|
|
@@ -3,11 +3,9 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
3
3
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
4
4
|
import { PublicProcessor } from '@aztec/simulator/server';
|
|
5
5
|
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
6
|
-
import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
7
6
|
import type { BuildBlockResult, FullNodeBlockBuilderConfig, IFullNodeBlockBuilder, MerkleTreeWriteOperations, PublicProcessorLimits, PublicProcessorValidator, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
8
7
|
import { GlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
9
8
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
10
|
-
export declare function buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, l1ToL2Messages: Fr[], newGlobalVariables: GlobalVariables, opts: PublicProcessorLimits | undefined, worldStateFork: MerkleTreeWriteOperations, processor: PublicProcessor, validator: PublicProcessorValidator, l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'>, dateProvider: DateProvider, telemetryClient?: TelemetryClient): Promise<BuildBlockResult>;
|
|
11
9
|
export declare class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
|
|
12
10
|
private config;
|
|
13
11
|
private worldState;
|
|
@@ -25,4 +23,4 @@ export declare class FullNodeBlockBuilder implements IFullNodeBlockBuilder {
|
|
|
25
23
|
buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, l1ToL2Messages: Fr[], globalVariables: GlobalVariables, opts: PublicProcessorLimits, suppliedFork?: MerkleTreeWriteOperations): Promise<BuildBlockResult>;
|
|
26
24
|
getFork(blockNumber: BlockNumber): Promise<MerkleTreeWriteOperations>;
|
|
27
25
|
}
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfYnVpbGRlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcXVlbmNlci9ibG9ja19idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUU5RCxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUl6RCxPQUFPLEVBQUUsWUFBWSxFQUFrQixNQUFNLHlCQUF5QixDQUFDO0FBR3ZFLE9BQU8sRUFHTCxlQUFlLEVBRWhCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUdqRSxPQUFPLEtBQUssRUFDVixnQkFBZ0IsRUFDaEIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFDdkIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQTJFbkYscUJBQWEsb0JBQXFCLFlBQVcscUJBQXFCO0lBRTlELE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLFVBQVU7SUFDbEIsT0FBTyxDQUFDLGtCQUFrQjtJQUMxQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsZUFBZTtJQUx6QixZQUNVLE1BQU0sRUFBRSwwQkFBMEIsRUFDbEMsVUFBVSxFQUFFLHNCQUFzQixFQUNsQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEVBQzdEO0lBRUcsU0FBUyxJQUFJLDBCQUEwQixDQUU3QztJQUVNLFlBQVksQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLDBCQUEwQixDQUFDLFFBRTlEO0lBRVksb0JBQW9CLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUseUJBQXlCOzs7T0FrQ2xHO1lBRWEsbUJBQW1CO0lBVTNCLFVBQVUsQ0FDZCxVQUFVLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxFQUFFLENBQUMsRUFDNUMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixlQUFlLEVBQUUsZUFBZSxFQUNoQyxJQUFJLEVBQUUscUJBQXFCLEVBQzNCLFlBQVksQ0FBQyxFQUFFLHlCQUF5QixHQUN2QyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FzQzNCO0lBRUQsT0FBTyxDQUFDLFdBQVcsRUFBRSxXQUFXLEdBQUcsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBRXBFO0NBQ0YifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/block_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAGvE,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"block_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/block_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIzD,OAAO,EAAE,YAAY,EAAkB,MAAM,yBAAyB,CAAC;AAGvE,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,KAAK,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AA2EnF,qBAAa,oBAAqB,YAAW,qBAAqB;IAE9D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IALzB,YACU,MAAM,EAAE,0BAA0B,EAClC,UAAU,EAAE,sBAAsB,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,SAAS,IAAI,0BAA0B,CAE7C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAEY,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkClG;YAEa,mBAAmB;IAU3B,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,cAAc,EAAE,EAAE,EAAE,EACpB,eAAe,EAAE,eAAe,EAChC,IAAI,EAAE,qBAAqB,EAC3B,YAAY,CAAC,EAAE,yBAAyB,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAsC3B;IAED,OAAO,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAEpE;CACF"}
|
|
@@ -13,7 +13,7 @@ import { Gas } from '@aztec/stdlib/gas';
|
|
|
13
13
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
14
14
|
import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
|
|
15
15
|
const log = createLogger('block-builder');
|
|
16
|
-
|
|
16
|
+
/** Builds a block out of pending txs */ async function buildBlock(pendingTxs, l1ToL2Messages, newGlobalVariables, opts = {}, worldStateFork, processor, validator, l1Constants, dateProvider, telemetryClient = getTelemetryClient()) {
|
|
17
17
|
const blockBuildingTimer = new Timer();
|
|
18
18
|
const blockNumber = newGlobalVariables.blockNumber;
|
|
19
19
|
const slot = newGlobalVariables.slotNumber;
|
|
@@ -57,8 +57,10 @@ const FullNodeBlockBuilderConfigKeys = [
|
|
|
57
57
|
'l1ChainId',
|
|
58
58
|
'rollupVersion',
|
|
59
59
|
'txPublicSetupAllowList',
|
|
60
|
-
'fakeProcessingDelayPerTxMs'
|
|
60
|
+
'fakeProcessingDelayPerTxMs',
|
|
61
|
+
'fakeThrowAfterProcessingTxCount'
|
|
61
62
|
];
|
|
63
|
+
// TODO(palla/mbps): Try killing this in favor of the CheckpointsBuilder
|
|
62
64
|
export class FullNodeBlockBuilder {
|
|
63
65
|
config;
|
|
64
66
|
worldState;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
4
|
+
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
5
|
+
import { PublicProcessor } from '@aztec/simulator/server';
|
|
6
|
+
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
7
|
+
import { Checkpoint } from '@aztec/stdlib/checkpoint';
|
|
8
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
9
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
10
|
+
import { type FullNodeBlockBuilderConfig, type MerkleTreeWriteOperations, type PublicProcessorLimits } from '@aztec/stdlib/interfaces/server';
|
|
11
|
+
import { type CheckpointGlobalVariables, type FailedTx, GlobalVariables, Tx } from '@aztec/stdlib/tx';
|
|
12
|
+
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
13
|
+
export interface BuildBlockInCheckpointResult {
|
|
14
|
+
block: L2BlockNew;
|
|
15
|
+
publicGas: Gas;
|
|
16
|
+
publicProcessorDuration: number;
|
|
17
|
+
numTxs: number;
|
|
18
|
+
failedTxs: FailedTx[];
|
|
19
|
+
blockBuildingTimer: Timer;
|
|
20
|
+
usedTxs: Tx[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
24
|
+
* and completing it.
|
|
25
|
+
*/
|
|
26
|
+
export declare class CheckpointBuilder {
|
|
27
|
+
private checkpointBuilder;
|
|
28
|
+
private fork;
|
|
29
|
+
private config;
|
|
30
|
+
private contractDataSource;
|
|
31
|
+
private dateProvider;
|
|
32
|
+
private telemetryClient;
|
|
33
|
+
constructor(checkpointBuilder: LightweightCheckpointBuilder, fork: MerkleTreeWriteOperations, config: FullNodeBlockBuilderConfig, contractDataSource: ContractDataSource, dateProvider: DateProvider, telemetryClient: TelemetryClient);
|
|
34
|
+
getConstantData(): CheckpointGlobalVariables;
|
|
35
|
+
/**
|
|
36
|
+
* Builds a single block within this checkpoint.
|
|
37
|
+
*/
|
|
38
|
+
buildBlock(pendingTxs: Iterable<Tx> | AsyncIterable<Tx>, blockNumber: BlockNumber, timestamp: bigint, opts: PublicProcessorLimits): Promise<BuildBlockInCheckpointResult>;
|
|
39
|
+
/** Completes the checkpoint and returns it. */
|
|
40
|
+
completeCheckpoint(): Promise<Checkpoint>;
|
|
41
|
+
/** Gets the checkpoint currently in progress. */
|
|
42
|
+
getCheckpoint(): Promise<Checkpoint>;
|
|
43
|
+
protected makeBlockBuilderDeps(globalVariables: GlobalVariables, fork: MerkleTreeWriteOperations): Promise<{
|
|
44
|
+
processor: PublicProcessor;
|
|
45
|
+
validator: import("@aztec/stdlib/interfaces/server").PublicProcessorValidator;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Factory for creating checkpoint builders.
|
|
50
|
+
*/
|
|
51
|
+
export declare class FullNodeCheckpointsBuilder {
|
|
52
|
+
private config;
|
|
53
|
+
private contractDataSource;
|
|
54
|
+
private dateProvider;
|
|
55
|
+
private telemetryClient;
|
|
56
|
+
constructor(config: FullNodeBlockBuilderConfig, contractDataSource: ContractDataSource, dateProvider: DateProvider, telemetryClient?: TelemetryClient);
|
|
57
|
+
updateConfig(config: Partial<FullNodeBlockBuilderConfig>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Starts a new checkpoint and returns a CheckpointBuilder to build blocks within it.
|
|
60
|
+
*/
|
|
61
|
+
startCheckpoint(checkpointNumber: CheckpointNumber, constants: CheckpointGlobalVariables, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations): Promise<CheckpointBuilder>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludF9idWlsZGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2NoZWNrcG9pbnRfYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFaEYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBR3BELE9BQU8sRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkUsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUUsT0FBTyxFQUdMLGVBQWUsRUFFaEIsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3RELE9BQU8sS0FBSyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDakUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3hDLE9BQU8sRUFDTCxLQUFLLDBCQUEwQixFQUUvQixLQUFLLHlCQUF5QixFQUM5QixLQUFLLHFCQUFxQixFQUMzQixNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxLQUFLLHlCQUF5QixFQUFFLEtBQUssUUFBUSxFQUFFLGVBQWUsRUFBRSxFQUFFLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUN0RyxPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFNbkYsTUFBTSxXQUFXLDRCQUE0QjtJQUMzQyxLQUFLLEVBQUUsVUFBVSxDQUFDO0lBQ2xCLFNBQVMsRUFBRSxHQUFHLENBQUM7SUFDZix1QkFBdUIsRUFBRSxNQUFNLENBQUM7SUFDaEMsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNmLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBQztJQUN0QixrQkFBa0IsRUFBRSxLQUFLLENBQUM7SUFDMUIsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDO0NBQ2Y7QUFFRDs7O0dBR0c7QUFDSCxxQkFBYSxpQkFBaUI7SUFFMUIsT0FBTyxDQUFDLGlCQUFpQjtJQUN6QixPQUFPLENBQUMsSUFBSTtJQUNaLE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLGtCQUFrQjtJQUMxQixPQUFPLENBQUMsWUFBWTtJQUNwQixPQUFPLENBQUMsZUFBZTtJQU56QixZQUNVLGlCQUFpQixFQUFFLDRCQUE0QixFQUMvQyxJQUFJLEVBQUUseUJBQXlCLEVBQy9CLE1BQU0sRUFBRSwwQkFBMEIsRUFDbEMsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQ3RDLFlBQVksRUFBRSxZQUFZLEVBQzFCLGVBQWUsRUFBRSxlQUFlLEVBQ3RDO0lBRUosZUFBZSxJQUFJLHlCQUF5QixDQUUzQztJQUVEOztPQUVHO0lBQ0csVUFBVSxDQUNkLFVBQVUsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLEVBQUUsQ0FBQyxFQUM1QyxXQUFXLEVBQUUsV0FBVyxFQUN4QixTQUFTLEVBQUUsTUFBTSxFQUNqQixJQUFJLEVBQUUscUJBQXFCLEdBQzFCLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQyxDQXdDdkM7SUFFRCwrQ0FBK0M7SUFDekMsa0JBQWtCLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQVU5QztJQUVELGlEQUFpRDtJQUNqRCxhQUFhLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUVuQztJQUVELFVBQWdCLG9CQUFvQixDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLHlCQUF5Qjs7O09Ba0NyRztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxxQkFBYSwwQkFBMEI7SUFFbkMsT0FBTyxDQUFDLE1BQU07SUFDZCxPQUFPLENBQUMsa0JBQWtCO0lBQzFCLE9BQU8sQ0FBQyxZQUFZO0lBQ3BCLE9BQU8sQ0FBQyxlQUFlO0lBSnpCLFlBQ1UsTUFBTSxFQUFFLDBCQUEwQixFQUNsQyxrQkFBa0IsRUFBRSxrQkFBa0IsRUFDdEMsWUFBWSxFQUFFLFlBQVksRUFDMUIsZUFBZSxHQUFFLGVBQXNDLEVBQzdEO0lBRUcsWUFBWSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsMEJBQTBCLENBQUMsUUFFOUQ7SUFFRDs7T0FFRztJQUNHLGVBQWUsQ0FDbkIsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQ2xDLFNBQVMsRUFBRSx5QkFBeUIsRUFDcEMsY0FBYyxFQUFFLEVBQUUsRUFBRSxFQUNwQixJQUFJLEVBQUUseUJBQXlCLEdBQzlCLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxDQTJCNUI7Q0FDRiJ9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint_builder.d.ts","sourceRoot":"","sources":["../../src/sequencer/checkpoint_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,KAAK,EAAW,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAGL,eAAe,EAEhB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EACL,KAAK,0BAA0B,EAE/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC3B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,QAAQ,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtG,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,yBAAyB,CAAC;AAMnF,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,GAAG,CAAC;IACf,uBAAuB,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,kBAAkB,EAAE,KAAK,CAAC;IAC1B,OAAO,EAAE,EAAE,EAAE,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IANzB,YACU,iBAAiB,EAAE,4BAA4B,EAC/C,IAAI,EAAE,yBAAyB,EAC/B,MAAM,EAAE,0BAA0B,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,EAAE,eAAe,EACtC;IAEJ,eAAe,IAAI,yBAAyB,CAE3C;IAED;;OAEG;IACG,UAAU,CACd,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,EAAE,CAAC,EAC5C,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,4BAA4B,CAAC,CAwCvC;IAED,+CAA+C;IACzC,kBAAkB,IAAI,OAAO,CAAC,UAAU,CAAC,CAU9C;IAED,iDAAiD;IACjD,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAEnC;IAED,UAAgB,oBAAoB,CAAC,eAAe,EAAE,eAAe,EAAE,IAAI,EAAE,yBAAyB;;;OAkCrG;CACF;AAED;;GAEG;AACH,qBAAa,0BAA0B;IAEnC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,eAAe;IAJzB,YACU,MAAM,EAAE,0BAA0B,EAClC,kBAAkB,EAAE,kBAAkB,EACtC,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAsC,EAC7D;IAEG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAE9D;IAED;;OAEG;IACG,eAAe,CACnB,gBAAgB,EAAE,gBAAgB,EAClC,SAAS,EAAE,yBAAyB,EACpC,cAAc,EAAE,EAAE,EAAE,EACpB,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CA2B5B;CACF"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { MerkleTreeId } from '@aztec/aztec.js/trees';
|
|
2
|
+
import { merge, pick } from '@aztec/foundation/collection';
|
|
3
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { bufferToHex } from '@aztec/foundation/string';
|
|
5
|
+
import { Timer, elapsed } from '@aztec/foundation/timer';
|
|
6
|
+
import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
7
|
+
import { LightweightCheckpointBuilder } from '@aztec/prover-client/light';
|
|
8
|
+
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, createPublicTxSimulatorForBlockBuilding } from '@aztec/simulator/server';
|
|
9
|
+
import { Gas } from '@aztec/stdlib/gas';
|
|
10
|
+
import { FullNodeBlockBuilderConfigKeys } from '@aztec/stdlib/interfaces/server';
|
|
11
|
+
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
12
|
+
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
13
|
+
import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
|
|
14
|
+
const log = createLogger('checkpoint-builder');
|
|
15
|
+
/**
|
|
16
|
+
* Builder for a single checkpoint. Handles building blocks within the checkpoint
|
|
17
|
+
* and completing it.
|
|
18
|
+
*/ export class CheckpointBuilder {
|
|
19
|
+
checkpointBuilder;
|
|
20
|
+
fork;
|
|
21
|
+
config;
|
|
22
|
+
contractDataSource;
|
|
23
|
+
dateProvider;
|
|
24
|
+
telemetryClient;
|
|
25
|
+
constructor(checkpointBuilder, fork, config, contractDataSource, dateProvider, telemetryClient){
|
|
26
|
+
this.checkpointBuilder = checkpointBuilder;
|
|
27
|
+
this.fork = fork;
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.contractDataSource = contractDataSource;
|
|
30
|
+
this.dateProvider = dateProvider;
|
|
31
|
+
this.telemetryClient = telemetryClient;
|
|
32
|
+
}
|
|
33
|
+
getConstantData() {
|
|
34
|
+
return this.checkpointBuilder.constants;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Builds a single block within this checkpoint.
|
|
38
|
+
*/ async buildBlock(pendingTxs, blockNumber, timestamp, opts) {
|
|
39
|
+
const blockBuildingTimer = new Timer();
|
|
40
|
+
const slot = this.checkpointBuilder.constants.slotNumber;
|
|
41
|
+
log.verbose(`Building block ${blockNumber} for slot ${slot} within checkpoint`, {
|
|
42
|
+
slot,
|
|
43
|
+
blockNumber,
|
|
44
|
+
...opts
|
|
45
|
+
});
|
|
46
|
+
const constants = this.checkpointBuilder.constants;
|
|
47
|
+
const globalVariables = GlobalVariables.from({
|
|
48
|
+
chainId: constants.chainId,
|
|
49
|
+
version: constants.version,
|
|
50
|
+
blockNumber,
|
|
51
|
+
slotNumber: constants.slotNumber,
|
|
52
|
+
timestamp,
|
|
53
|
+
coinbase: constants.coinbase,
|
|
54
|
+
feeRecipient: constants.feeRecipient,
|
|
55
|
+
gasFees: constants.gasFees
|
|
56
|
+
});
|
|
57
|
+
const { processor, validator } = await this.makeBlockBuilderDeps(globalVariables, this.fork);
|
|
58
|
+
const [publicProcessorDuration, [processedTxs, failedTxs, usedTxs]] = await elapsed(()=>processor.process(pendingTxs, opts, validator));
|
|
59
|
+
// Add block to checkpoint
|
|
60
|
+
const block = await this.checkpointBuilder.addBlock(globalVariables, processedTxs);
|
|
61
|
+
// How much public gas was processed
|
|
62
|
+
const publicGas = processedTxs.reduce((acc, tx)=>acc.add(tx.gasUsed.publicGas), Gas.empty());
|
|
63
|
+
const res = {
|
|
64
|
+
block,
|
|
65
|
+
publicGas,
|
|
66
|
+
publicProcessorDuration,
|
|
67
|
+
numTxs: processedTxs.length,
|
|
68
|
+
failedTxs,
|
|
69
|
+
blockBuildingTimer,
|
|
70
|
+
usedTxs
|
|
71
|
+
};
|
|
72
|
+
log.debug('Built block within checkpoint', res.block.header);
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
/** Completes the checkpoint and returns it. */ async completeCheckpoint() {
|
|
76
|
+
const checkpoint = await this.checkpointBuilder.completeCheckpoint();
|
|
77
|
+
log.verbose(`Completed checkpoint ${checkpoint.number}`, {
|
|
78
|
+
checkpointNumber: checkpoint.number,
|
|
79
|
+
numBlocks: checkpoint.blocks.length,
|
|
80
|
+
archiveRoot: checkpoint.archive.root.toString()
|
|
81
|
+
});
|
|
82
|
+
return checkpoint;
|
|
83
|
+
}
|
|
84
|
+
/** Gets the checkpoint currently in progress. */ getCheckpoint() {
|
|
85
|
+
return this.checkpointBuilder.clone().completeCheckpoint();
|
|
86
|
+
}
|
|
87
|
+
async makeBlockBuilderDeps(globalVariables, fork) {
|
|
88
|
+
const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
89
|
+
const contractsDB = new PublicContractsDB(this.contractDataSource);
|
|
90
|
+
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
91
|
+
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(guardedFork, contractsDB, globalVariables, this.telemetryClient);
|
|
92
|
+
const processor = new PublicProcessor(globalVariables, guardedFork, contractsDB, publicTxSimulator, this.dateProvider, this.telemetryClient, undefined, this.config);
|
|
93
|
+
const validator = createValidatorForBlockBuilding(fork, this.contractDataSource, globalVariables, txPublicSetupAllowList);
|
|
94
|
+
return {
|
|
95
|
+
processor,
|
|
96
|
+
validator
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Factory for creating checkpoint builders.
|
|
102
|
+
*/ export class FullNodeCheckpointsBuilder {
|
|
103
|
+
config;
|
|
104
|
+
contractDataSource;
|
|
105
|
+
dateProvider;
|
|
106
|
+
telemetryClient;
|
|
107
|
+
constructor(config, contractDataSource, dateProvider, telemetryClient = getTelemetryClient()){
|
|
108
|
+
this.config = config;
|
|
109
|
+
this.contractDataSource = contractDataSource;
|
|
110
|
+
this.dateProvider = dateProvider;
|
|
111
|
+
this.telemetryClient = telemetryClient;
|
|
112
|
+
}
|
|
113
|
+
updateConfig(config) {
|
|
114
|
+
this.config = merge(this.config, pick(config, ...FullNodeBlockBuilderConfigKeys));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Starts a new checkpoint and returns a CheckpointBuilder to build blocks within it.
|
|
118
|
+
*/ async startCheckpoint(checkpointNumber, constants, l1ToL2Messages, fork) {
|
|
119
|
+
const stateReference = await fork.getStateReference();
|
|
120
|
+
const archiveTree = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
121
|
+
log.verbose(`Building checkpoint ${checkpointNumber}`, {
|
|
122
|
+
checkpointNumber,
|
|
123
|
+
msgCount: l1ToL2Messages.length,
|
|
124
|
+
initialStateReference: stateReference.toInspect(),
|
|
125
|
+
initialArchiveRoot: bufferToHex(archiveTree.root),
|
|
126
|
+
constants
|
|
127
|
+
});
|
|
128
|
+
const lightweightBuilder = await LightweightCheckpointBuilder.startNewCheckpoint(checkpointNumber, constants, l1ToL2Messages, fork);
|
|
129
|
+
return new CheckpointBuilder(lightweightBuilder, fork, this.config, this.contractDataSource, this.dateProvider, this.telemetryClient);
|
|
130
|
+
}
|
|
131
|
+
}
|