@aztec/ethereum 0.0.1-commit.3fd054f6 → 0.0.1-commit.431c48d
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.d.ts +19 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +52 -3
- package/dest/config.d.ts +15 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +29 -9
- package/dest/contracts/chain_state_override.d.ts +78 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +137 -0
- package/dest/contracts/empire_base.d.ts +1 -3
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.d.ts +6 -2
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -1
- package/dest/contracts/fee_asset_price_oracle.js +11 -6
- package/dest/contracts/governance.d.ts +135 -35
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +226 -15
- package/dest/contracts/governance_proposer.d.ts +33 -4
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +52 -13
- package/dest/contracts/gse.d.ts +4 -2
- package/dest/contracts/gse.d.ts.map +1 -1
- package/dest/contracts/gse.js +2 -2
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +12 -7
- package/dest/contracts/index.d.ts +3 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -2
- package/dest/contracts/multicall.d.ts +79 -13
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +117 -95
- package/dest/contracts/outbox.d.ts +27 -4
- package/dest/contracts/outbox.d.ts.map +1 -1
- package/dest/contracts/outbox.js +34 -7
- package/dest/contracts/rollup.d.ts +5418 -28
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +389 -95
- package/dest/contracts/slashing_proposer.d.ts +171 -0
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/slashing_proposer.js +753 -0
- package/dest/contracts/watch_event.d.ts +36 -0
- package/dest/contracts/watch_event.d.ts.map +1 -0
- package/dest/contracts/watch_event.js +66 -0
- package/dest/deploy_aztec_l1_contracts.d.ts +4 -7
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +15 -8
- package/dest/foundry_binary.d.ts +13 -0
- package/dest/foundry_binary.d.ts.map +1 -0
- package/dest/foundry_binary.js +52 -0
- package/dest/generated/l1-contracts-defaults.d.ts +2 -2
- package/dest/generated/l1-contracts-defaults.js +2 -2
- package/dest/l1_artifacts.d.ts +14941 -16273
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +61 -65
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +101 -82
- package/dest/l1_reader.d.ts +3 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +3 -6
- package/dest/l1_tx_utils/config.js +3 -3
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +9 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +115 -54
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +49 -19
- package/dest/l1_tx_utils/tx_delayer.d.ts +5 -3
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -1
- package/dest/l1_tx_utils/tx_delayer.js +7 -5
- package/dest/publisher_manager.d.ts +18 -6
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +44 -7
- package/dest/queries.d.ts +13 -2
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +62 -3
- package/dest/test/blob_kzg_warmup.d.ts +19 -0
- package/dest/test/blob_kzg_warmup.d.ts.map +1 -0
- package/dest/test/blob_kzg_warmup.js +64 -0
- package/dest/test/chain_monitor.d.ts +34 -2
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +76 -6
- package/dest/test/eth_cheat_codes.d.ts +26 -3
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +61 -40
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -0
- package/dest/test/recording_rpc_server.d.ts +18 -0
- package/dest/test/recording_rpc_server.d.ts.map +1 -0
- package/dest/test/recording_rpc_server.js +68 -0
- package/dest/test/rollup_cheat_codes.d.ts +60 -3
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +86 -7
- package/dest/test/start_anvil.d.ts +1 -1
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +41 -5
- package/dest/utils.d.ts +9 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +45 -14
- package/package.json +6 -6
- package/src/client.ts +63 -1
- package/src/config.ts +44 -13
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/empire_base.ts +0 -2
- package/src/contracts/fee_asset_price_oracle.ts +10 -5
- package/src/contracts/governance.ts +310 -10
- package/src/contracts/governance_proposer.ts +56 -13
- package/src/contracts/gse.ts +7 -2
- package/src/contracts/inbox.ts +13 -5
- package/src/contracts/index.ts +2 -2
- package/src/contracts/multicall.ts +179 -105
- package/src/contracts/outbox.ts +42 -8
- package/src/contracts/rollup.ts +429 -86
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +119 -45
- package/src/contracts/watch_event.ts +110 -0
- package/src/deploy_aztec_l1_contracts.ts +19 -10
- package/src/foundry_binary.ts +57 -0
- package/src/generated/l1-contracts-defaults.ts +2 -2
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -94
- package/src/l1_reader.ts +4 -9
- package/src/l1_tx_utils/config.ts +3 -3
- package/src/l1_tx_utils/l1_tx_utils.ts +107 -50
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +49 -13
- package/src/l1_tx_utils/tx_delayer.ts +16 -7
- package/src/publisher_manager.ts +54 -18
- package/src/queries.ts +70 -4
- package/src/test/blob_kzg_warmup.ts +65 -0
- package/src/test/chain_monitor.ts +93 -5
- package/src/test/eth_cheat_codes.ts +57 -43
- package/src/test/index.ts +1 -0
- package/src/test/recording_rpc_server.ts +69 -0
- package/src/test/rollup_cheat_codes.ts +115 -6
- package/src/test/start_anvil.ts +38 -6
- package/src/utils.ts +41 -17
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -69
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -216
- package/dest/contracts/tally_slashing_proposer.d.ts +0 -140
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/tally_slashing_proposer.js +0 -320
- package/src/contracts/empire_slashing_proposer.ts +0 -265
package/dest/contracts/rollup.js
CHANGED
|
@@ -376,25 +376,21 @@ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
|
376
376
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
377
377
|
import { memoize } from '@aztec/foundation/decorators';
|
|
378
378
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
379
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
379
380
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
381
|
+
import { getErrorCause } from '@aztec/foundation/types';
|
|
380
382
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
381
383
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
382
384
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
383
385
|
import chunk from 'lodash.chunk';
|
|
384
|
-
import { encodeFunctionData, getContract, hexToBigInt, keccak256 } from 'viem';
|
|
386
|
+
import { ContractFunctionRevertedError, RpcRequestError, decodeErrorResult, encodeAbiParameters, encodeFunctionData, getContract, hexToBigInt, keccak256 } from 'viem';
|
|
385
387
|
import { getPublicClient } from '../client.js';
|
|
386
388
|
import { formatViemError } from '../utils.js';
|
|
387
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
388
389
|
import { GSEContract } from './gse.js';
|
|
389
390
|
import { SlasherContract } from './slasher_contract.js';
|
|
390
|
-
import {
|
|
391
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
391
392
|
import { checkBlockTag } from './utils.js';
|
|
392
|
-
|
|
393
|
-
SlashingProposerType[SlashingProposerType["None"] = 0] = "None";
|
|
394
|
-
SlashingProposerType[SlashingProposerType["Tally"] = 1] = "Tally";
|
|
395
|
-
SlashingProposerType[SlashingProposerType["Empire"] = 2] = "Empire";
|
|
396
|
-
return SlashingProposerType;
|
|
397
|
-
}({});
|
|
393
|
+
import { watchContractEvent } from './watch_event.js';
|
|
398
394
|
/**
|
|
399
395
|
* Status of a validator/attester in the staking system.
|
|
400
396
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -405,6 +401,38 @@ export var SlashingProposerType = /*#__PURE__*/ function(SlashingProposerType) {
|
|
|
405
401
|
AttesterStatus[AttesterStatus["EXITING"] = 3] = "EXITING";
|
|
406
402
|
return AttesterStatus;
|
|
407
403
|
}({});
|
|
404
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */ export var TempCheckpointLogField = /*#__PURE__*/ function(TempCheckpointLogField) {
|
|
405
|
+
TempCheckpointLogField[TempCheckpointLogField["HeaderHash"] = 0] = "HeaderHash";
|
|
406
|
+
TempCheckpointLogField[TempCheckpointLogField["BlobCommitmentsHash"] = 1] = "BlobCommitmentsHash";
|
|
407
|
+
TempCheckpointLogField[TempCheckpointLogField["OutHash"] = 2] = "OutHash";
|
|
408
|
+
TempCheckpointLogField[TempCheckpointLogField["AttestationsHash"] = 3] = "AttestationsHash";
|
|
409
|
+
TempCheckpointLogField[TempCheckpointLogField["PayloadDigest"] = 4] = "PayloadDigest";
|
|
410
|
+
TempCheckpointLogField[TempCheckpointLogField["SlotNumber"] = 5] = "SlotNumber";
|
|
411
|
+
TempCheckpointLogField[TempCheckpointLogField["FeeHeader"] = 6] = "FeeHeader";
|
|
412
|
+
return TempCheckpointLogField;
|
|
413
|
+
}({});
|
|
414
|
+
const INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR = 'ValidatorSelection__InsufficientValidatorSetSize';
|
|
415
|
+
/** SlasherUpdated events are rare governance operations, so their watcher polls well below the client's interval. */ const SLASHER_UPDATED_POLLING_INTERVAL_MS = 60_000;
|
|
416
|
+
function isValidatorSelectionError(err, errorName) {
|
|
417
|
+
return getErrorCause(err, ContractFunctionRevertedError)?.data?.errorName === errorName || decodeRpcRequestErrorName(err) === errorName;
|
|
418
|
+
}
|
|
419
|
+
function decodeRpcRequestErrorName(err) {
|
|
420
|
+
const data = getErrorCause(err, RpcRequestError)?.data;
|
|
421
|
+
if (!isHexString(data)) {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
return decodeErrorResult({
|
|
426
|
+
abi: RollupAbi,
|
|
427
|
+
data
|
|
428
|
+
}).errorName;
|
|
429
|
+
} catch {
|
|
430
|
+
return undefined;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
function isHexString(value) {
|
|
434
|
+
return typeof value === 'string' && value.startsWith('0x');
|
|
435
|
+
}
|
|
408
436
|
export class RollupContract {
|
|
409
437
|
client;
|
|
410
438
|
static{
|
|
@@ -517,6 +545,7 @@ export class RollupContract {
|
|
|
517
545
|
], []));
|
|
518
546
|
}
|
|
519
547
|
rollup;
|
|
548
|
+
logger;
|
|
520
549
|
static cachedStfStorageSlot;
|
|
521
550
|
cachedEscapeHatch;
|
|
522
551
|
static get checkBlobStorageSlot() {
|
|
@@ -535,12 +564,12 @@ export class RollupContract {
|
|
|
535
564
|
}
|
|
536
565
|
static getFromConfig(config) {
|
|
537
566
|
const client = getPublicClient(config);
|
|
538
|
-
const address = config.
|
|
567
|
+
const address = config.rollupAddress.toString();
|
|
539
568
|
return new RollupContract(client, address);
|
|
540
569
|
}
|
|
541
570
|
constructor(client, address){
|
|
542
571
|
this.client = client;
|
|
543
|
-
_initProto(this);
|
|
572
|
+
this.logger = (_initProto(this), createLogger('ethereum:rollup'));
|
|
544
573
|
if (address instanceof EthAddress) {
|
|
545
574
|
address = address.toString();
|
|
546
575
|
}
|
|
@@ -565,34 +594,10 @@ export class RollupContract {
|
|
|
565
594
|
return undefined;
|
|
566
595
|
}
|
|
567
596
|
const proposerAddress = await slasher.getProposer();
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
type: 'function',
|
|
571
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
572
|
-
inputs: [],
|
|
573
|
-
outputs: [
|
|
574
|
-
{
|
|
575
|
-
name: '',
|
|
576
|
-
type: 'uint8',
|
|
577
|
-
internalType: 'enum SlasherFlavor'
|
|
578
|
-
}
|
|
579
|
-
],
|
|
580
|
-
stateMutability: 'view'
|
|
581
|
-
}
|
|
582
|
-
];
|
|
583
|
-
const proposer = getContract({
|
|
584
|
-
address: proposerAddress.toString(),
|
|
585
|
-
abi: proposerAbi,
|
|
586
|
-
client: this.client
|
|
587
|
-
});
|
|
588
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
589
|
-
if (proposerType === 1..valueOf()) {
|
|
590
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
591
|
-
} else if (proposerType === 2..valueOf()) {
|
|
592
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
593
|
-
} else {
|
|
594
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
597
|
+
if (proposerAddress.isZero()) {
|
|
598
|
+
return undefined;
|
|
595
599
|
}
|
|
600
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
596
601
|
}
|
|
597
602
|
getL1StartBlock() {
|
|
598
603
|
return this.rollup.read.L1_BLOCK_AT_GENESIS();
|
|
@@ -733,7 +738,11 @@ export class RollupContract {
|
|
|
733
738
|
BigInt(epoch)
|
|
734
739
|
]);
|
|
735
740
|
return isOpen;
|
|
736
|
-
} catch
|
|
741
|
+
} catch (err) {
|
|
742
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
743
|
+
epoch: Number(epoch),
|
|
744
|
+
error: err
|
|
745
|
+
});
|
|
737
746
|
return false;
|
|
738
747
|
}
|
|
739
748
|
}
|
|
@@ -749,8 +758,9 @@ export class RollupContract {
|
|
|
749
758
|
async getOwner() {
|
|
750
759
|
return EthAddress.fromString(await this.rollup.read.owner());
|
|
751
760
|
}
|
|
752
|
-
async getActiveAttesterCount() {
|
|
753
|
-
|
|
761
|
+
async getActiveAttesterCount(options) {
|
|
762
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
763
|
+
return Number(await this.rollup.read.getActiveAttesterCount(options));
|
|
754
764
|
}
|
|
755
765
|
async getSlashingProposerAddress() {
|
|
756
766
|
const slasher = await this.getSlasherContract();
|
|
@@ -762,25 +772,40 @@ export class RollupContract {
|
|
|
762
772
|
getCheckpointReward() {
|
|
763
773
|
return this.rollup.read.getCheckpointReward();
|
|
764
774
|
}
|
|
765
|
-
async getCheckpointNumber() {
|
|
766
|
-
|
|
775
|
+
async getCheckpointNumber(options) {
|
|
776
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
777
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
767
778
|
}
|
|
768
779
|
async getProvenCheckpointNumber(options) {
|
|
769
780
|
await checkBlockTag(options?.blockNumber, this.client);
|
|
770
781
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
771
782
|
}
|
|
772
|
-
async getSlotNumber() {
|
|
773
|
-
|
|
783
|
+
async getSlotNumber(options) {
|
|
784
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
785
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
774
786
|
}
|
|
775
|
-
async getL1FeesAt(timestamp) {
|
|
787
|
+
async getL1FeesAt(timestamp, options) {
|
|
788
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
776
789
|
const result = await this.rollup.read.getL1FeesAt([
|
|
777
790
|
timestamp
|
|
778
|
-
]);
|
|
791
|
+
], options);
|
|
779
792
|
return {
|
|
780
793
|
baseFee: result.baseFee,
|
|
781
794
|
blobFee: result.blobFee
|
|
782
795
|
};
|
|
783
796
|
}
|
|
797
|
+
async getFeeHeader(checkpointNumber) {
|
|
798
|
+
const result = await this.rollup.read.getFeeHeader([
|
|
799
|
+
checkpointNumber
|
|
800
|
+
]);
|
|
801
|
+
return {
|
|
802
|
+
excessMana: result.excessMana,
|
|
803
|
+
manaUsed: result.manaUsed,
|
|
804
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
805
|
+
congestionCost: result.congestionCost,
|
|
806
|
+
proverCost: result.proverCost
|
|
807
|
+
};
|
|
808
|
+
}
|
|
784
809
|
getEthPerFeeAsset() {
|
|
785
810
|
return this.rollup.read.getEthPerFeeAsset();
|
|
786
811
|
}
|
|
@@ -793,7 +818,7 @@ export class RollupContract {
|
|
|
793
818
|
timestamp
|
|
794
819
|
]
|
|
795
820
|
}).catch((e)=>{
|
|
796
|
-
if (e
|
|
821
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
797
822
|
return {
|
|
798
823
|
result: undefined
|
|
799
824
|
};
|
|
@@ -820,7 +845,7 @@ export class RollupContract {
|
|
|
820
845
|
functionName: 'getCurrentEpochCommittee',
|
|
821
846
|
args: []
|
|
822
847
|
}).catch((e)=>{
|
|
823
|
-
if (e
|
|
848
|
+
if (isValidatorSelectionError(e, INSUFFICIENT_VALIDATOR_SET_SIZE_ERROR)) {
|
|
824
849
|
return {
|
|
825
850
|
result: undefined
|
|
826
851
|
};
|
|
@@ -849,10 +874,11 @@ export class RollupContract {
|
|
|
849
874
|
});
|
|
850
875
|
return EthAddress.fromString(result);
|
|
851
876
|
}
|
|
852
|
-
async getCheckpoint(checkpointNumber) {
|
|
877
|
+
async getCheckpoint(checkpointNumber, options) {
|
|
878
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
853
879
|
const result = await this.rollup.read.getCheckpoint([
|
|
854
880
|
BigInt(checkpointNumber)
|
|
855
|
-
]);
|
|
881
|
+
], options);
|
|
856
882
|
return {
|
|
857
883
|
archive: Fr.fromString(result.archive),
|
|
858
884
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -882,6 +908,28 @@ export class RollupContract {
|
|
|
882
908
|
0.5
|
|
883
909
|
]));
|
|
884
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
913
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
914
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
915
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
916
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
917
|
+
*/ getEffectivePendingCheckpoint(atTimestamp, options) {
|
|
918
|
+
return retry(async ()=>{
|
|
919
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
920
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
921
|
+
if (canPrune) {
|
|
922
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
923
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
924
|
+
}
|
|
925
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
926
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
927
|
+
}, 'getting effective pending checkpoint', makeBackoff([
|
|
928
|
+
0.5,
|
|
929
|
+
0.5,
|
|
930
|
+
0.5
|
|
931
|
+
]));
|
|
932
|
+
}
|
|
885
933
|
async getTips() {
|
|
886
934
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
887
935
|
return {
|
|
@@ -966,7 +1014,7 @@ export class RollupContract {
|
|
|
966
1014
|
* @return [slot, checkpointNumber, timeOfNextL1Slot] - If you can propose, the L2 slot number, checkpoint number and
|
|
967
1015
|
* timestamp of the next L1 block
|
|
968
1016
|
* @throws otherwise
|
|
969
|
-
*/ async canProposeAt(archive, account, timestamp,
|
|
1017
|
+
*/ async canProposeAt(archive, account, timestamp, stateOverride = []) {
|
|
970
1018
|
const timeOfNextL1Slot = timestamp;
|
|
971
1019
|
const who = typeof account === 'string' ? account : account.address;
|
|
972
1020
|
try {
|
|
@@ -980,7 +1028,7 @@ export class RollupContract {
|
|
|
980
1028
|
who
|
|
981
1029
|
],
|
|
982
1030
|
account,
|
|
983
|
-
stateOverride
|
|
1031
|
+
stateOverride
|
|
984
1032
|
});
|
|
985
1033
|
return {
|
|
986
1034
|
slot: SlotNumber.fromBigInt(slot),
|
|
@@ -992,11 +1040,15 @@ export class RollupContract {
|
|
|
992
1040
|
}
|
|
993
1041
|
}
|
|
994
1042
|
/**
|
|
995
|
-
* Returns a state override that sets the pending
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
|
|
999
|
-
|
|
1043
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
1044
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
1045
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
1046
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
1047
|
+
*
|
|
1048
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
1049
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
1050
|
+
*/ async makeChainTipsOverride(override) {
|
|
1051
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
1000
1052
|
return [];
|
|
1001
1053
|
}
|
|
1002
1054
|
const slot = RollupContract.stfStorageSlot;
|
|
@@ -1004,8 +1056,15 @@ export class RollupContract {
|
|
|
1004
1056
|
address: this.address,
|
|
1005
1057
|
slot
|
|
1006
1058
|
});
|
|
1007
|
-
const
|
|
1008
|
-
const
|
|
1059
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
1060
|
+
const currentPending = currentRaw >> 128n;
|
|
1061
|
+
const currentProven = currentRaw & (1n << 128n) - 1n;
|
|
1062
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
1063
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
1064
|
+
if (newProven > newPending) {
|
|
1065
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
1066
|
+
}
|
|
1067
|
+
const newValue = newPending << 128n | newProven;
|
|
1009
1068
|
return [
|
|
1010
1069
|
{
|
|
1011
1070
|
address: this.address,
|
|
@@ -1018,6 +1077,161 @@ export class RollupContract {
|
|
|
1018
1077
|
}
|
|
1019
1078
|
];
|
|
1020
1079
|
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
1082
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
1083
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
1084
|
+
*
|
|
1085
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
1086
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
1087
|
+
*/ async makeTempCheckpointLogOverride(checkpointNumber, fields) {
|
|
1088
|
+
const constants = await this.getRollupConstants();
|
|
1089
|
+
const slotAt = (field)=>`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}`;
|
|
1090
|
+
const word = (v)=>`0x${v.toString(16).padStart(64, '0')}`;
|
|
1091
|
+
const stateDiff = [];
|
|
1092
|
+
if (fields.headerHash) {
|
|
1093
|
+
stateDiff.push({
|
|
1094
|
+
slot: slotAt(0),
|
|
1095
|
+
value: fields.headerHash.toString()
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
if (fields.outHash) {
|
|
1099
|
+
stateDiff.push({
|
|
1100
|
+
slot: slotAt(2),
|
|
1101
|
+
value: fields.outHash.toString()
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
if (fields.payloadDigest) {
|
|
1105
|
+
stateDiff.push({
|
|
1106
|
+
slot: slotAt(4),
|
|
1107
|
+
value: fields.payloadDigest.toString()
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
if (fields.slotNumber !== undefined) {
|
|
1111
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
1112
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
1113
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
1114
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
1115
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
1116
|
+
}
|
|
1117
|
+
stateDiff.push({
|
|
1118
|
+
slot: slotAt(5),
|
|
1119
|
+
value: word(slotNumber)
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
if (fields.feeHeader) {
|
|
1123
|
+
stateDiff.push({
|
|
1124
|
+
slot: slotAt(6),
|
|
1125
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader))
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
if (stateDiff.length === 0) {
|
|
1129
|
+
return [];
|
|
1130
|
+
}
|
|
1131
|
+
return [
|
|
1132
|
+
{
|
|
1133
|
+
address: this.address,
|
|
1134
|
+
stateDiff
|
|
1135
|
+
}
|
|
1136
|
+
];
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
1140
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
1141
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
1142
|
+
*/ makeArchiveOverride(checkpointNumber, archive) {
|
|
1143
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
1144
|
+
const archiveSlot = hexToBigInt(keccak256(encodeAbiParameters([
|
|
1145
|
+
{
|
|
1146
|
+
type: 'uint256'
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
type: 'uint256'
|
|
1150
|
+
}
|
|
1151
|
+
], [
|
|
1152
|
+
BigInt(checkpointNumber),
|
|
1153
|
+
archivesMappingBase
|
|
1154
|
+
])));
|
|
1155
|
+
return [
|
|
1156
|
+
{
|
|
1157
|
+
address: this.address,
|
|
1158
|
+
stateDiff: [
|
|
1159
|
+
{
|
|
1160
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
1161
|
+
value: archive.toString()
|
|
1162
|
+
}
|
|
1163
|
+
]
|
|
1164
|
+
}
|
|
1165
|
+
];
|
|
1166
|
+
}
|
|
1167
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */ static mergeStateOverrides(...overrides) {
|
|
1168
|
+
const byAddress = new Map();
|
|
1169
|
+
for (const override of overrides){
|
|
1170
|
+
for (const entry of override){
|
|
1171
|
+
const key = entry.address.toLowerCase();
|
|
1172
|
+
const existing = byAddress.get(key);
|
|
1173
|
+
if (existing) {
|
|
1174
|
+
existing.stateDiff.push(...entry.stateDiff ?? []);
|
|
1175
|
+
if (entry.balance !== undefined) {
|
|
1176
|
+
existing.balance = entry.balance;
|
|
1177
|
+
}
|
|
1178
|
+
} else {
|
|
1179
|
+
byAddress.set(key, {
|
|
1180
|
+
address: entry.address,
|
|
1181
|
+
balance: entry.balance,
|
|
1182
|
+
stateDiff: [
|
|
1183
|
+
...entry.stateDiff ?? []
|
|
1184
|
+
]
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
return [
|
|
1190
|
+
...byAddress.values()
|
|
1191
|
+
];
|
|
1192
|
+
}
|
|
1193
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */ static compressFeeHeader(feeHeader) {
|
|
1194
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1195
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1196
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1197
|
+
let value = BigInt(feeHeader.manaUsed) & (1n << 32n) - 1n; // bits [0:31]
|
|
1198
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1199
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1200
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1201
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1202
|
+
value |= 1n << 255n; // preheat flag
|
|
1203
|
+
return value;
|
|
1204
|
+
}
|
|
1205
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1206
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */ static computeChildFeeHeader(parentFeeHeader, childManaUsed, feeAssetPriceModifier, manaTarget) {
|
|
1207
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1208
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1209
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1210
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1211
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1212
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1213
|
+
const parentPrice = parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1214
|
+
let newPrice;
|
|
1215
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1216
|
+
newPrice = parentPrice * (10_000n + feeAssetPriceModifier) / 10_000n;
|
|
1217
|
+
} else {
|
|
1218
|
+
const absMod = -feeAssetPriceModifier;
|
|
1219
|
+
newPrice = parentPrice * (10_000n - absMod) / 10_000n;
|
|
1220
|
+
}
|
|
1221
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1222
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1223
|
+
}
|
|
1224
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1225
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1226
|
+
}
|
|
1227
|
+
return {
|
|
1228
|
+
excessMana,
|
|
1229
|
+
manaUsed: childManaUsed,
|
|
1230
|
+
ethPerFeeAsset: newPrice,
|
|
1231
|
+
congestionCost: 0n,
|
|
1232
|
+
proverCost: 0n
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1021
1235
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */ buildInvalidateBadAttestationRequest(checkpointNumber, attestationsAndSigners, committee, invalidIndex) {
|
|
1022
1236
|
return {
|
|
1023
1237
|
to: this.address,
|
|
@@ -1059,11 +1273,13 @@ export class RollupContract {
|
|
|
1059
1273
|
prover
|
|
1060
1274
|
]);
|
|
1061
1275
|
}
|
|
1062
|
-
getManaMinFeeAt(timestamp, inFeeAsset) {
|
|
1276
|
+
getManaMinFeeAt(timestamp, inFeeAsset, stateOverride) {
|
|
1063
1277
|
return this.rollup.read.getManaMinFeeAt([
|
|
1064
1278
|
timestamp,
|
|
1065
1279
|
inFeeAsset
|
|
1066
|
-
]
|
|
1280
|
+
], {
|
|
1281
|
+
stateOverride
|
|
1282
|
+
});
|
|
1067
1283
|
}
|
|
1068
1284
|
async getManaMinFeeComponentsAt(timestamp, inFeeAsset) {
|
|
1069
1285
|
const result = await this.rollup.read.getManaMinFeeComponentsAt([
|
|
@@ -1127,14 +1343,23 @@ export class RollupContract {
|
|
|
1127
1343
|
]);
|
|
1128
1344
|
}
|
|
1129
1345
|
async getAttesters(timestamp) {
|
|
1130
|
-
|
|
1346
|
+
// Pin every read to a single L1 block so the attester count and the chunked index reads
|
|
1347
|
+
// observe a consistent set. Without this, the count and each chunk default to `latest` and
|
|
1348
|
+
// can straddle a block boundary (or reorg), yielding an inconsistent or truncated set.
|
|
1349
|
+
const block = await this.client.getBlock();
|
|
1350
|
+
const blockNumber = block.number ?? undefined;
|
|
1351
|
+
const ts = timestamp ?? block.timestamp;
|
|
1352
|
+
const attesterSize = await this.getActiveAttesterCount({
|
|
1353
|
+
blockNumber
|
|
1354
|
+
});
|
|
1131
1355
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
1132
|
-
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
1133
1356
|
const indices = Array.from({
|
|
1134
1357
|
length: attesterSize
|
|
1135
1358
|
}, (_, i)=>BigInt(i));
|
|
1136
1359
|
const chunks = chunk(indices, 1000);
|
|
1137
|
-
const results = await Promise.all(chunks.map((chunk)=>gse.getAttestersFromIndicesAtTime(this.address, ts, chunk
|
|
1360
|
+
const results = await Promise.all(chunks.map((chunk)=>gse.getAttestersFromIndicesAtTime(this.address, ts, chunk, {
|
|
1361
|
+
blockNumber
|
|
1362
|
+
})));
|
|
1138
1363
|
return results.flat().map((addr)=>EthAddress.fromString(addr));
|
|
1139
1364
|
}
|
|
1140
1365
|
async getAttesterView(address) {
|
|
@@ -1216,31 +1441,48 @@ export class RollupContract {
|
|
|
1216
1441
|
})
|
|
1217
1442
|
});
|
|
1218
1443
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1444
|
+
/**
|
|
1445
|
+
* Watches for SlasherUpdated events. Events are delivered by polling `eth_getLogs`: a reorg may re-emit them and
|
|
1446
|
+
* removals are never reported, and events mined within roughly one polling interval of subscribing may be missed.
|
|
1447
|
+
* Slasher rotations are rare governance operations, so by default this polls much slower than the other watchers.
|
|
1448
|
+
*/ listenToSlasherChanged(callback, options) {
|
|
1449
|
+
return watchContractEvent(this.client, this.logger, {
|
|
1450
|
+
address: this.address,
|
|
1451
|
+
abi: RollupAbi,
|
|
1452
|
+
eventName: 'SlasherUpdated',
|
|
1453
|
+
onLog: (log)=>{
|
|
1454
|
+
const { oldSlasher, newSlasher } = log.args;
|
|
1455
|
+
if (oldSlasher && newSlasher) {
|
|
1456
|
+
return callback({
|
|
1457
|
+
oldSlasher,
|
|
1458
|
+
newSlasher
|
|
1459
|
+
});
|
|
1227
1460
|
}
|
|
1228
1461
|
}
|
|
1462
|
+
}, {
|
|
1463
|
+
pollingIntervalMs: SLASHER_UPDATED_POLLING_INTERVAL_MS,
|
|
1464
|
+
...options
|
|
1229
1465
|
});
|
|
1230
1466
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1467
|
+
/**
|
|
1468
|
+
* Watches for CheckpointInvalidated events. Events are delivered by polling `eth_getLogs`: a reorg may re-emit
|
|
1469
|
+
* them and removals are never reported, and events mined within roughly one polling interval of subscribing may
|
|
1470
|
+
* be missed.
|
|
1471
|
+
*/ listenToCheckpointInvalidated(callback, options) {
|
|
1472
|
+
return watchContractEvent(this.client, this.logger, {
|
|
1473
|
+
address: this.address,
|
|
1474
|
+
abi: RollupAbi,
|
|
1475
|
+
eventName: 'CheckpointInvalidated',
|
|
1476
|
+
onLog: (log)=>{
|
|
1477
|
+
const { checkpointNumber } = log.args;
|
|
1478
|
+
if (checkpointNumber !== undefined) {
|
|
1479
|
+
return callback({
|
|
1480
|
+
checkpointNumber: CheckpointNumber.fromBigInt(checkpointNumber),
|
|
1481
|
+
event: log
|
|
1482
|
+
});
|
|
1241
1483
|
}
|
|
1242
1484
|
}
|
|
1243
|
-
});
|
|
1485
|
+
}, options);
|
|
1244
1486
|
}
|
|
1245
1487
|
async getSlashEvents(l1BlockHash) {
|
|
1246
1488
|
const events = await this.rollup.getEvents.Slashed({}, {
|
|
@@ -1252,18 +1494,31 @@ export class RollupContract {
|
|
|
1252
1494
|
attester: EthAddress.fromString(event.args.attester)
|
|
1253
1495
|
}));
|
|
1254
1496
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1497
|
+
/**
|
|
1498
|
+
* Watches for Slashed events. Events are delivered by polling `eth_getLogs`: a reorg may re-emit them and
|
|
1499
|
+
* removals are never reported, and events mined within roughly one polling interval of subscribing may be missed.
|
|
1500
|
+
*/ listenToSlash(callback, options) {
|
|
1501
|
+
return watchContractEvent(this.client, this.logger, {
|
|
1502
|
+
address: this.address,
|
|
1503
|
+
abi: RollupAbi,
|
|
1504
|
+
eventName: 'Slashed',
|
|
1257
1505
|
strict: true,
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1506
|
+
onLog: (log)=>callback({
|
|
1507
|
+
amount: log.args.amount,
|
|
1508
|
+
attester: EthAddress.fromString(log.args.attester)
|
|
1509
|
+
})
|
|
1510
|
+
}, options);
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1514
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1515
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1516
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1517
|
+
*/ async getOwnershipTransferredEventsAtDeploy() {
|
|
1518
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1519
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, {
|
|
1520
|
+
fromBlock: l1StartBlock,
|
|
1521
|
+
toBlock: l1StartBlock
|
|
1267
1522
|
});
|
|
1268
1523
|
}
|
|
1269
1524
|
/** Fetches CheckpointProposed events within the given block range. */ async getCheckpointProposedEvents(fromBlock, toBlock) {
|
|
@@ -1294,4 +1549,43 @@ export class RollupContract {
|
|
|
1294
1549
|
}
|
|
1295
1550
|
}));
|
|
1296
1551
|
}
|
|
1552
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */ static packChainTips(pendingCheckpointNumber, provenCheckpointNumber) {
|
|
1553
|
+
return pendingCheckpointNumber << 128n | provenCheckpointNumber & (1n << 128n) - 1n;
|
|
1554
|
+
}
|
|
1555
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */ static get chainTipsStorageSlot() {
|
|
1556
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1560
|
+
* @param checkpointNumber - The checkpoint number
|
|
1561
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1562
|
+
*/ async getTempCheckpointLogStorageSlot(checkpointNumber, field) {
|
|
1563
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1564
|
+
this.getEpochDuration(),
|
|
1565
|
+
this.getProofSubmissionEpochs()
|
|
1566
|
+
]);
|
|
1567
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, {
|
|
1568
|
+
epochDuration,
|
|
1569
|
+
proofSubmissionEpochs
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants) {
|
|
1573
|
+
const fieldOffset = BigInt(field);
|
|
1574
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1575
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1576
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1577
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1578
|
+
const entryBase = BigInt(keccak256(encodeAbiParameters([
|
|
1579
|
+
{
|
|
1580
|
+
type: 'uint256'
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
type: 'uint256'
|
|
1584
|
+
}
|
|
1585
|
+
], [
|
|
1586
|
+
circularIndex,
|
|
1587
|
+
tempCheckpointLogsBase
|
|
1588
|
+
])));
|
|
1589
|
+
return entryBase + fieldOffset;
|
|
1590
|
+
}
|
|
1297
1591
|
}
|