@aztec/sequencer-client 0.0.1-commit.684755437 → 0.0.1-commit.69c59a8b3
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 +6 -12
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +30 -80
- package/dest/config.d.ts +4 -3
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +17 -13
- package/dest/global_variable_builder/fee_predictor.d.ts +37 -0
- package/dest/global_variable_builder/fee_predictor.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_predictor.js +128 -0
- package/dest/global_variable_builder/fee_provider.d.ts +21 -0
- package/dest/global_variable_builder/fee_provider.d.ts.map +1 -0
- package/dest/global_variable_builder/fee_provider.js +58 -0
- package/dest/global_variable_builder/global_builder.d.ts +15 -14
- package/dest/global_variable_builder/global_builder.d.ts.map +1 -1
- package/dest/global_variable_builder/global_builder.js +16 -50
- package/dest/global_variable_builder/index.d.ts +4 -2
- package/dest/global_variable_builder/index.d.ts.map +1 -1
- package/dest/global_variable_builder/index.js +2 -0
- package/dest/publisher/config.d.ts +13 -1
- package/dest/publisher/config.d.ts.map +1 -1
- package/dest/publisher/config.js +19 -4
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts +3 -4
- package/dest/publisher/l1_tx_failed_store/failed_tx_store.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.d.ts +3 -5
- package/dest/publisher/sequencer-publisher-factory.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher-factory.js +2 -3
- package/dest/publisher/sequencer-publisher.d.ts +51 -43
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +135 -111
- package/dest/sequencer/chain_state_overrides.d.ts +25 -0
- package/dest/sequencer/chain_state_overrides.d.ts.map +1 -0
- package/dest/sequencer/chain_state_overrides.js +39 -0
- package/dest/sequencer/checkpoint_proposal_job.d.ts +26 -7
- package/dest/sequencer/checkpoint_proposal_job.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_proposal_job.js +296 -185
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts +34 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.d.ts.map +1 -0
- package/dest/sequencer/checkpoint_proposal_job_metrics.js +72 -0
- package/dest/sequencer/checkpoint_voter.d.ts +1 -2
- package/dest/sequencer/checkpoint_voter.d.ts.map +1 -1
- package/dest/sequencer/checkpoint_voter.js +2 -5
- package/dest/sequencer/events.d.ts +2 -1
- package/dest/sequencer/events.d.ts.map +1 -1
- package/dest/sequencer/metrics.d.ts +9 -10
- package/dest/sequencer/metrics.d.ts.map +1 -1
- package/dest/sequencer/metrics.js +23 -20
- package/dest/sequencer/sequencer.d.ts +22 -7
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +136 -73
- package/dest/sequencer/timetable.d.ts +14 -1
- package/dest/sequencer/timetable.d.ts.map +1 -1
- package/dest/sequencer/timetable.js +45 -36
- package/dest/sequencer/types.d.ts +2 -5
- package/dest/sequencer/types.d.ts.map +1 -1
- package/dest/test/mock_checkpoint_builder.d.ts +4 -4
- package/dest/test/mock_checkpoint_builder.d.ts.map +1 -1
- package/package.json +27 -28
- package/src/client/sequencer-client.ts +42 -108
- package/src/config.ts +20 -12
- package/src/global_variable_builder/README.md +44 -0
- package/src/global_variable_builder/fee_predictor.ts +172 -0
- package/src/global_variable_builder/fee_provider.ts +75 -0
- package/src/global_variable_builder/global_builder.ts +26 -62
- package/src/global_variable_builder/index.ts +3 -1
- package/src/publisher/config.ts +38 -4
- package/src/publisher/l1_tx_failed_store/failed_tx_store.ts +3 -1
- package/src/publisher/sequencer-publisher-factory.ts +3 -6
- package/src/publisher/sequencer-publisher.ts +202 -158
- package/src/sequencer/README.md +83 -13
- package/src/sequencer/chain_state_overrides.ts +87 -0
- package/src/sequencer/checkpoint_proposal_job.ts +383 -206
- package/src/sequencer/checkpoint_proposal_job_metrics.ts +128 -0
- package/src/sequencer/checkpoint_voter.ts +1 -12
- package/src/sequencer/events.ts +1 -1
- package/src/sequencer/metrics.ts +29 -25
- package/src/sequencer/sequencer.ts +197 -80
- package/src/sequencer/timetable.ts +57 -45
- package/src/sequencer/types.ts +2 -5
- package/src/test/mock_checkpoint_builder.ts +3 -3
|
@@ -372,24 +372,26 @@ function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
|
|
|
372
372
|
}
|
|
373
373
|
var _dec, _dec1, _dec2, _initProto;
|
|
374
374
|
import { Blob, getBlobsPerL1Block, getPrefixedEthBlobCommitments } from '@aztec/blob-lib';
|
|
375
|
-
import { FeeAssetPriceOracle, MULTI_CALL_3_ADDRESS, Multicall3,
|
|
375
|
+
import { FeeAssetPriceOracle, MULTI_CALL_3_ADDRESS, Multicall3, SimulationOverridesBuilder, buildSimulationOverridesStateOverride } from '@aztec/ethereum/contracts';
|
|
376
376
|
import { L1FeeAnalyzer } from '@aztec/ethereum/l1-fee-analysis';
|
|
377
377
|
import { MAX_L1_TX_LIMIT, WEI_CONST } from '@aztec/ethereum/l1-tx-utils';
|
|
378
378
|
import { FormattedViemError, formatViemError, mergeAbis, tryExtractEvent } from '@aztec/ethereum/utils';
|
|
379
379
|
import { sumBigint } from '@aztec/foundation/bigint';
|
|
380
|
-
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
381
380
|
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
381
|
+
import { trimmedBytesLength } from '@aztec/foundation/buffer';
|
|
382
382
|
import { pick } from '@aztec/foundation/collection';
|
|
383
383
|
import { TimeoutError } from '@aztec/foundation/error';
|
|
384
384
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
385
385
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
386
386
|
import { createLogger } from '@aztec/foundation/log';
|
|
387
387
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
388
|
+
import { InterruptibleSleep } from '@aztec/foundation/sleep';
|
|
388
389
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
389
390
|
import { Timer } from '@aztec/foundation/timer';
|
|
390
391
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
391
392
|
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
392
393
|
import { CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
394
|
+
import { getLastL1SlotTimestampForL2Slot, getNextL1SlotTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
393
395
|
import { getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
394
396
|
import { encodeFunctionData, keccak256, multicall3Abi, toHex } from 'viem';
|
|
395
397
|
import { createL1TxFailedStore } from './l1_tx_failed_store/index.js';
|
|
@@ -399,9 +401,6 @@ export const Actions = [
|
|
|
399
401
|
'invalidate-by-insufficient-attestations',
|
|
400
402
|
'propose',
|
|
401
403
|
'governance-signal',
|
|
402
|
-
'empire-slashing-signal',
|
|
403
|
-
'create-empire-payload',
|
|
404
|
-
'execute-empire-payload',
|
|
405
404
|
'vote-offenses',
|
|
406
405
|
'execute-slash'
|
|
407
406
|
];
|
|
@@ -440,11 +439,14 @@ export class SequencerPublisher {
|
|
|
440
439
|
payloadProposedCache;
|
|
441
440
|
log;
|
|
442
441
|
ethereumSlotDuration;
|
|
442
|
+
aztecSlotDuration;
|
|
443
|
+
/** Date provider for wall-clock time. */ dateProvider;
|
|
443
444
|
blobClient;
|
|
444
445
|
/** Address to use for simulations in fisherman mode (actual proposer's address) */ proposerAddressForSimulation;
|
|
445
446
|
/** Optional callback to obtain a replacement publisher when the current one fails to send. */ getNextPublisher;
|
|
446
447
|
/** L1 fee analyzer for fisherman mode */ l1FeeAnalyzer;
|
|
447
448
|
/** Fee asset price oracle for computing price modifiers from Uniswap V4 */ feeAssetPriceOracle;
|
|
449
|
+
/** Interruptible sleep used by sendRequestsAt to wait until a target timestamp. */ interruptibleSleep;
|
|
448
450
|
// A CALL to a cold address is 2700 gas
|
|
449
451
|
static MULTICALL_OVERHEAD_GAS_GUESS = 5000n;
|
|
450
452
|
// Gas report for VotingWithSigTest shows a max gas of 100k, but we've seen it cost 700k+ in testnet
|
|
@@ -453,7 +455,6 @@ export class SequencerPublisher {
|
|
|
453
455
|
rollupContract;
|
|
454
456
|
govProposerContract;
|
|
455
457
|
slashingProposerContract;
|
|
456
|
-
slashFactoryContract;
|
|
457
458
|
tracer;
|
|
458
459
|
requests;
|
|
459
460
|
constructor(config, deps){
|
|
@@ -464,12 +465,16 @@ export class SequencerPublisher {
|
|
|
464
465
|
this.lastActions = {};
|
|
465
466
|
this.isPayloadEmptyCache = new Map();
|
|
466
467
|
this.payloadProposedCache = new Set();
|
|
468
|
+
this.interruptibleSleep = new InterruptibleSleep();
|
|
467
469
|
this.requests = [];
|
|
468
470
|
this.log = deps.log ?? createLogger('sequencer:publisher');
|
|
469
471
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
472
|
+
this.aztecSlotDuration = BigInt(config.aztecSlotDuration);
|
|
473
|
+
this.dateProvider = deps.dateProvider;
|
|
470
474
|
this.epochCache = deps.epochCache;
|
|
471
475
|
this.lastActions = deps.lastActions;
|
|
472
476
|
this.blobClient = deps.blobClient;
|
|
477
|
+
this.dateProvider = deps.dateProvider;
|
|
473
478
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
474
479
|
this.metrics = deps.metrics ?? new SequencerPublisherMetrics(telemetry, 'SequencerPublisher');
|
|
475
480
|
this.tracer = telemetry.getTracer('SequencerPublisher');
|
|
@@ -483,7 +488,6 @@ export class SequencerPublisher {
|
|
|
483
488
|
const newSlashingProposer = await this.rollupContract.getSlashingProposer();
|
|
484
489
|
this.slashingProposerContract = newSlashingProposer;
|
|
485
490
|
});
|
|
486
|
-
this.slashFactoryContract = deps.slashFactoryContract;
|
|
487
491
|
// Initialize L1 fee analyzer for fisherman mode
|
|
488
492
|
if (config.fishermanMode) {
|
|
489
493
|
this.l1FeeAnalyzer = new L1FeeAnalyzer(this.l1TxUtils.client, deps.dateProvider, createLogger('sequencer:publisher:fee-analyzer'));
|
|
@@ -536,7 +540,7 @@ export class SequencerPublisher {
|
|
|
536
540
|
this.requests.push(request);
|
|
537
541
|
}
|
|
538
542
|
getCurrentL2Slot() {
|
|
539
|
-
return this.epochCache.
|
|
543
|
+
return this.epochCache.getSlotNow();
|
|
540
544
|
}
|
|
541
545
|
/**
|
|
542
546
|
* Clears all pending requests without sending them.
|
|
@@ -625,8 +629,8 @@ export class SequencerPublisher {
|
|
|
625
629
|
// @note - we can only have one blob config per bundle
|
|
626
630
|
// find requests with gas and blob configs
|
|
627
631
|
// See https://github.com/AztecProtocol/aztec-packages/issues/11513
|
|
628
|
-
const gasConfigs =
|
|
629
|
-
const blobConfigs =
|
|
632
|
+
const gasConfigs = validRequests.filter((request)=>request.gasConfig).map((request)=>request.gasConfig);
|
|
633
|
+
const blobConfigs = validRequests.filter((request)=>request.blobConfig).map((request)=>request.blobConfig);
|
|
630
634
|
if (blobConfigs.length > 1) {
|
|
631
635
|
throw new Error('Multiple blob configs found');
|
|
632
636
|
}
|
|
@@ -734,6 +738,41 @@ export class SequencerPublisher {
|
|
|
734
738
|
}
|
|
735
739
|
}
|
|
736
740
|
}
|
|
741
|
+
/*
|
|
742
|
+
* Schedules sending all enqueued requests at (or after) the given timestamp.
|
|
743
|
+
* Uses InterruptibleSleep so it can be cancelled via interrupt().
|
|
744
|
+
* Returns the promise for the L1 response (caller should NOT await this in the work loop).
|
|
745
|
+
*/ async sendRequestsAt(submitAfter) {
|
|
746
|
+
const ms = submitAfter.getTime() - this.dateProvider.now();
|
|
747
|
+
if (ms > 0) {
|
|
748
|
+
this.log.debug(`Sleeping ${ms}ms before sending requests`, {
|
|
749
|
+
submitAfter
|
|
750
|
+
});
|
|
751
|
+
await this.interruptibleSleep.sleep(ms);
|
|
752
|
+
}
|
|
753
|
+
if (this.interrupted) {
|
|
754
|
+
return undefined;
|
|
755
|
+
}
|
|
756
|
+
// Re-validate enqueued requests after the sleep (state may have changed, e.g. prune or L1 reorg)
|
|
757
|
+
const validRequests = [];
|
|
758
|
+
for (const request of this.requests){
|
|
759
|
+
if (!request.preCheck) {
|
|
760
|
+
validRequests.push(request);
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
try {
|
|
764
|
+
await request.preCheck();
|
|
765
|
+
validRequests.push(request);
|
|
766
|
+
} catch (err) {
|
|
767
|
+
this.log.warn(`Pre-send validation failed for ${request.action}, discarding request`, err);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
this.requests = validRequests;
|
|
771
|
+
if (this.requests.length === 0) {
|
|
772
|
+
return undefined;
|
|
773
|
+
}
|
|
774
|
+
return this.sendRequests();
|
|
775
|
+
}
|
|
737
776
|
callbackBundledTransactions(requests, result, txContext) {
|
|
738
777
|
const actionsListStr = requests.map((r)=>r.action).join(', ');
|
|
739
778
|
if (result instanceof FormattedViemError) {
|
|
@@ -767,7 +806,16 @@ export class SequencerPublisher {
|
|
|
767
806
|
} else {
|
|
768
807
|
this.log.verbose(`Published bundled transactions (${actionsListStr})`, {
|
|
769
808
|
result,
|
|
770
|
-
requests
|
|
809
|
+
requests: requests.map((r)=>({
|
|
810
|
+
...r,
|
|
811
|
+
// Avoid logging large blob data
|
|
812
|
+
blobConfig: r.blobConfig ? {
|
|
813
|
+
...r.blobConfig,
|
|
814
|
+
blobs: r.blobConfig.blobs.map((b)=>({
|
|
815
|
+
size: trimmedBytesLength(b)
|
|
816
|
+
}))
|
|
817
|
+
} : undefined
|
|
818
|
+
}))
|
|
771
819
|
});
|
|
772
820
|
const successfulActions = [];
|
|
773
821
|
const failedActions = [];
|
|
@@ -816,19 +864,20 @@ export class SequencerPublisher {
|
|
|
816
864
|
}
|
|
817
865
|
}
|
|
818
866
|
/**
|
|
819
|
-
* @notice Will call `
|
|
867
|
+
* @notice Will call `canProposeAt` to make sure that it is possible to propose
|
|
820
868
|
* @param tipArchive - The archive to check
|
|
821
869
|
* @returns The slot and block number if it is possible to propose, undefined otherwise
|
|
822
|
-
*/
|
|
870
|
+
*/ async canProposeAt(tipArchive, msgSender, simulationOverridesPlan) {
|
|
823
871
|
// TODO: #14291 - should loop through multiple keys to check if any of them can propose
|
|
824
872
|
const ignoredErrors = [
|
|
825
873
|
'SlotAlreadyInChain',
|
|
826
874
|
'InvalidProposer',
|
|
827
875
|
'InvalidArchive'
|
|
828
876
|
];
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
877
|
+
const pipelined = this.epochCache.isProposerPipeliningEnabled();
|
|
878
|
+
const slotOffset = pipelined ? this.aztecSlotDuration : 0n;
|
|
879
|
+
const nextL1SlotTs = this.getNextL1SlotTimestamp() + slotOffset;
|
|
880
|
+
return this.rollupContract.canProposeAt(tipArchive.toBuffer(), msgSender.toString(), nextL1SlotTs, await buildSimulationOverridesStateOverride(this.rollupContract, simulationOverridesPlan)).catch((err)=>{
|
|
832
881
|
if (err instanceof FormattedViemError && ignoredErrors.find((e)=>err.message.includes(e))) {
|
|
833
882
|
this.log.warn(`Failed canProposeAtTime check with ${ignoredErrors.find((e)=>err.message.includes(e))}`, {
|
|
834
883
|
error: err.message
|
|
@@ -844,7 +893,7 @@ export class SequencerPublisher {
|
|
|
844
893
|
* @dev This is a convenience function that can be used by the sequencer to validate a "partial" header.
|
|
845
894
|
* It will throw if the block header is invalid.
|
|
846
895
|
* @param header - The block header to validate
|
|
847
|
-
*/ async validateBlockHeader(header,
|
|
896
|
+
*/ async validateBlockHeader(header, simulationOverridesPlan) {
|
|
848
897
|
const flags = {
|
|
849
898
|
ignoreDA: true,
|
|
850
899
|
ignoreSignatures: true
|
|
@@ -858,8 +907,8 @@ export class SequencerPublisher {
|
|
|
858
907
|
header.blobsHash.toString(),
|
|
859
908
|
flags
|
|
860
909
|
];
|
|
861
|
-
const ts =
|
|
862
|
-
const stateOverrides = await this.rollupContract
|
|
910
|
+
const ts = this.getSimulationTimestamp(header.slotNumber);
|
|
911
|
+
const stateOverrides = await buildSimulationOverridesStateOverride(this.rollupContract, simulationOverridesPlan);
|
|
863
912
|
let balance = 0n;
|
|
864
913
|
if (this.config.fishermanMode) {
|
|
865
914
|
// In fisherman mode, we can't know where the proposer is publishing from
|
|
@@ -881,7 +930,7 @@ export class SequencerPublisher {
|
|
|
881
930
|
}),
|
|
882
931
|
from: MULTI_CALL_3_ADDRESS
|
|
883
932
|
}, {
|
|
884
|
-
time: ts
|
|
933
|
+
time: ts
|
|
885
934
|
}, stateOverrides);
|
|
886
935
|
this.log.debug(`Simulated validateHeader`);
|
|
887
936
|
}
|
|
@@ -927,6 +976,7 @@ export class SequencerPublisher {
|
|
|
927
976
|
gasUsed,
|
|
928
977
|
checkpointNumber,
|
|
929
978
|
forcePendingCheckpointNumber: CheckpointNumber(checkpointNumber - 1),
|
|
979
|
+
lastArchive: validationResult.checkpoint.lastArchive,
|
|
930
980
|
reason
|
|
931
981
|
};
|
|
932
982
|
} catch (err) {
|
|
@@ -939,8 +989,8 @@ export class SequencerPublisher {
|
|
|
939
989
|
request,
|
|
940
990
|
error: viemError.message
|
|
941
991
|
});
|
|
942
|
-
const
|
|
943
|
-
if (
|
|
992
|
+
const latestProposedCheckpointNumber = await this.rollupContract.getCheckpointNumber();
|
|
993
|
+
if (latestProposedCheckpointNumber < checkpointNumber) {
|
|
944
994
|
this.log.verbose(`Checkpoint ${checkpointNumber} has already been invalidated`, {
|
|
945
995
|
...logData
|
|
946
996
|
});
|
|
@@ -1000,8 +1050,7 @@ export class SequencerPublisher {
|
|
|
1000
1050
|
throw new Error(`Unknown reason for invalidation`);
|
|
1001
1051
|
}
|
|
1002
1052
|
}
|
|
1003
|
-
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature,
|
|
1004
|
-
const ts = BigInt((await this.l1TxUtils.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
1053
|
+
/** Simulates `propose` to make sure that the checkpoint is valid for submission */ async validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, simulationOverridesPlan) {
|
|
1005
1054
|
const blobFields = checkpoint.toBlobFields();
|
|
1006
1055
|
const blobs = await getBlobsPerL1Block(blobFields);
|
|
1007
1056
|
const blobInput = getPrefixedEthBlobCommitments(blobs);
|
|
@@ -1018,10 +1067,9 @@ export class SequencerPublisher {
|
|
|
1018
1067
|
attestationsAndSignersSignature.toViemSignature(),
|
|
1019
1068
|
blobInput
|
|
1020
1069
|
];
|
|
1021
|
-
await this.simulateProposeTx(args,
|
|
1022
|
-
return ts;
|
|
1070
|
+
await this.simulateProposeTx(args, simulationOverridesPlan);
|
|
1023
1071
|
}
|
|
1024
|
-
async enqueueCastSignalHelper(slotNumber,
|
|
1072
|
+
async enqueueCastSignalHelper(slotNumber, signalType, payload, base, signerAddress, signer) {
|
|
1025
1073
|
if (this.lastActions[signalType] && this.lastActions[signalType] === slotNumber) {
|
|
1026
1074
|
this.log.debug(`Skipping duplicate vote cast signal ${signalType} for slot ${slotNumber}`);
|
|
1027
1075
|
return false;
|
|
@@ -1078,6 +1126,7 @@ export class SequencerPublisher {
|
|
|
1078
1126
|
lastValidL2Slot: slotNumber
|
|
1079
1127
|
});
|
|
1080
1128
|
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1129
|
+
const timestamp = this.getSimulationTimestamp(slotNumber);
|
|
1081
1130
|
try {
|
|
1082
1131
|
await this.l1TxUtils.simulate(request, {
|
|
1083
1132
|
time: timestamp
|
|
@@ -1090,7 +1139,10 @@ export class SequencerPublisher {
|
|
|
1090
1139
|
});
|
|
1091
1140
|
} catch (err) {
|
|
1092
1141
|
const viemError = formatViemError(err);
|
|
1093
|
-
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError
|
|
1142
|
+
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, viemError, {
|
|
1143
|
+
simulationTimestamp: timestamp,
|
|
1144
|
+
l1BlockNumber
|
|
1145
|
+
});
|
|
1094
1146
|
this.backupFailedTx({
|
|
1095
1147
|
id: keccak256(request.data),
|
|
1096
1148
|
failureType: 'simulation',
|
|
@@ -1155,55 +1207,17 @@ export class SequencerPublisher {
|
|
|
1155
1207
|
/**
|
|
1156
1208
|
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
1157
1209
|
* @param slotNumber - The slot number to cast a signal for.
|
|
1158
|
-
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
1159
1210
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
1160
|
-
*/ enqueueGovernanceCastSignal(governancePayload, slotNumber,
|
|
1161
|
-
return this.enqueueCastSignalHelper(slotNumber,
|
|
1211
|
+
*/ enqueueGovernanceCastSignal(governancePayload, slotNumber, signerAddress, signer) {
|
|
1212
|
+
return this.enqueueCastSignalHelper(slotNumber, 'governance-signal', governancePayload, this.govProposerContract, signerAddress, signer);
|
|
1162
1213
|
}
|
|
1163
|
-
/** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber,
|
|
1214
|
+
/** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber, signerAddress, signer) {
|
|
1164
1215
|
if (actions.length === 0) {
|
|
1165
1216
|
this.log.debug(`No slashing actions to enqueue for slot ${slotNumber}`);
|
|
1166
1217
|
return false;
|
|
1167
1218
|
}
|
|
1168
1219
|
for (const action of actions){
|
|
1169
1220
|
switch(action.type){
|
|
1170
|
-
case 'vote-empire-payload':
|
|
1171
|
-
{
|
|
1172
|
-
if (this.slashingProposerContract?.type !== 'empire') {
|
|
1173
|
-
this.log.error('Cannot vote for empire payload on non-empire slashing contract');
|
|
1174
|
-
break;
|
|
1175
|
-
}
|
|
1176
|
-
this.log.debug(`Enqueuing slashing vote for payload ${action.payload} at slot ${slotNumber}`, {
|
|
1177
|
-
signerAddress
|
|
1178
|
-
});
|
|
1179
|
-
await this.enqueueCastSignalHelper(slotNumber, timestamp, 'empire-slashing-signal', action.payload, this.slashingProposerContract, signerAddress, signer);
|
|
1180
|
-
break;
|
|
1181
|
-
}
|
|
1182
|
-
case 'create-empire-payload':
|
|
1183
|
-
{
|
|
1184
|
-
this.log.debug(`Enqueuing slashing create payload at slot ${slotNumber}`, {
|
|
1185
|
-
slotNumber,
|
|
1186
|
-
signerAddress
|
|
1187
|
-
});
|
|
1188
|
-
const request = this.slashFactoryContract.buildCreatePayloadRequest(action.data);
|
|
1189
|
-
await this.simulateAndEnqueueRequest('create-empire-payload', request, (receipt)=>!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs), slotNumber, timestamp);
|
|
1190
|
-
break;
|
|
1191
|
-
}
|
|
1192
|
-
case 'execute-empire-payload':
|
|
1193
|
-
{
|
|
1194
|
-
this.log.debug(`Enqueuing slashing execute payload at slot ${slotNumber}`, {
|
|
1195
|
-
slotNumber,
|
|
1196
|
-
signerAddress
|
|
1197
|
-
});
|
|
1198
|
-
if (this.slashingProposerContract?.type !== 'empire') {
|
|
1199
|
-
this.log.error('Cannot execute slashing payload on non-empire slashing contract');
|
|
1200
|
-
return false;
|
|
1201
|
-
}
|
|
1202
|
-
const empireSlashingProposer = this.slashingProposerContract;
|
|
1203
|
-
const request = empireSlashingProposer.buildExecuteRoundRequest(action.round);
|
|
1204
|
-
await this.simulateAndEnqueueRequest('execute-empire-payload', request, (receipt)=>!!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs), slotNumber, timestamp);
|
|
1205
|
-
break;
|
|
1206
|
-
}
|
|
1207
1221
|
case 'vote-offenses':
|
|
1208
1222
|
{
|
|
1209
1223
|
this.log.debug(`Enqueuing slashing vote for ${action.votes.length} votes at slot ${slotNumber}`, {
|
|
@@ -1212,14 +1226,13 @@ export class SequencerPublisher {
|
|
|
1212
1226
|
votesCount: action.votes.length,
|
|
1213
1227
|
signerAddress
|
|
1214
1228
|
});
|
|
1215
|
-
if (this.slashingProposerContract
|
|
1216
|
-
this.log.error('
|
|
1229
|
+
if (!this.slashingProposerContract) {
|
|
1230
|
+
this.log.error('No slashing proposer contract available');
|
|
1217
1231
|
return false;
|
|
1218
1232
|
}
|
|
1219
|
-
const tallySlashingProposer = this.slashingProposerContract;
|
|
1220
1233
|
const votes = bufferToHex(encodeSlashConsensusVotes(action.votes));
|
|
1221
|
-
const request = await
|
|
1222
|
-
await this.simulateAndEnqueueRequest('vote-offenses', request, (receipt)=>!!
|
|
1234
|
+
const request = await this.slashingProposerContract.buildVoteRequestFromSigner(votes, slotNumber, signer);
|
|
1235
|
+
await this.simulateAndEnqueueRequest('vote-offenses', request, (receipt)=>!!this.slashingProposerContract.tryExtractVoteCastEvent(receipt.logs), slotNumber);
|
|
1223
1236
|
break;
|
|
1224
1237
|
}
|
|
1225
1238
|
case 'execute-slash':
|
|
@@ -1229,13 +1242,12 @@ export class SequencerPublisher {
|
|
|
1229
1242
|
round: action.round,
|
|
1230
1243
|
signerAddress
|
|
1231
1244
|
});
|
|
1232
|
-
if (this.slashingProposerContract
|
|
1233
|
-
this.log.error('
|
|
1245
|
+
if (!this.slashingProposerContract) {
|
|
1246
|
+
this.log.error('No slashing proposer contract available');
|
|
1234
1247
|
return false;
|
|
1235
1248
|
}
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
await this.simulateAndEnqueueRequest('execute-slash', request, (receipt)=>!!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs), slotNumber, timestamp);
|
|
1249
|
+
const executeRequest = this.slashingProposerContract.buildExecuteRoundRequest(action.round, action.committees);
|
|
1250
|
+
await this.simulateAndEnqueueRequest('execute-slash', executeRequest, (receipt)=>!!this.slashingProposerContract.tryExtractRoundExecutedEvent(receipt.logs), slotNumber);
|
|
1239
1251
|
break;
|
|
1240
1252
|
}
|
|
1241
1253
|
default:
|
|
@@ -1259,27 +1271,40 @@ export class SequencerPublisher {
|
|
|
1259
1271
|
attestationsAndSignersSignature,
|
|
1260
1272
|
feeAssetPriceModifier: checkpoint.feeAssetPriceModifier
|
|
1261
1273
|
};
|
|
1262
|
-
|
|
1274
|
+
const simulationOverridesPlan = SimulationOverridesBuilder.from(opts.simulationOverridesPlan).withoutBlobCheck().build();
|
|
1263
1275
|
try {
|
|
1264
1276
|
// @note This will make sure that we are passing the checks for our header ASSUMING that the data is also made available
|
|
1265
1277
|
// This means that we can avoid the simulation issues in later checks.
|
|
1266
1278
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
1267
1279
|
// make time consistency checks break.
|
|
1268
1280
|
// TODO(palla): Check whether we're validating twice, once here and once within addProposeTx, since we call simulateProposeTx in both places.
|
|
1269
|
-
|
|
1281
|
+
await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, simulationOverridesPlan);
|
|
1270
1282
|
} catch (err) {
|
|
1271
1283
|
this.log.error(`Checkpoint validation failed. ${err instanceof Error ? err.message : 'No error message'}`, err, {
|
|
1272
1284
|
...checkpoint.getStats(),
|
|
1273
1285
|
slotNumber: checkpoint.header.slotNumber,
|
|
1274
|
-
|
|
1286
|
+
simulationOverridesPlan
|
|
1275
1287
|
});
|
|
1276
1288
|
throw err;
|
|
1277
1289
|
}
|
|
1290
|
+
// Build a pre-check callback that re-validates the checkpoint before L1 submission.
|
|
1291
|
+
// During pipelining this catches stale proposals due to prunes or L1 reorgs that occur during the pipeline sleep.
|
|
1292
|
+
let preCheck = undefined;
|
|
1293
|
+
if (this.epochCache.isProposerPipeliningEnabled()) {
|
|
1294
|
+
preCheck = async ()=>{
|
|
1295
|
+
this.log.debug(`Re-validating checkpoint ${checkpoint.number} before L1 submission`);
|
|
1296
|
+
await this.validateCheckpointForSubmission(checkpoint, attestationsAndSigners, attestationsAndSignersSignature, simulationOverridesPlan);
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1278
1299
|
this.log.verbose(`Enqueuing checkpoint propose transaction`, {
|
|
1279
1300
|
...checkpoint.toCheckpointInfo(),
|
|
1280
|
-
|
|
1301
|
+
txTimeoutAt: opts.txTimeoutAt,
|
|
1302
|
+
simulationOverridesPlan
|
|
1281
1303
|
});
|
|
1282
|
-
await this.addProposeTx(checkpoint, proposeTxArgs,
|
|
1304
|
+
await this.addProposeTx(checkpoint, proposeTxArgs, {
|
|
1305
|
+
txTimeoutAt: opts.txTimeoutAt,
|
|
1306
|
+
simulationOverridesPlan
|
|
1307
|
+
}, preCheck);
|
|
1283
1308
|
}
|
|
1284
1309
|
enqueueInvalidateCheckpoint(request, opts = {}) {
|
|
1285
1310
|
if (!request) {
|
|
@@ -1320,7 +1345,8 @@ export class SequencerPublisher {
|
|
|
1320
1345
|
}
|
|
1321
1346
|
});
|
|
1322
1347
|
}
|
|
1323
|
-
async simulateAndEnqueueRequest(action, request, checkSuccess, slotNumber
|
|
1348
|
+
async simulateAndEnqueueRequest(action, request, checkSuccess, slotNumber) {
|
|
1349
|
+
const timestamp = this.getSimulationTimestamp(slotNumber);
|
|
1324
1350
|
const logData = {
|
|
1325
1351
|
slotNumber,
|
|
1326
1352
|
timestamp,
|
|
@@ -1342,7 +1368,7 @@ export class SequencerPublisher {
|
|
|
1342
1368
|
try {
|
|
1343
1369
|
({ gasUsed } = await this.l1TxUtils.simulate(request, {
|
|
1344
1370
|
time: timestamp
|
|
1345
|
-
}, [], simulateAbi));
|
|
1371
|
+
}, [], simulateAbi));
|
|
1346
1372
|
this.log.verbose(`Simulation for ${action} succeeded`, {
|
|
1347
1373
|
...logData,
|
|
1348
1374
|
request,
|
|
@@ -1417,13 +1443,14 @@ export class SequencerPublisher {
|
|
|
1417
1443
|
* A call to `restart` is required before you can continue publishing.
|
|
1418
1444
|
*/ interrupt() {
|
|
1419
1445
|
this.interrupted = true;
|
|
1446
|
+
this.interruptibleSleep.interrupt();
|
|
1420
1447
|
this.l1TxUtils.interrupt();
|
|
1421
1448
|
}
|
|
1422
1449
|
/** Restarts the publisher after calling `interrupt`. */ restart() {
|
|
1423
1450
|
this.interrupted = false;
|
|
1424
1451
|
this.l1TxUtils.restart();
|
|
1425
1452
|
}
|
|
1426
|
-
async prepareProposeTx(encodedData,
|
|
1453
|
+
async prepareProposeTx(encodedData, simulationOverridesPlan) {
|
|
1427
1454
|
const kzg = Blob.getViemKzgInstance();
|
|
1428
1455
|
const blobInput = getPrefixedEthBlobCommitments(encodedData.blobs);
|
|
1429
1456
|
this.log.debug('Validating blob input', {
|
|
@@ -1500,7 +1527,7 @@ export class SequencerPublisher {
|
|
|
1500
1527
|
encodedData.attestationsAndSignersSignature.toViemSignature(),
|
|
1501
1528
|
blobInput
|
|
1502
1529
|
];
|
|
1503
|
-
const { rollupData, simulationResult } = await this.simulateProposeTx(args,
|
|
1530
|
+
const { rollupData, simulationResult } = await this.simulateProposeTx(args, simulationOverridesPlan);
|
|
1504
1531
|
return {
|
|
1505
1532
|
args,
|
|
1506
1533
|
blobEvaluationGas,
|
|
@@ -1511,29 +1538,14 @@ export class SequencerPublisher {
|
|
|
1511
1538
|
/**
|
|
1512
1539
|
* Simulates the propose tx with eth_simulateV1
|
|
1513
1540
|
* @param args - The propose tx args
|
|
1514
|
-
* @param timestamp - The timestamp to simulate proposal at
|
|
1515
1541
|
* @returns The simulation result
|
|
1516
|
-
*/ async simulateProposeTx(args,
|
|
1542
|
+
*/ async simulateProposeTx(args, simulationOverridesPlan) {
|
|
1517
1543
|
const rollupData = encodeFunctionData({
|
|
1518
1544
|
abi: RollupAbi,
|
|
1519
1545
|
functionName: 'propose',
|
|
1520
1546
|
args
|
|
1521
1547
|
});
|
|
1522
|
-
|
|
1523
|
-
const forcePendingCheckpointNumberStateDiff = (options.forcePendingCheckpointNumber !== undefined ? await this.rollupContract.makePendingCheckpointNumberOverride(options.forcePendingCheckpointNumber) : []).flatMap((override)=>override.stateDiff ?? []);
|
|
1524
|
-
const stateOverrides = [
|
|
1525
|
-
{
|
|
1526
|
-
address: this.rollupContract.address,
|
|
1527
|
-
// @note we override checkBlob to false since blobs are not part simulate()
|
|
1528
|
-
stateDiff: [
|
|
1529
|
-
{
|
|
1530
|
-
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
1531
|
-
value: toPaddedHex(0n, true)
|
|
1532
|
-
},
|
|
1533
|
-
...forcePendingCheckpointNumberStateDiff
|
|
1534
|
-
]
|
|
1535
|
-
}
|
|
1536
|
-
];
|
|
1548
|
+
const stateOverrides = await buildSimulationOverridesStateOverride(this.rollupContract, simulationOverridesPlan);
|
|
1537
1549
|
// In fisherman mode, simulate as the proposer but with sufficient balance
|
|
1538
1550
|
if (this.proposerAddressForSimulation) {
|
|
1539
1551
|
stateOverrides.push({
|
|
@@ -1542,6 +1554,7 @@ export class SequencerPublisher {
|
|
|
1542
1554
|
});
|
|
1543
1555
|
}
|
|
1544
1556
|
const l1BlockNumber = await this.l1TxUtils.getBlockNumber();
|
|
1557
|
+
const simTs = this.getSimulationTimestamp(SlotNumber.fromBigInt(args[0].header.slotNumber));
|
|
1545
1558
|
const simulationResult = await this.l1TxUtils.simulate({
|
|
1546
1559
|
to: this.rollupContract.address,
|
|
1547
1560
|
data: rollupData,
|
|
@@ -1550,8 +1563,7 @@ export class SequencerPublisher {
|
|
|
1550
1563
|
from: this.proposerAddressForSimulation.toString()
|
|
1551
1564
|
}
|
|
1552
1565
|
}, {
|
|
1553
|
-
|
|
1554
|
-
time: timestamp + 1n,
|
|
1566
|
+
time: simTs,
|
|
1555
1567
|
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit so we increase here
|
|
1556
1568
|
gasLimit: MAX_L1_TX_LIMIT * 2n
|
|
1557
1569
|
}, stateOverrides, RollupAbi, {
|
|
@@ -1568,7 +1580,9 @@ export class SequencerPublisher {
|
|
|
1568
1580
|
logs: []
|
|
1569
1581
|
};
|
|
1570
1582
|
}
|
|
1571
|
-
this.log.error(`Failed to simulate propose tx`, viemError
|
|
1583
|
+
this.log.error(`Failed to simulate propose tx`, viemError, {
|
|
1584
|
+
simulationTimestamp: simTs
|
|
1585
|
+
});
|
|
1572
1586
|
this.backupFailedTx({
|
|
1573
1587
|
id: keccak256(rollupData),
|
|
1574
1588
|
failureType: 'simulation',
|
|
@@ -1596,11 +1610,11 @@ export class SequencerPublisher {
|
|
|
1596
1610
|
simulationResult
|
|
1597
1611
|
};
|
|
1598
1612
|
}
|
|
1599
|
-
async addProposeTx(checkpoint, encodedData, opts = {},
|
|
1613
|
+
async addProposeTx(checkpoint, encodedData, opts = {}, preCheck) {
|
|
1600
1614
|
const slot = checkpoint.header.slotNumber;
|
|
1601
1615
|
const timer = new Timer();
|
|
1602
1616
|
const kzg = Blob.getViemKzgInstance();
|
|
1603
|
-
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData,
|
|
1617
|
+
const { rollupData, simulationResult, blobEvaluationGas } = await this.prepareProposeTx(encodedData, opts.simulationOverridesPlan);
|
|
1604
1618
|
const startBlock = await this.l1TxUtils.getBlockNumber();
|
|
1605
1619
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(simulationResult.gasUsed) * 64 / 63)) + blobEvaluationGas + SequencerPublisher.MULTICALL_OVERHEAD_GAS_GUESS);
|
|
1606
1620
|
// Send the blobs to the blob client preemptively. This helps in tests where the sequencer mistakingly thinks that the propose
|
|
@@ -1616,9 +1630,10 @@ export class SequencerPublisher {
|
|
|
1616
1630
|
},
|
|
1617
1631
|
lastValidL2Slot: checkpoint.header.slotNumber,
|
|
1618
1632
|
gasConfig: {
|
|
1619
|
-
|
|
1633
|
+
txTimeoutAt: opts.txTimeoutAt,
|
|
1620
1634
|
gasLimit
|
|
1621
1635
|
},
|
|
1636
|
+
preCheck,
|
|
1622
1637
|
blobConfig: {
|
|
1623
1638
|
blobs: encodedData.blobs.map((b)=>b.data),
|
|
1624
1639
|
kzg
|
|
@@ -1665,4 +1680,13 @@ export class SequencerPublisher {
|
|
|
1665
1680
|
}
|
|
1666
1681
|
});
|
|
1667
1682
|
}
|
|
1683
|
+
/** Returns the timestamp of the last L1 slot within a given L2 slot. Used as the simulation timestamp
|
|
1684
|
+
* for eth_simulateV1 calls, since it's guaranteed to be greater than any L1 block produced during the slot. */ getSimulationTimestamp(slot) {
|
|
1685
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
1686
|
+
return getLastL1SlotTimestampForL2Slot(slot, l1Constants);
|
|
1687
|
+
}
|
|
1688
|
+
/** Returns the timestamp of the next L1 slot boundary after now. */ getNextL1SlotTimestamp() {
|
|
1689
|
+
const l1Constants = this.epochCache.getL1Constants();
|
|
1690
|
+
return getNextL1SlotTimestamp(this.dateProvider.nowInSeconds(), l1Constants);
|
|
1691
|
+
}
|
|
1668
1692
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { RollupContract, type SimulationOverridesPlan } from '@aztec/ethereum/contracts';
|
|
2
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
5
|
+
import type { ProposedCheckpointData } from '@aztec/stdlib/checkpoint';
|
|
6
|
+
type PipelinedParentSimulationOverridesPlanInput = {
|
|
7
|
+
checkpointNumber: CheckpointNumber;
|
|
8
|
+
proposedCheckpointData?: ProposedCheckpointData;
|
|
9
|
+
rollup: RollupContract;
|
|
10
|
+
log: Logger;
|
|
11
|
+
};
|
|
12
|
+
type SubmissionSimulationOverridesPlanInput = {
|
|
13
|
+
pipelinedParentPlan?: SimulationOverridesPlan;
|
|
14
|
+
invalidateToPendingCheckpointNumber?: CheckpointNumber;
|
|
15
|
+
lastArchiveRoot: Fr;
|
|
16
|
+
pipeliningEnabled: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** Builds the simulated parent checkpoint view used while constructing a pipelined proposal. */
|
|
19
|
+
export declare function buildPipelinedParentSimulationOverridesPlan(input: PipelinedParentSimulationOverridesPlanInput): Promise<SimulationOverridesPlan | undefined>;
|
|
20
|
+
/** Builds the simulated chain view used when validating and enqueueing checkpoint submission. */
|
|
21
|
+
export declare function buildSubmissionSimulationOverridesPlan(input: SubmissionSimulationOverridesPlanInput): SimulationOverridesPlan | undefined;
|
|
22
|
+
/** Derives the pending parent fee header used during pipelined proposal simulation. */
|
|
23
|
+
export declare function computePipelinedParentFeeHeader(input: PipelinedParentSimulationOverridesPlanInput): Promise<import("@aztec/ethereum/contracts").FeeHeader | undefined>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhaW5fc3RhdGVfb3ZlcnJpZGVzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VxdWVuY2VyL2NoYWluX3N0YXRlX292ZXJyaWRlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUE4QixLQUFLLHVCQUF1QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDckgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxLQUFLLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDekQsT0FBTyxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDcEQsT0FBTyxLQUFLLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV2RSxLQUFLLDJDQUEyQyxHQUFHO0lBQ2pELGdCQUFnQixFQUFFLGdCQUFnQixDQUFDO0lBQ25DLHNCQUFzQixDQUFDLEVBQUUsc0JBQXNCLENBQUM7SUFDaEQsTUFBTSxFQUFFLGNBQWMsQ0FBQztJQUN2QixHQUFHLEVBQUUsTUFBTSxDQUFDO0NBQ2IsQ0FBQztBQUVGLEtBQUssc0NBQXNDLEdBQUc7SUFDNUMsbUJBQW1CLENBQUMsRUFBRSx1QkFBdUIsQ0FBQztJQUM5QyxtQ0FBbUMsQ0FBQyxFQUFFLGdCQUFnQixDQUFDO0lBQ3ZELGVBQWUsRUFBRSxFQUFFLENBQUM7SUFDcEIsaUJBQWlCLEVBQUUsT0FBTyxDQUFDO0NBQzVCLENBQUM7QUFFRixnR0FBZ0c7QUFDaEcsd0JBQXNCLDJDQUEyQyxDQUMvRCxLQUFLLEVBQUUsMkNBQTJDLEdBQ2pELE9BQU8sQ0FBQyx1QkFBdUIsR0FBRyxTQUFTLENBQUMsQ0FVOUM7QUFFRCxpR0FBaUc7QUFDakcsd0JBQWdCLHNDQUFzQyxDQUNwRCxLQUFLLEVBQUUsc0NBQXNDLEdBQzVDLHVCQUF1QixHQUFHLFNBQVMsQ0FhckM7QUFFRCx1RkFBdUY7QUFDdkYsd0JBQXNCLCtCQUErQixDQUFDLEtBQUssRUFBRSwyQ0FBMkMsc0VBZ0N2RyJ9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain_state_overrides.d.ts","sourceRoot":"","sources":["../../src/sequencer/chain_state_overrides.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA8B,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACrH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,KAAK,2CAA2C,GAAG;IACjD,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,MAAM,EAAE,cAAc,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,sCAAsC,GAAG;IAC5C,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;IAC9C,mCAAmC,CAAC,EAAE,gBAAgB,CAAC;IACvD,eAAe,EAAE,EAAE,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,gGAAgG;AAChG,wBAAsB,2CAA2C,CAC/D,KAAK,EAAE,2CAA2C,GACjD,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,CAU9C;AAED,iGAAiG;AACjG,wBAAgB,sCAAsC,CACpD,KAAK,EAAE,sCAAsC,GAC5C,uBAAuB,GAAG,SAAS,CAarC;AAED,uFAAuF;AACvF,wBAAsB,+BAA+B,CAAC,KAAK,EAAE,2CAA2C,sEAgCvG"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { RollupContract, SimulationOverridesBuilder } from '@aztec/ethereum/contracts';
|
|
2
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
/** Builds the simulated parent checkpoint view used while constructing a pipelined proposal. */ export async function buildPipelinedParentSimulationOverridesPlan(input) {
|
|
4
|
+
const parentCheckpointNumber = CheckpointNumber(input.checkpointNumber - 1);
|
|
5
|
+
const builder = new SimulationOverridesBuilder().forPendingCheckpoint(parentCheckpointNumber);
|
|
6
|
+
const pendingFeeHeader = await computePipelinedParentFeeHeader(input);
|
|
7
|
+
if (pendingFeeHeader) {
|
|
8
|
+
builder.withPendingFeeHeader(pendingFeeHeader);
|
|
9
|
+
}
|
|
10
|
+
return builder.build();
|
|
11
|
+
}
|
|
12
|
+
/** Builds the simulated chain view used when validating and enqueueing checkpoint submission. */ export function buildSubmissionSimulationOverridesPlan(input) {
|
|
13
|
+
const pendingCheckpointNumber = input.invalidateToPendingCheckpointNumber ?? input.pipelinedParentPlan?.pendingCheckpointNumber;
|
|
14
|
+
const builder = SimulationOverridesBuilder.from(input.pipelinedParentPlan).forPendingCheckpoint(pendingCheckpointNumber);
|
|
15
|
+
if (input.pipeliningEnabled && pendingCheckpointNumber !== undefined) {
|
|
16
|
+
builder.withPendingArchive(input.lastArchiveRoot);
|
|
17
|
+
}
|
|
18
|
+
return builder.build();
|
|
19
|
+
}
|
|
20
|
+
/** Derives the pending parent fee header used during pipelined proposal simulation. */ export async function computePipelinedParentFeeHeader(input) {
|
|
21
|
+
if (!input.proposedCheckpointData || input.checkpointNumber < 2) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const grandparentCheckpointNumber = CheckpointNumber(input.checkpointNumber - 2);
|
|
25
|
+
try {
|
|
26
|
+
const [grandparentCheckpoint, manaTarget] = await Promise.all([
|
|
27
|
+
input.rollup.getCheckpoint(grandparentCheckpointNumber),
|
|
28
|
+
input.rollup.getManaTarget()
|
|
29
|
+
]);
|
|
30
|
+
if (!grandparentCheckpoint?.feeHeader) {
|
|
31
|
+
input.log.error(`Grandparent checkpoint or feeHeader missing for checkpoint ${grandparentCheckpointNumber.toString()}`);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return RollupContract.computeChildFeeHeader(grandparentCheckpoint.feeHeader, input.proposedCheckpointData.totalManaUsed, input.proposedCheckpointData.feeAssetPriceModifier, manaTarget);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
input.log.error(`Failed to derive pipelined parent fee header for checkpoint ${grandparentCheckpointNumber.toString()}: ${err}`);
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|