@aztec/sequencer-client 0.0.1-commit.d3ec352c → 0.0.1-commit.fcb71a6
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 +10 -9
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +32 -25
- package/dest/config.d.ts +12 -5
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +68 -30
- package/dest/global_variable_builder/global_builder.d.ts +18 -9
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +39 -29
- 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 +7 -4
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +9 -3
- package/dest/publisher/sequencer-publisher-factory.d.ts +5 -4
- 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 +32 -25
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +122 -65
- package/dest/sequencer/block_builder.d.ts +2 -4
- package/dest/sequencer/block_builder.d.ts.map +1 -1
- package/dest/sequencer/block_builder.js +6 -11
- 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/config.d.ts +3 -2
- package/dest/sequencer/config.d.ts.map +1 -1
- 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 +22 -2
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +154 -0
- package/dest/sequencer/sequencer.d.ts +93 -127
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +218 -574
- 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 +4 -2
- 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/dest/tx_validator/tx_validator_factory.js +1 -1
- package/package.json +27 -27
- package/src/client/sequencer-client.ts +28 -38
- package/src/config.ts +73 -34
- package/src/global_variable_builder/global_builder.ts +52 -48
- package/src/index.ts +2 -0
- package/src/publisher/config.ts +12 -9
- package/src/publisher/sequencer-publisher-factory.ts +5 -4
- package/src/publisher/sequencer-publisher-metrics.ts +2 -2
- package/src/publisher/sequencer-publisher.ts +180 -84
- package/src/sequencer/README.md +531 -0
- package/src/sequencer/block_builder.ts +7 -12
- 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/config.ts +2 -1
- package/src/sequencer/events.ts +27 -0
- package/src/sequencer/index.ts +4 -0
- package/src/sequencer/metrics.ts +203 -1
- package/src/sequencer/sequencer.ts +322 -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 +3 -1
- package/src/test/mock_checkpoint_builder.ts +247 -0
- package/src/test/utils.ts +137 -0
- package/src/tx_validator/tx_validator_factory.ts +1 -1
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { MULTI_CALL_3_ADDRESS, Multicall3, RollupContract } from '@aztec/ethereum/contracts';
|
|
3
|
+
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
4
|
+
import { WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
5
|
+
import { FormattedViemError, formatViemError, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
4
6
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
5
7
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
6
8
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
9
|
+
import { pick } from '@aztec/foundation/collection';
|
|
7
10
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
8
11
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
9
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
@@ -11,7 +14,7 @@ import { bufferToHex } from '@aztec/foundation/string';
|
|
|
11
14
|
import { Timer } from '@aztec/foundation/timer';
|
|
12
15
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
13
16
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
14
|
-
import {
|
|
17
|
+
import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
15
18
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
16
19
|
import { encodeFunctionData, toHex } from 'viem';
|
|
17
20
|
import { SequencerPublisherMetrics } from './sequencer-publisher-metrics.js';
|
|
@@ -36,10 +39,12 @@ export class SequencerPublisher {
|
|
|
36
39
|
governanceLog;
|
|
37
40
|
slashingLog;
|
|
38
41
|
lastActions;
|
|
42
|
+
isPayloadEmptyCache;
|
|
39
43
|
log;
|
|
40
44
|
ethereumSlotDuration;
|
|
41
|
-
|
|
45
|
+
blobClient;
|
|
42
46
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
47
|
+
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
43
48
|
// @note - with blobs, the below estimate seems too large.
|
|
44
49
|
// Total used for full block from int_l1_pub e2e test: 1m (of which 86k is 1x blob)
|
|
45
50
|
// Total used for emptier block from above test: 429k (of which 84k is 1x blob)
|
|
@@ -60,14 +65,13 @@ export class SequencerPublisher {
|
|
|
60
65
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
61
66
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
62
67
|
this.lastActions = {};
|
|
68
|
+
this.isPayloadEmptyCache = new Map();
|
|
63
69
|
this.requests = [];
|
|
64
70
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
65
71
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
66
72
|
this.epochCache = deps.epochCache;
|
|
67
73
|
this.lastActions = deps.lastActions;
|
|
68
|
-
this.
|
|
69
|
-
logger: createLogger('sequencer:blob-sink:client')
|
|
70
|
-
});
|
|
74
|
+
this.blobClient = deps.blobClient;
|
|
71
75
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
72
76
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
73
77
|
this.l1TxUtils = deps.l1TxUtils;
|
|
@@ -80,6 +84,10 @@ export class SequencerPublisher {
|
|
|
80
84
|
this.slashingProposerContract = newSlashingProposer;
|
|
81
85
|
});
|
|
82
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
|
+
}
|
|
83
91
|
}
|
|
84
92
|
getRollupContract() {
|
|
85
93
|
return this.rollupContract;
|
|
@@ -88,6 +96,11 @@ export class SequencerPublisher {
|
|
|
88
96
|
return this.l1TxUtils.getSenderAddress();
|
|
89
97
|
}
|
|
90
98
|
/**
|
|
99
|
+
* Gets the L1 fee analyzer instance (only available in fisherman mode)
|
|
100
|
+
*/ getL1FeeAnalyzer() {
|
|
101
|
+
return this.l1FeeAnalyzer;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
91
104
|
* Sets the proposer address to use for simulations in fisherman mode.
|
|
92
105
|
* @param proposerAddress - The actual proposer's address to use for balance lookups in simulations
|
|
93
106
|
*/ setProposerAddressForSimulation(proposerAddress) {
|
|
@@ -109,6 +122,46 @@ export class SequencerPublisher {
|
|
|
109
122
|
}
|
|
110
123
|
}
|
|
111
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
|
+
/**
|
|
112
165
|
* Sends all requests that are still valid.
|
|
113
166
|
* @returns one of:
|
|
114
167
|
* - A receipt and stats if the tx succeeded
|
|
@@ -119,7 +172,7 @@ export class SequencerPublisher {
|
|
|
119
172
|
...this.requests
|
|
120
173
|
];
|
|
121
174
|
this.requests = [];
|
|
122
|
-
if (this.interrupted) {
|
|
175
|
+
if (this.interrupted || requestsToProcess.length === 0) {
|
|
123
176
|
return undefined;
|
|
124
177
|
}
|
|
125
178
|
const currentL2Slot = this.getCurrentL2Slot();
|
|
@@ -378,34 +431,29 @@ export class SequencerPublisher {
|
|
|
378
431
|
throw new Error(`Unknown reason for invalidation`);
|
|
379
432
|
}
|
|
380
433
|
}
|
|
381
|
-
/**
|
|
382
|
-
* @notice Will simulate `propose` to make sure that the block is valid for submission
|
|
383
|
-
*
|
|
384
|
-
* @dev Throws if unable to propose
|
|
385
|
-
*
|
|
386
|
-
* @param block - The block to propose
|
|
387
|
-
* @param attestationData - The block's attestation data
|
|
388
|
-
*
|
|
389
|
-
*/ 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) {
|
|
390
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?
|
|
391
437
|
// If we have no attestations, we still need to provide the empty attestations
|
|
392
438
|
// so that the committee is recalculated correctly
|
|
393
|
-
const ignoreSignatures = attestationsAndSigners.attestations.length === 0;
|
|
394
|
-
if (ignoreSignatures) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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();
|
|
403
451
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
404
452
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
405
453
|
const args = [
|
|
406
454
|
{
|
|
407
|
-
header:
|
|
408
|
-
archive: toHex(
|
|
455
|
+
header: checkpoint.header.toViem(),
|
|
456
|
+
archive: toHex(checkpoint.archive.root.toBuffer()),
|
|
409
457
|
oracleInput: {
|
|
410
458
|
feeAssetPriceModifier: 0n
|
|
411
459
|
}
|
|
@@ -432,9 +480,16 @@ export class SequencerPublisher {
|
|
|
432
480
|
}
|
|
433
481
|
const round = await base.computeRound(slotNumber);
|
|
434
482
|
const roundInfo = await base.getRoundInfo(this.rollupContract.address, round);
|
|
483
|
+
if (roundInfo.quorumReached) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
435
486
|
if (roundInfo.lastSignalSlot >= slotNumber) {
|
|
436
487
|
return false;
|
|
437
488
|
}
|
|
489
|
+
if (await this.isPayloadEmpty(payload)) {
|
|
490
|
+
this.log.warn(`Skipping vote cast for payload with empty code`);
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
438
493
|
const cachedLastVote = this.lastActions[signalType];
|
|
439
494
|
this.lastActions[signalType] = slotNumber;
|
|
440
495
|
const action = signalType;
|
|
@@ -473,17 +528,27 @@ export class SequencerPublisher {
|
|
|
473
528
|
payload: payload.toString()
|
|
474
529
|
};
|
|
475
530
|
if (!success) {
|
|
476
|
-
this.log.error(`Signaling in
|
|
531
|
+
this.log.error(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} failed`, logData);
|
|
477
532
|
this.lastActions[signalType] = cachedLastVote;
|
|
478
533
|
return false;
|
|
479
534
|
} else {
|
|
480
|
-
this.log.info(`Signaling in
|
|
535
|
+
this.log.info(`Signaling in ${action} for ${payload} at slot ${slotNumber} in round ${round} succeeded`, logData);
|
|
481
536
|
return true;
|
|
482
537
|
}
|
|
483
538
|
}
|
|
484
539
|
});
|
|
485
540
|
return true;
|
|
486
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
|
+
}
|
|
487
552
|
/**
|
|
488
553
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
489
554
|
* @param slotNumber - The slot number to cast a signal for.
|
|
@@ -579,19 +644,13 @@ export class SequencerPublisher {
|
|
|
579
644
|
}
|
|
580
645
|
return true;
|
|
581
646
|
}
|
|
582
|
-
/**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
* @param block - L2 block to propose.
|
|
586
|
-
* @returns True if the tx has been enqueued, throws otherwise. See #9315
|
|
587
|
-
*/ async enqueueProposeL2Block(block, attestationsAndSigners, attestationsAndSignersSignature, opts = {}) {
|
|
588
|
-
const checkpointHeader = block.getCheckpointHeader();
|
|
589
|
-
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();
|
|
590
650
|
const blobs = getBlobsPerL1Block(blobFields);
|
|
591
651
|
const proposeTxArgs = {
|
|
592
652
|
header: checkpointHeader,
|
|
593
|
-
archive:
|
|
594
|
-
body: block.body.toBuffer(),
|
|
653
|
+
archive: checkpoint.archive.root.toBuffer(),
|
|
595
654
|
blobs,
|
|
596
655
|
attestationsAndSigners,
|
|
597
656
|
attestationsAndSignersSignature
|
|
@@ -603,21 +662,20 @@ export class SequencerPublisher {
|
|
|
603
662
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
604
663
|
// make time consistency checks break.
|
|
605
664
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
606
|
-
ts = await this.
|
|
665
|
+
ts = await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, opts);
|
|
607
666
|
} catch (err) {
|
|
608
|
-
this.log.error(`
|
|
609
|
-
...
|
|
610
|
-
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,
|
|
611
670
|
forcePendingBlockNumber: opts.forcePendingBlockNumber
|
|
612
671
|
});
|
|
613
672
|
throw err;
|
|
614
673
|
}
|
|
615
|
-
this.log.verbose(`Enqueuing
|
|
616
|
-
...
|
|
674
|
+
this.log.verbose(`Enqueuing checkpoint propose transaction`, {
|
|
675
|
+
...checkpoint.toCheckpointInfo(),
|
|
617
676
|
...opts
|
|
618
677
|
});
|
|
619
|
-
await this.addProposeTx(
|
|
620
|
-
return true;
|
|
678
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, opts, ts);
|
|
621
679
|
}
|
|
622
680
|
enqueueInvalidateBlock(request, opts = {}) {
|
|
623
681
|
if (!request) {
|
|
@@ -855,24 +913,25 @@ export class SequencerPublisher {
|
|
|
855
913
|
simulationResult
|
|
856
914
|
};
|
|
857
915
|
}
|
|
858
|
-
async addProposeTx(
|
|
916
|
+
async addProposeTx(checkpoint, encodedData, opts = {}, timestamp) {
|
|
917
|
+
const slot = checkpoint.header.slotNumber;
|
|
859
918
|
const timer = new Timer();
|
|
860
919
|
const kzg = Blob.getViemKzgInstance();
|
|
861
920
|
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, timestamp, opts);
|
|
862
921
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
863
922
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
|
|
864
|
-
// Send the blobs to the blob
|
|
865
|
-
// tx fails but it does get mined. We make sure that the blobs are sent to the blob
|
|
866
|
-
void this.
|
|
867
|
-
|
|
868
|
-
|
|
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
|
+
}));
|
|
869
928
|
return this.addRequest({
|
|
870
929
|
action: 'propose',
|
|
871
930
|
request: {
|
|
872
931
|
to: this.rollupContract.address,
|
|
873
932
|
data: rollupData
|
|
874
933
|
},
|
|
875
|
-
lastValidL2Slot:
|
|
934
|
+
lastValidL2Slot: checkpoint.header.slotNumber,
|
|
876
935
|
gasConfig: {
|
|
877
936
|
...opts,
|
|
878
937
|
gasLimit
|
|
@@ -900,25 +959,23 @@ export class SequencerPublisher {
|
|
|
900
959
|
calldataGas,
|
|
901
960
|
calldataSize,
|
|
902
961
|
sender,
|
|
903
|
-
...
|
|
962
|
+
...checkpoint.getStats(),
|
|
904
963
|
eventName: 'rollup-published-to-l1',
|
|
905
964
|
blobCount: encodedData.blobs.length,
|
|
906
965
|
inclusionBlocks
|
|
907
966
|
};
|
|
908
|
-
this.log.info(`Published
|
|
967
|
+
this.log.info(`Published checkpoint ${checkpoint.number} at slot ${slot} to rollup contract`, {
|
|
909
968
|
...stats,
|
|
910
|
-
...
|
|
911
|
-
...receipt
|
|
969
|
+
...checkpoint.getStats(),
|
|
970
|
+
...pick(receipt, 'transactionHash', 'blockHash')
|
|
912
971
|
});
|
|
913
972
|
this.metrics.recordProcessBlockTx(timer.ms(), publishStats);
|
|
914
973
|
return true;
|
|
915
974
|
} else {
|
|
916
975
|
this.metrics.recordFailedTx('process');
|
|
917
|
-
this.log.error(`
|
|
918
|
-
...
|
|
919
|
-
receipt
|
|
920
|
-
txHash: receipt.transactionHash,
|
|
921
|
-
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
|
|
922
979
|
});
|
|
923
980
|
return false;
|
|
924
981
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { Fr } from '@aztec/foundation/
|
|
2
|
+
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,
|
|
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"}
|
|
@@ -7,14 +7,13 @@ import { bufferToHex } from '@aztec/foundation/string';
|
|
|
7
7
|
import { Timer, elapsed } from '@aztec/foundation/timer';
|
|
8
8
|
import { getDefaultAllowedSetupFunctions } from '@aztec/p2p/msg_validators';
|
|
9
9
|
import { LightweightBlockFactory } from '@aztec/prover-client/block-factory';
|
|
10
|
-
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor,
|
|
11
|
-
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
10
|
+
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, createPublicTxSimulatorForBlockBuilding } from '@aztec/simulator/server';
|
|
12
11
|
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
13
12
|
import { Gas } from '@aztec/stdlib/gas';
|
|
14
13
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
15
14
|
import { createValidatorForBlockBuilding } from '../tx_validator/tx_validator_factory.js';
|
|
16
15
|
const log = createLogger('block-builder');
|
|
17
|
-
|
|
16
|
+
/** Builds a block out of pending txs */ async function buildBlock(pendingTxs, l1ToL2Messages, newGlobalVariables, opts = {}, worldStateFork, processor, validator, l1Constants, dateProvider, telemetryClient = getTelemetryClient()) {
|
|
18
17
|
const blockBuildingTimer = new Timer();
|
|
19
18
|
const blockNumber = newGlobalVariables.blockNumber;
|
|
20
19
|
const slot = newGlobalVariables.slotNumber;
|
|
@@ -58,8 +57,10 @@ const FullNodeBlockBuilderConfigKeys = [
|
|
|
58
57
|
'l1ChainId',
|
|
59
58
|
'rollupVersion',
|
|
60
59
|
'txPublicSetupAllowList',
|
|
61
|
-
'fakeProcessingDelayPerTxMs'
|
|
60
|
+
'fakeProcessingDelayPerTxMs',
|
|
61
|
+
'fakeThrowAfterProcessingTxCount'
|
|
62
62
|
];
|
|
63
|
+
// TODO(palla/mbps): Try killing this in favor of the CheckpointsBuilder
|
|
63
64
|
export class FullNodeBlockBuilder {
|
|
64
65
|
config;
|
|
65
66
|
worldState;
|
|
@@ -83,13 +84,7 @@ export class FullNodeBlockBuilder {
|
|
|
83
84
|
const txPublicSetupAllowList = this.config.txPublicSetupAllowList ?? await getDefaultAllowedSetupFunctions();
|
|
84
85
|
const contractsDB = new PublicContractsDB(this.contractDataSource);
|
|
85
86
|
const guardedFork = new GuardedMerkleTreeOperations(fork);
|
|
86
|
-
const publicTxSimulator =
|
|
87
|
-
skipFeeEnforcement: false,
|
|
88
|
-
collectDebugLogs: false,
|
|
89
|
-
collectHints: false,
|
|
90
|
-
collectStatistics: false,
|
|
91
|
-
collectCallMetadata: false
|
|
92
|
-
}));
|
|
87
|
+
const publicTxSimulator = createPublicTxSimulatorForBlockBuilding(guardedFork, contractsDB, globalVariables, this.telemetryClient);
|
|
93
88
|
const processor = new PublicProcessor(globalVariables, guardedFork, contractsDB, publicTxSimulator, this.dateProvider, this.telemetryClient, undefined, this.config);
|
|
94
89
|
const validator = createValidatorForBlockBuilding(fork, this.contractDataSource, globalVariables, txPublicSetupAllowList);
|
|
95
90
|
return {
|
|
@@ -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
|
+
}
|