@aztec/validator-client 0.0.1-commit.ffe5b04ea → 0.0.1-commit.fff30aa
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/README.md +9 -10
- package/dest/checkpoint_builder.d.ts +10 -7
- package/dest/checkpoint_builder.d.ts.map +1 -1
- package/dest/checkpoint_builder.js +64 -41
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +1 -2
- package/dest/duties/validation_service.js +1 -1
- package/dest/factory.d.ts +7 -4
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +5 -5
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/key_store/ha_key_store.js +1 -1
- package/dest/metrics.d.ts +2 -2
- package/dest/metrics.d.ts.map +1 -1
- package/dest/proposal_handler.d.ts +94 -0
- package/dest/proposal_handler.d.ts.map +1 -0
- package/dest/{block_proposal_handler.js → proposal_handler.js} +313 -12
- package/dest/validator.d.ts +10 -23
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +44 -248
- package/package.json +19 -19
- package/src/checkpoint_builder.ts +79 -52
- package/src/config.ts +1 -2
- package/src/duties/validation_service.ts +1 -1
- package/src/factory.ts +9 -4
- package/src/index.ts +1 -1
- package/src/key_store/ha_key_store.ts +1 -1
- package/src/metrics.ts +1 -1
- package/src/{block_proposal_handler.ts → proposal_handler.ts} +362 -13
- package/src/validator.ts +57 -270
- package/dest/block_proposal_handler.d.ts +0 -63
- package/dest/block_proposal_handler.d.ts.map +0 -1
|
@@ -63,7 +63,9 @@ function _ts_dispose_resources(env) {
|
|
|
63
63
|
return next();
|
|
64
64
|
})(env);
|
|
65
65
|
}
|
|
66
|
+
import { encodeCheckpointBlobDataFromBlocks, getBlobsPerL1Block } from '@aztec/blob-lib';
|
|
66
67
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
68
|
+
import { validateFeeAssetPriceModifier } from '@aztec/ethereum/contracts';
|
|
67
69
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
68
70
|
import { pick } from '@aztec/foundation/collection';
|
|
69
71
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -71,12 +73,14 @@ import { TimeoutError } from '@aztec/foundation/error';
|
|
|
71
73
|
import { createLogger } from '@aztec/foundation/log';
|
|
72
74
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
73
75
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
76
|
+
import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
74
77
|
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
75
78
|
import { Gas } from '@aztec/stdlib/gas';
|
|
76
|
-
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
77
|
-
import {
|
|
79
|
+
import { accumulateCheckpointOutHashes, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
80
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
81
|
+
import { ReExFailedTxsError, ReExInitialStateMismatchError, ReExStateMismatchError, ReExTimeoutError, TransactionsNotAvailableError } from '@aztec/stdlib/validators';
|
|
78
82
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
79
|
-
export class
|
|
83
|
+
/** Handles block and checkpoint proposals for both validator and non-validator nodes. */ export class ProposalHandler {
|
|
80
84
|
checkpointsBuilder;
|
|
81
85
|
worldState;
|
|
82
86
|
blockSource;
|
|
@@ -85,11 +89,12 @@ export class BlockProposalHandler {
|
|
|
85
89
|
blockProposalValidator;
|
|
86
90
|
epochCache;
|
|
87
91
|
config;
|
|
92
|
+
blobClient;
|
|
88
93
|
metrics;
|
|
89
94
|
dateProvider;
|
|
90
95
|
log;
|
|
91
96
|
tracer;
|
|
92
|
-
constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:
|
|
97
|
+
constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:proposal-handler')){
|
|
93
98
|
this.checkpointsBuilder = checkpointsBuilder;
|
|
94
99
|
this.worldState = worldState;
|
|
95
100
|
this.blockSource = blockSource;
|
|
@@ -98,18 +103,22 @@ export class BlockProposalHandler {
|
|
|
98
103
|
this.blockProposalValidator = blockProposalValidator;
|
|
99
104
|
this.epochCache = epochCache;
|
|
100
105
|
this.config = config;
|
|
106
|
+
this.blobClient = blobClient;
|
|
101
107
|
this.metrics = metrics;
|
|
102
108
|
this.dateProvider = dateProvider;
|
|
103
109
|
this.log = log;
|
|
104
110
|
if (config.fishermanMode) {
|
|
105
111
|
this.log = this.log.createChild('[FISHERMAN]');
|
|
106
112
|
}
|
|
107
|
-
this.tracer = telemetry.getTracer('
|
|
113
|
+
this.tracer = telemetry.getTracer('ProposalHandler');
|
|
108
114
|
}
|
|
109
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Registers non-validator handlers for block and checkpoint proposals on the p2p client.
|
|
117
|
+
* Block proposals are always registered. Checkpoint proposals are registered if the blob client can upload.
|
|
118
|
+
*/ register(p2pClient, shouldReexecute) {
|
|
110
119
|
// Non-validator handler that processes or re-executes for monitoring but does not attest.
|
|
111
120
|
// Returns boolean indicating whether the proposal was valid.
|
|
112
|
-
const
|
|
121
|
+
const blockHandler = async (proposal, proposalSender)=>{
|
|
113
122
|
try {
|
|
114
123
|
const { slotNumber, blockNumber } = proposal;
|
|
115
124
|
const result = await this.handleBlockProposal(proposal, proposalSender, shouldReexecute);
|
|
@@ -136,7 +145,30 @@ export class BlockProposalHandler {
|
|
|
136
145
|
return false;
|
|
137
146
|
}
|
|
138
147
|
};
|
|
139
|
-
p2pClient.registerBlockProposalHandler(
|
|
148
|
+
p2pClient.registerBlockProposalHandler(blockHandler);
|
|
149
|
+
// Register checkpoint proposal handler if blob uploads are enabled and we are reexecuting
|
|
150
|
+
if (this.blobClient.canUpload() && shouldReexecute) {
|
|
151
|
+
const checkpointHandler = async (checkpoint, _sender)=>{
|
|
152
|
+
try {
|
|
153
|
+
const proposalInfo = {
|
|
154
|
+
proposalSlotNumber: checkpoint.slotNumber,
|
|
155
|
+
archive: checkpoint.archive.toString(),
|
|
156
|
+
proposer: checkpoint.getSender()?.toString()
|
|
157
|
+
};
|
|
158
|
+
const result = await this.handleCheckpointProposal(checkpoint, proposalInfo);
|
|
159
|
+
if (result.isValid) {
|
|
160
|
+
this.log.info(`Non-validator checkpoint proposal at slot ${checkpoint.slotNumber} handled`, proposalInfo);
|
|
161
|
+
} else {
|
|
162
|
+
this.log.warn(`Non-validator checkpoint proposal at slot ${checkpoint.slotNumber} failed: ${result.reason}`, proposalInfo);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
this.log.error('Error processing checkpoint proposal in non-validator handler', error);
|
|
166
|
+
}
|
|
167
|
+
// Non-validators don't attest
|
|
168
|
+
return undefined;
|
|
169
|
+
};
|
|
170
|
+
p2pClient.registerCheckpointProposalHandler(checkpointHandler);
|
|
171
|
+
}
|
|
140
172
|
return this;
|
|
141
173
|
}
|
|
142
174
|
async handleBlockProposal(proposal, proposalSender, shouldReexecute) {
|
|
@@ -153,7 +185,9 @@ export class BlockProposalHandler {
|
|
|
153
185
|
}
|
|
154
186
|
const proposalInfo = {
|
|
155
187
|
...proposal.toBlockInfo(),
|
|
156
|
-
proposer: proposer.toString()
|
|
188
|
+
proposer: proposer.toString(),
|
|
189
|
+
blockNumber: undefined,
|
|
190
|
+
checkpointNumber: undefined
|
|
157
191
|
};
|
|
158
192
|
this.log.info(`Processing proposal for slot ${slotNumber}`, {
|
|
159
193
|
...proposalInfo,
|
|
@@ -169,7 +203,22 @@ export class BlockProposalHandler {
|
|
|
169
203
|
reason: 'invalid_proposal'
|
|
170
204
|
};
|
|
171
205
|
}
|
|
172
|
-
//
|
|
206
|
+
// Ensure the block source is synced before checking for existing blocks,
|
|
207
|
+
// since a pending checkpoint prune may remove blocks we'd otherwise find.
|
|
208
|
+
// This affects mostly the block_number_already_exists check, since a pending
|
|
209
|
+
// checkpoint prune could remove a block that would conflict with this proposal.
|
|
210
|
+
// TODO(@Maddiaa0): This may break staggered slots.
|
|
211
|
+
const blockSourceSync = await this.waitForBlockSourceSync(slotNumber);
|
|
212
|
+
if (!blockSourceSync) {
|
|
213
|
+
this.log.warn(`Block source is not synced, skipping processing`, proposalInfo);
|
|
214
|
+
return {
|
|
215
|
+
isValid: false,
|
|
216
|
+
reason: 'block_source_not_synced'
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Check that the parent proposal is a block we know, otherwise reexecution would fail.
|
|
220
|
+
// If we don't find it immediately, we keep retrying for a while; it may be we still
|
|
221
|
+
// need to process other block proposals to get to it.
|
|
173
222
|
const parentBlock = await this.getParentBlock(proposal);
|
|
174
223
|
if (parentBlock === undefined) {
|
|
175
224
|
this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
|
|
@@ -192,6 +241,7 @@ export class BlockProposalHandler {
|
|
|
192
241
|
}
|
|
193
242
|
// Compute the block number based on the parent block
|
|
194
243
|
const blockNumber = parentBlock === 'genesis' ? BlockNumber(INITIAL_L2_BLOCK_NUM) : BlockNumber(parentBlock.header.getBlockNumber() + 1);
|
|
244
|
+
proposalInfo.blockNumber = blockNumber;
|
|
195
245
|
// Check that this block number does not exist already
|
|
196
246
|
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
197
247
|
if (existingBlock) {
|
|
@@ -208,7 +258,7 @@ export class BlockProposalHandler {
|
|
|
208
258
|
pinnedPeer: proposalSender,
|
|
209
259
|
deadline: this.getReexecutionDeadline(slotNumber, config)
|
|
210
260
|
});
|
|
211
|
-
// If reexecution is disabled, bail. We
|
|
261
|
+
// If reexecution is disabled, bail. We were just interested in triggering tx collection.
|
|
212
262
|
if (!shouldReexecute) {
|
|
213
263
|
this.log.info(`Received valid block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`, proposalInfo);
|
|
214
264
|
return {
|
|
@@ -226,6 +276,7 @@ export class BlockProposalHandler {
|
|
|
226
276
|
};
|
|
227
277
|
}
|
|
228
278
|
const checkpointNumber = checkpointResult.checkpointNumber;
|
|
279
|
+
proposalInfo.checkpointNumber = checkpointNumber;
|
|
229
280
|
// Check that I have the same set of l1ToL2Messages as the proposal
|
|
230
281
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
231
282
|
const computedInHash = computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
@@ -444,8 +495,39 @@ export class BlockProposalHandler {
|
|
|
444
495
|
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
445
496
|
return new Date(nextSlotTimestampSeconds * 1000);
|
|
446
497
|
}
|
|
498
|
+
/** Waits for the block source to sync L1 data up to at least the slot before the given one. */ async waitForBlockSourceSync(slot) {
|
|
499
|
+
const deadline = this.getReexecutionDeadline(slot, this.checkpointsBuilder.getConfig());
|
|
500
|
+
const timeoutMs = deadline.getTime() - this.dateProvider.now();
|
|
501
|
+
if (slot === 0) {
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
// Make a quick check before triggering an archiver sync
|
|
505
|
+
const syncedSlot = await this.blockSource.getSyncedL2SlotNumber();
|
|
506
|
+
if (syncedSlot !== undefined && syncedSlot + 1 >= slot) {
|
|
507
|
+
return true;
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
// Trigger an immediate sync of the block source, and wait until it reports being synced to the required slot
|
|
511
|
+
return await retryUntil(async ()=>{
|
|
512
|
+
await this.blockSource.syncImmediate();
|
|
513
|
+
const syncedSlot = await this.blockSource.getSyncedL2SlotNumber();
|
|
514
|
+
return syncedSlot !== undefined && syncedSlot + 1 >= slot;
|
|
515
|
+
}, 'wait for block source sync', timeoutMs / 1000, 0.5);
|
|
516
|
+
} catch (err) {
|
|
517
|
+
if (err instanceof TimeoutError) {
|
|
518
|
+
this.log.warn(`Timed out waiting for block source to sync to slot ${slot}`);
|
|
519
|
+
return false;
|
|
520
|
+
} else {
|
|
521
|
+
throw err;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
447
525
|
getReexecuteFailureReason(err) {
|
|
448
|
-
if (err instanceof
|
|
526
|
+
if (err instanceof TransactionsNotAvailableError) {
|
|
527
|
+
return 'txs_not_available';
|
|
528
|
+
} else if (err instanceof ReExInitialStateMismatchError) {
|
|
529
|
+
return 'initial_state_mismatch';
|
|
530
|
+
} else if (err instanceof ReExStateMismatchError) {
|
|
449
531
|
return 'state_mismatch';
|
|
450
532
|
} else if (err instanceof ReExFailedTxsError) {
|
|
451
533
|
return 'failed_txs';
|
|
@@ -479,6 +561,12 @@ export class BlockProposalHandler {
|
|
|
479
561
|
const parentBlockNumber = BlockNumber(blockNumber - 1);
|
|
480
562
|
await this.worldState.syncImmediate(parentBlockNumber);
|
|
481
563
|
const fork = _ts_add_disposable_resource(env, await this.worldState.fork(parentBlockNumber), true);
|
|
564
|
+
// Verify the fork's archive root matches the proposal's expected last archive.
|
|
565
|
+
// If they don't match, our world state synced to a different chain and reexecution would fail.
|
|
566
|
+
const forkArchiveRoot = new Fr((await fork.getTreeInfo(MerkleTreeId.ARCHIVE)).root);
|
|
567
|
+
if (!forkArchiveRoot.equals(proposal.blockHeader.lastArchive.root)) {
|
|
568
|
+
throw new ReExInitialStateMismatchError(proposal.blockHeader.lastArchive.root, forkArchiveRoot);
|
|
569
|
+
}
|
|
482
570
|
// Build checkpoint constants from proposal (excludes blockNumber which is per-block)
|
|
483
571
|
const constants = {
|
|
484
572
|
chainId: new Fr(config.l1ChainId),
|
|
@@ -495,6 +583,8 @@ export class BlockProposalHandler {
|
|
|
495
583
|
const deadline = this.getReexecutionDeadline(slot, config);
|
|
496
584
|
const maxBlockGas = this.config.validateMaxL2BlockGas !== undefined || this.config.validateMaxDABlockGas !== undefined ? new Gas(this.config.validateMaxDABlockGas ?? Infinity, this.config.validateMaxL2BlockGas ?? Infinity) : undefined;
|
|
497
585
|
const result = await checkpointBuilder.buildBlock(txs, blockNumber, blockHeader.globalVariables.timestamp, {
|
|
586
|
+
isBuildingProposal: false,
|
|
587
|
+
minValidTxs: 0,
|
|
498
588
|
deadline,
|
|
499
589
|
expectedEndState: blockHeader.state,
|
|
500
590
|
maxTransactions: this.config.validateMaxTxsPerBlock,
|
|
@@ -548,4 +638,215 @@ export class BlockProposalHandler {
|
|
|
548
638
|
if (result) await result;
|
|
549
639
|
}
|
|
550
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* Validates a checkpoint proposal and uploads blobs if configured.
|
|
643
|
+
* Used by both non-validator nodes (via register) and the validator client (via delegation).
|
|
644
|
+
*/ async handleCheckpointProposal(proposal, proposalInfo) {
|
|
645
|
+
const proposer = proposal.getSender();
|
|
646
|
+
if (!proposer) {
|
|
647
|
+
this.log.warn(`Received checkpoint proposal with invalid signature for slot ${proposal.slotNumber}`);
|
|
648
|
+
return {
|
|
649
|
+
isValid: false,
|
|
650
|
+
reason: 'invalid_signature'
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
if (!validateFeeAssetPriceModifier(proposal.feeAssetPriceModifier)) {
|
|
654
|
+
this.log.warn(`Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${proposal.slotNumber}`);
|
|
655
|
+
return {
|
|
656
|
+
isValid: false,
|
|
657
|
+
reason: 'invalid_fee_asset_price_modifier'
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
const result = await this.validateCheckpointProposal(proposal, proposalInfo);
|
|
661
|
+
// Upload blobs to filestore if validation passed (fire and forget)
|
|
662
|
+
if (result.isValid) {
|
|
663
|
+
this.tryUploadBlobsForCheckpoint(proposal, proposalInfo);
|
|
664
|
+
}
|
|
665
|
+
return result;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Validates a checkpoint proposal by building the full checkpoint and comparing it with the proposal.
|
|
669
|
+
* @returns Validation result with isValid flag and reason if invalid.
|
|
670
|
+
*/ async validateCheckpointProposal(proposal, proposalInfo) {
|
|
671
|
+
const slot = proposal.slotNumber;
|
|
672
|
+
// Timeout block syncing at the start of the next slot
|
|
673
|
+
const config = this.checkpointsBuilder.getConfig();
|
|
674
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
675
|
+
const timeoutSeconds = Math.max(1, nextSlotTimestampSeconds - Math.floor(this.dateProvider.now() / 1000));
|
|
676
|
+
// Wait for last block to sync by archive
|
|
677
|
+
let lastBlockHeader;
|
|
678
|
+
try {
|
|
679
|
+
lastBlockHeader = await retryUntil(async ()=>{
|
|
680
|
+
await this.blockSource.syncImmediate();
|
|
681
|
+
return this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
682
|
+
}, `waiting for block with archive ${proposal.archive.toString()} for slot ${slot}`, timeoutSeconds, 0.5);
|
|
683
|
+
} catch (err) {
|
|
684
|
+
if (err instanceof TimeoutError) {
|
|
685
|
+
this.log.warn(`Timed out waiting for block with archive matching checkpoint proposal`, proposalInfo);
|
|
686
|
+
return {
|
|
687
|
+
isValid: false,
|
|
688
|
+
reason: 'last_block_not_found'
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
this.log.error(`Error fetching last block for checkpoint proposal`, err, proposalInfo);
|
|
692
|
+
return {
|
|
693
|
+
isValid: false,
|
|
694
|
+
reason: 'block_fetch_error'
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
if (!lastBlockHeader) {
|
|
698
|
+
this.log.warn(`Last block not found for checkpoint proposal`, proposalInfo);
|
|
699
|
+
return {
|
|
700
|
+
isValid: false,
|
|
701
|
+
reason: 'last_block_not_found'
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
// Get all full blocks for the slot and checkpoint
|
|
705
|
+
const blocks = await this.blockSource.getBlocksForSlot(slot);
|
|
706
|
+
if (blocks.length === 0) {
|
|
707
|
+
this.log.warn(`No blocks found for slot ${slot}`, proposalInfo);
|
|
708
|
+
return {
|
|
709
|
+
isValid: false,
|
|
710
|
+
reason: 'no_blocks_for_slot'
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
714
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
715
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
716
|
+
return {
|
|
717
|
+
isValid: false,
|
|
718
|
+
reason: 'last_block_archive_mismatch'
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
722
|
+
...proposalInfo,
|
|
723
|
+
blockNumbers: blocks.map((b)=>b.number)
|
|
724
|
+
});
|
|
725
|
+
// Get checkpoint constants from first block
|
|
726
|
+
const firstBlock = blocks[0];
|
|
727
|
+
const constants = this.extractCheckpointConstants(firstBlock);
|
|
728
|
+
const checkpointNumber = firstBlock.checkpointNumber;
|
|
729
|
+
// Get L1-to-L2 messages for this checkpoint
|
|
730
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
731
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
732
|
+
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
733
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
|
|
734
|
+
// Fork world state at the block before the first block
|
|
735
|
+
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
736
|
+
const fork = await this.worldState.fork(parentBlockNumber);
|
|
737
|
+
try {
|
|
738
|
+
// Create checkpoint builder with all existing blocks
|
|
739
|
+
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(checkpointNumber, constants, proposal.feeAssetPriceModifier, l1ToL2Messages, previousCheckpointOutHashes, fork, blocks, this.log.getBindings());
|
|
740
|
+
// Complete the checkpoint to get computed values
|
|
741
|
+
const computedCheckpoint = await checkpointBuilder.completeCheckpoint();
|
|
742
|
+
// Compare checkpoint header with proposal
|
|
743
|
+
if (!computedCheckpoint.header.equals(proposal.checkpointHeader)) {
|
|
744
|
+
this.log.warn(`Checkpoint header mismatch`, {
|
|
745
|
+
...proposalInfo,
|
|
746
|
+
computed: computedCheckpoint.header.toInspect(),
|
|
747
|
+
proposal: proposal.checkpointHeader.toInspect()
|
|
748
|
+
});
|
|
749
|
+
return {
|
|
750
|
+
isValid: false,
|
|
751
|
+
reason: 'checkpoint_header_mismatch'
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
// Compare archive root with proposal
|
|
755
|
+
if (!computedCheckpoint.archive.root.equals(proposal.archive)) {
|
|
756
|
+
this.log.warn(`Archive root mismatch`, {
|
|
757
|
+
...proposalInfo,
|
|
758
|
+
computed: computedCheckpoint.archive.root.toString(),
|
|
759
|
+
proposal: proposal.archive.toString()
|
|
760
|
+
});
|
|
761
|
+
return {
|
|
762
|
+
isValid: false,
|
|
763
|
+
reason: 'archive_mismatch'
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
// Check that the accumulated epoch out hash matches the value in the proposal.
|
|
767
|
+
// The epoch out hash is the accumulated hash of all checkpoint out hashes in the epoch.
|
|
768
|
+
const checkpointOutHash = computedCheckpoint.getCheckpointOutHash();
|
|
769
|
+
const computedEpochOutHash = accumulateCheckpointOutHashes([
|
|
770
|
+
...previousCheckpointOutHashes,
|
|
771
|
+
checkpointOutHash
|
|
772
|
+
]);
|
|
773
|
+
const proposalEpochOutHash = proposal.checkpointHeader.epochOutHash;
|
|
774
|
+
if (!computedEpochOutHash.equals(proposalEpochOutHash)) {
|
|
775
|
+
this.log.warn(`Epoch out hash mismatch`, {
|
|
776
|
+
proposalEpochOutHash: proposalEpochOutHash.toString(),
|
|
777
|
+
computedEpochOutHash: computedEpochOutHash.toString(),
|
|
778
|
+
checkpointOutHash: checkpointOutHash.toString(),
|
|
779
|
+
previousCheckpointOutHashes: previousCheckpointOutHashes.map((h)=>h.toString()),
|
|
780
|
+
...proposalInfo
|
|
781
|
+
});
|
|
782
|
+
return {
|
|
783
|
+
isValid: false,
|
|
784
|
+
reason: 'out_hash_mismatch'
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
// Final round of validations on the checkpoint, just in case.
|
|
788
|
+
try {
|
|
789
|
+
validateCheckpoint(computedCheckpoint, {
|
|
790
|
+
rollupManaLimit: this.checkpointsBuilder.getConfig().rollupManaLimit,
|
|
791
|
+
maxDABlockGas: this.config.validateMaxDABlockGas,
|
|
792
|
+
maxL2BlockGas: this.config.validateMaxL2BlockGas,
|
|
793
|
+
maxTxsPerBlock: this.config.validateMaxTxsPerBlock,
|
|
794
|
+
maxTxsPerCheckpoint: this.config.validateMaxTxsPerCheckpoint
|
|
795
|
+
});
|
|
796
|
+
} catch (err) {
|
|
797
|
+
this.log.warn(`Checkpoint validation failed: ${err}`, proposalInfo);
|
|
798
|
+
return {
|
|
799
|
+
isValid: false,
|
|
800
|
+
reason: 'checkpoint_validation_failed'
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
this.log.verbose(`Checkpoint proposal validation successful for slot ${slot}`, proposalInfo);
|
|
804
|
+
return {
|
|
805
|
+
isValid: true
|
|
806
|
+
};
|
|
807
|
+
} finally{
|
|
808
|
+
await fork.close();
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
/** Extracts checkpoint global variables from a block. */ extractCheckpointConstants(block) {
|
|
812
|
+
const gv = block.header.globalVariables;
|
|
813
|
+
return {
|
|
814
|
+
chainId: gv.chainId,
|
|
815
|
+
version: gv.version,
|
|
816
|
+
slotNumber: gv.slotNumber,
|
|
817
|
+
timestamp: gv.timestamp,
|
|
818
|
+
coinbase: gv.coinbase,
|
|
819
|
+
feeRecipient: gv.feeRecipient,
|
|
820
|
+
gasFees: gv.gasFees
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
/** Triggers blob upload for a checkpoint if the blob client can upload (fire and forget). */ tryUploadBlobsForCheckpoint(proposal, proposalInfo) {
|
|
824
|
+
if (this.blobClient.canUpload()) {
|
|
825
|
+
void this.uploadBlobsForCheckpoint(proposal, proposalInfo);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
/** Uploads blobs for a checkpoint to the filestore. */ async uploadBlobsForCheckpoint(proposal, proposalInfo) {
|
|
829
|
+
try {
|
|
830
|
+
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
831
|
+
if (!lastBlockHeader) {
|
|
832
|
+
this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const blocks = await this.blockSource.getBlocksForSlot(proposal.slotNumber);
|
|
836
|
+
if (blocks.length === 0) {
|
|
837
|
+
this.log.warn(`No blocks found for blob upload`, proposalInfo);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const blockBlobData = blocks.map((b)=>b.toBlockBlobData());
|
|
841
|
+
const blobFields = encodeCheckpointBlobDataFromBlocks(blockBlobData);
|
|
842
|
+
const blobs = await getBlobsPerL1Block(blobFields);
|
|
843
|
+
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
844
|
+
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
845
|
+
...proposalInfo,
|
|
846
|
+
numBlobs: blobs.length
|
|
847
|
+
});
|
|
848
|
+
} catch (err) {
|
|
849
|
+
this.log.warn(`Failed to upload blobs for checkpoint: ${err}`, proposalInfo);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
551
852
|
}
|
package/dest/validator.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint, SlotNumber } from
|
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
7
|
-
import { type
|
|
7
|
+
import { type Logger } from '@aztec/foundation/log';
|
|
8
8
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
9
|
import type { KeystoreManager } from '@aztec/node-keystore';
|
|
10
10
|
import type { P2P, PeerId } from '@aztec/p2p';
|
|
@@ -12,17 +12,17 @@ import { type Watcher, type WatcherEmitter } from '@aztec/slasher';
|
|
|
12
12
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
13
|
import type { CommitteeAttestationsAndSigners, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
14
14
|
import type { CreateCheckpointProposalLastBlockData, ITxProvider, Validator, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
15
|
-
import {
|
|
15
|
+
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
16
16
|
import { type BlockProposal, type BlockProposalOptions, type CheckpointAttestation, CheckpointProposal, type CheckpointProposalCore, type CheckpointProposalOptions } from '@aztec/stdlib/p2p';
|
|
17
17
|
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
18
18
|
import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
|
|
19
19
|
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
20
|
-
import { type SigningContext } from '@aztec/validator-ha-signer/types';
|
|
20
|
+
import { type SigningContext, type SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
|
|
21
21
|
import type { ValidatorHASigner } from '@aztec/validator-ha-signer/validator-ha-signer';
|
|
22
22
|
import type { TypedDataDefinition } from 'viem';
|
|
23
|
-
import { BlockProposalHandler } from './block_proposal_handler.js';
|
|
24
23
|
import type { FullNodeCheckpointsBuilder } from './checkpoint_builder.js';
|
|
25
24
|
import type { ExtendedValidatorKeyStore } from './key_store/interface.js';
|
|
25
|
+
import { ProposalHandler } from './proposal_handler.js';
|
|
26
26
|
declare const ValidatorClient_base: new () => WatcherEmitter;
|
|
27
27
|
/**
|
|
28
28
|
* Validator Client
|
|
@@ -31,14 +31,10 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
31
31
|
private keyStore;
|
|
32
32
|
private epochCache;
|
|
33
33
|
private p2pClient;
|
|
34
|
-
private
|
|
35
|
-
private blockSource;
|
|
36
|
-
private checkpointsBuilder;
|
|
37
|
-
private worldState;
|
|
38
|
-
private l1ToL2MessageSource;
|
|
34
|
+
private proposalHandler;
|
|
39
35
|
private config;
|
|
40
36
|
private blobClient;
|
|
41
|
-
private
|
|
37
|
+
private haSigner;
|
|
42
38
|
private dateProvider;
|
|
43
39
|
readonly tracer: Tracer;
|
|
44
40
|
private validationService;
|
|
@@ -56,12 +52,12 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
56
52
|
private proposersOfInvalidBlocks;
|
|
57
53
|
/** Tracks the last checkpoint proposal we attested to, to prevent equivocation. */
|
|
58
54
|
private lastAttestedProposal?;
|
|
59
|
-
protected constructor(keyStore: ExtendedValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P,
|
|
55
|
+
protected constructor(keyStore: ExtendedValidatorKeyStore, epochCache: EpochCache, p2pClient: P2P, proposalHandler: ProposalHandler, config: ValidatorClientFullConfig, blobClient: BlobClientInterface, haSigner: ValidatorHASigner | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: Logger);
|
|
60
56
|
static validateKeyStoreConfiguration(keyStoreManager: KeystoreManager, logger?: Logger): void;
|
|
61
57
|
private handleEpochCommitteeUpdate;
|
|
62
|
-
static new(config: ValidatorClientFullConfig, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, keyStoreManager: KeystoreManager, blobClient: BlobClientInterface, dateProvider?: DateProvider, telemetry?: TelemetryClient): Promise<ValidatorClient>;
|
|
58
|
+
static new(config: ValidatorClientFullConfig, checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, keyStoreManager: KeystoreManager, blobClient: BlobClientInterface, dateProvider?: DateProvider, telemetry?: TelemetryClient, slashingProtectionDb?: SlashingProtectionDatabase): Promise<ValidatorClient>;
|
|
63
59
|
getValidatorAddresses(): EthAddress[];
|
|
64
|
-
|
|
60
|
+
getProposalHandler(): ProposalHandler;
|
|
65
61
|
signWithAddress(addr: EthAddress, msg: TypedDataDefinition, context: SigningContext): Promise<Signature>;
|
|
66
62
|
getCoinbaseForAttestor(attestor: EthAddress): EthAddress;
|
|
67
63
|
getFeeRecipientForAttestor(attestor: EthAddress): AztecAddress;
|
|
@@ -91,15 +87,6 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
91
87
|
*/
|
|
92
88
|
private shouldAttestToSlot;
|
|
93
89
|
private createCheckpointAttestationsFromProposal;
|
|
94
|
-
private validateCheckpointProposal;
|
|
95
|
-
/**
|
|
96
|
-
* Extract checkpoint global variables from a block.
|
|
97
|
-
*/
|
|
98
|
-
private extractCheckpointConstants;
|
|
99
|
-
/**
|
|
100
|
-
* Uploads blobs for a checkpoint to the filestore (fire and forget).
|
|
101
|
-
*/
|
|
102
|
-
protected uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void>;
|
|
103
90
|
private slashInvalidBlock;
|
|
104
91
|
/**
|
|
105
92
|
* Handle detection of a duplicate proposal (equivocation).
|
|
@@ -120,4 +107,4 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
120
107
|
private handleAuthRequest;
|
|
121
108
|
}
|
|
122
109
|
export {};
|
|
123
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
110
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDckQsT0FBTyxFQUNMLFdBQVcsRUFDWCxnQkFBZ0IsRUFFaEIscUJBQXFCLEVBQ3JCLFVBQVUsRUFDWCxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sdUJBQXVCLENBQUM7QUFHbEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzVELE9BQU8sS0FBSyxFQUFtRCxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRS9GLE9BQU8sRUFBb0MsS0FBSyxPQUFPLEVBQUUsS0FBSyxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRyxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSwrQkFBK0IsRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkcsT0FBTyxLQUFLLEVBQ1YscUNBQXFDLEVBQ3JDLFdBQVcsRUFDWCxTQUFTLEVBQ1QseUJBQXlCLEVBQ3pCLHNCQUFzQixFQUN2QixNQUFNLGlDQUFpQyxDQUFD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
|
package/dest/validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,WAAW,EACX,gBAAgB,EAEhB,qBAAqB,EACrB,UAAU,EACX,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAmD,GAAG,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE/F,OAAO,EAAoC,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,+BAA+B,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEvG,OAAO,KAAK,EACV,qCAAqC,EACrC,WAAW,EACX,SAAS,EACT,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,kBAAkB,EAClB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAsB,MAAM,yBAAyB,CAAC;AAEhG,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAClH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAGxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAEhD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAG1E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EAA6C,eAAe,EAAE,MAAM,uBAAuB,CAAC;;AAYnG;;GAEG;AACH,qBAAa,eAAgB,SAAQ,oBAA2C,YAAW,SAAS,EAAE,OAAO;IAyBzG,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IA/BtB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,GAAG,CAAS;IAEpB,OAAO,CAAC,qBAAqB,CAAS;IAEtC,wFAAwF;IACxF,OAAO,CAAC,iBAAiB,CAAC,CAAgB;IAE1C,sDAAsD;IACtD,OAAO,CAAC,sBAAsB,CAAC,CAAqB;IAEpD,OAAO,CAAC,+BAA+B,CAA0B;IACjE,OAAO,CAAC,oBAAoB,CAAiB;IAC7C,oGAAoG;IACpG,OAAO,CAAC,2BAA2B,CAAuC;IAE1E,OAAO,CAAC,wBAAwB,CAA0B;IAE1D,mFAAmF;IACnF,OAAO,CAAC,oBAAoB,CAAC,CAAyB;IAEtD,SAAS,aACC,QAAQ,EAAE,yBAAyB,EACnC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,yBAAyB,EACjC,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,YAAY,GAAE,YAAiC,EACvD,SAAS,GAAE,eAAsC,EACjD,GAAG,SAA4B,EAiBhC;IAED,OAAc,6BAA6B,CAAC,eAAe,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,MAAM,QAuB5F;YAEa,0BAA0B;IA4BxC,OAAa,GAAG,CACd,MAAM,EAAE,yBAAyB,EACjC,kBAAkB,EAAE,0BAA0B,EAC9C,UAAU,EAAE,sBAAsB,EAClC,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,GAAG,EACd,WAAW,EAAE,aAAa,GAAG,WAAW,EACxC,mBAAmB,EAAE,mBAAmB,EACxC,UAAU,EAAE,WAAW,EACvB,eAAe,EAAE,eAAe,EAChC,UAAU,EAAE,mBAAmB,EAC/B,YAAY,GAAE,YAAiC,EAC/C,SAAS,GAAE,eAAsC,EACjD,oBAAoB,CAAC,EAAE,0BAA0B,4BAsDlD;IAEM,qBAAqB,iBAI3B;IAEM,kBAAkB,oBAExB;IAEM,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,cAAc,sBAEzF;IAEM,sBAAsB,CAAC,QAAQ,EAAE,UAAU,GAAG,UAAU,CAE9D;IAEM,0BAA0B,CAAC,QAAQ,EAAE,UAAU,GAAG,YAAY,CAEpE;IAEM,SAAS,IAAI,yBAAyB,CAE5C;IAEM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,QAE7D;IAEM,cAAc,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAoBvD;IAEY,KAAK,kBAmBjB;IAEY,IAAI,kBAGhB;IAED,0CAA0C;IAC7B,gBAAgB,kBAkC5B;IAED;;;;OAIG;IACG,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkG7F;IAED;;;;;OAKG;IACG,0BAA0B,CAC9B,QAAQ,EAAE,sBAAsB,EAChC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,qBAAqB,EAAE,GAAG,SAAS,CAAC,CAiG9C;IAED;;;OAGG;IACH,OAAO,CAAC,kBAAkB;YAiBZ,wCAAwC;IAkBtD,OAAO,CAAC,iBAAiB;IA2BzB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAkB5B,mBAAmB,CACvB,WAAW,EAAE,WAAW,EACxB,qBAAqB,EAAE,qBAAqB,EAC5C,MAAM,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,EACX,GAAG,EAAE,EAAE,EAAE,EACT,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,aAAa,CAAC,CAgCxB;IAEK,wBAAwB,CAC5B,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,EAAE,EACX,qBAAqB,EAAE,MAAM,EAC7B,aAAa,EAAE,qCAAqC,GAAG,SAAS,EAChE,eAAe,EAAE,UAAU,GAAG,SAAS,EACvC,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,kBAAkB,CAAC,CAyB7B;IAEK,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnE;IAEK,0BAA0B,CAC9B,sBAAsB,EAAE,+BAA+B,EACvD,QAAQ,EAAE,UAAU,EACpB,IAAI,EAAE,UAAU,EAChB,WAAW,EAAE,WAAW,GAAG,gBAAgB,GAC1C,OAAO,CAAC,SAAS,CAAC,CAEpB;IAEK,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAiB3F;IAEK,mBAAmB,CACvB,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,IAAI,GACb,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAiElC;YAEa,iBAAiB;CAwBhC"}
|