@aztec/ethereum 0.0.1-commit.96bb3f7 → 0.0.1-commit.993d240
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 +16 -2
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +27 -7
- package/dest/config.d.ts +22 -33
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +59 -64
- 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/fee_asset_handler.d.ts +1 -1
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/fee_asset_handler.js +2 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts +105 -0
- package/dest/contracts/fee_asset_price_oracle.d.ts.map +1 -0
- package/dest/contracts/fee_asset_price_oracle.js +656 -0
- package/dest/contracts/governance.d.ts +110 -33
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +207 -16
- package/dest/contracts/governance_proposer.d.ts +33 -1
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +57 -3
- package/dest/contracts/inbox.d.ts +18 -1
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +38 -2
- package/dest/contracts/index.d.ts +5 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +4 -2
- package/dest/contracts/log.d.ts +13 -0
- package/dest/contracts/log.d.ts.map +1 -0
- package/dest/contracts/log.js +1 -0
- package/dest/contracts/multicall.d.ts +127 -12
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +201 -93
- package/dest/contracts/outbox.d.ts +21 -4
- package/dest/contracts/outbox.d.ts.map +1 -1
- package/dest/contracts/outbox.js +29 -6
- package/dest/contracts/registry.d.ts +3 -1
- package/dest/contracts/registry.d.ts.map +1 -1
- package/dest/contracts/registry.js +30 -1
- package/dest/contracts/rollup.d.ts +5288 -27
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +432 -69
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +3 -4
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +18 -13
- package/dest/deploy_aztec_l1_contracts.d.ts +9 -8
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +58 -32
- package/dest/deploy_l1_contract.js +3 -3
- package/dest/generated/l1-contracts-defaults.d.ts +30 -0
- package/dest/generated/l1-contracts-defaults.d.ts.map +1 -0
- package/dest/generated/l1-contracts-defaults.js +30 -0
- package/dest/l1_artifacts.d.ts +15699 -16241
- 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 +5 -5
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +9 -7
- package/dest/l1_tx_utils/config.d.ts +7 -1
- package/dest/l1_tx_utils/config.d.ts.map +1 -1
- package/dest/l1_tx_utils/config.js +14 -1
- package/dest/l1_tx_utils/constants.d.ts +1 -1
- package/dest/l1_tx_utils/constants.js +2 -2
- package/dest/l1_tx_utils/factory.d.ts +18 -10
- package/dest/l1_tx_utils/factory.d.ts.map +1 -1
- package/dest/l1_tx_utils/factory.js +17 -7
- package/dest/l1_tx_utils/fee-strategies/p75_competitive.js +1 -1
- package/dest/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.js +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts +15 -15
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/forwarder_l1_tx_utils.js +9 -15
- package/dest/l1_tx_utils/index-blobs.d.ts +3 -3
- package/dest/l1_tx_utils/index-blobs.d.ts.map +1 -1
- package/dest/l1_tx_utils/index-blobs.js +2 -2
- package/dest/l1_tx_utils/index.d.ts +2 -1
- package/dest/l1_tx_utils/index.d.ts.map +1 -1
- package/dest/l1_tx_utils/index.js +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +26 -7
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +101 -66
- 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 +11 -7
- package/dest/l1_tx_utils/tx_delayer.d.ts +58 -0
- package/dest/l1_tx_utils/tx_delayer.d.ts.map +1 -0
- package/dest/{test → l1_tx_utils}/tx_delayer.js +67 -37
- package/dest/publisher_manager.d.ts +21 -6
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -7
- package/dest/queries.d.ts +14 -3
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +66 -4
- package/dest/test/chain_monitor.d.ts +23 -3
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +38 -2
- package/dest/test/eth_cheat_codes.d.ts +24 -4
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +17 -4
- package/dest/test/index.d.ts +1 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +0 -2
- package/dest/test/rollup_cheat_codes.d.ts +34 -4
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +69 -8
- package/dest/test/start_anvil.d.ts +23 -3
- package/dest/test/start_anvil.d.ts.map +1 -1
- package/dest/test/start_anvil.js +143 -29
- package/dest/test/upgrade_utils.js +2 -2
- package/dest/utils.d.ts +9 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +81 -12
- package/package.json +9 -10
- package/src/client.ts +28 -2
- package/src/config.ts +75 -65
- package/src/contracts/README.md +157 -0
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/fee_asset_handler.ts +2 -0
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +279 -13
- package/src/contracts/governance_proposer.ts +58 -2
- package/src/contracts/inbox.ts +57 -2
- package/src/contracts/index.ts +4 -2
- package/src/contracts/log.ts +13 -0
- package/src/contracts/multicall.ts +243 -102
- package/src/contracts/outbox.ts +38 -8
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +500 -68
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +16 -14
- package/src/deploy_aztec_l1_contracts.ts +81 -40
- package/src/deploy_l1_contract.ts +3 -3
- package/src/generated/l1-contracts-defaults.ts +32 -0
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +120 -94
- package/src/l1_reader.ts +17 -10
- package/src/l1_tx_utils/config.ts +20 -0
- package/src/l1_tx_utils/constants.ts +2 -2
- package/src/l1_tx_utils/factory.ts +31 -31
- package/src/l1_tx_utils/fee-strategies/p75_competitive.ts +1 -1
- package/src/l1_tx_utils/fee-strategies/p75_competitive_blob_txs_only.ts +1 -1
- package/src/l1_tx_utils/forwarder_l1_tx_utils.ts +43 -54
- package/src/l1_tx_utils/index-blobs.ts +2 -2
- package/src/l1_tx_utils/index.ts +1 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +99 -48
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +11 -7
- package/src/{test → l1_tx_utils}/tx_delayer.ts +93 -56
- package/src/publisher_manager.ts +107 -10
- package/src/queries.ts +73 -5
- package/src/test/chain_monitor.ts +65 -3
- package/src/test/eth_cheat_codes.ts +16 -4
- package/src/test/index.ts +0 -2
- package/src/test/rollup_cheat_codes.ts +75 -8
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +88 -14
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -67
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -209
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +0 -26
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +0 -26
- package/dest/test/delayed_tx_utils.d.ts +0 -13
- package/dest/test/delayed_tx_utils.d.ts.map +0 -1
- package/dest/test/delayed_tx_utils.js +0 -28
- package/dest/test/tx_delayer.d.ts +0 -36
- package/dest/test/tx_delayer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -270
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/dest/contracts/rollup.js
CHANGED
|
@@ -376,24 +376,19 @@ 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 { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
380
382
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
381
383
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
382
384
|
import chunk from 'lodash.chunk';
|
|
383
|
-
import { encodeFunctionData, getContract, hexToBigInt, keccak256 } from 'viem';
|
|
385
|
+
import { encodeAbiParameters, encodeFunctionData, getContract, hexToBigInt, keccak256 } from 'viem';
|
|
384
386
|
import { getPublicClient } from '../client.js';
|
|
385
387
|
import { formatViemError } from '../utils.js';
|
|
386
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
387
388
|
import { GSEContract } from './gse.js';
|
|
388
389
|
import { SlasherContract } from './slasher_contract.js';
|
|
389
|
-
import {
|
|
390
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
390
391
|
import { checkBlockTag } from './utils.js';
|
|
391
|
-
export var SlashingProposerType = /*#__PURE__*/ function(SlashingProposerType) {
|
|
392
|
-
SlashingProposerType[SlashingProposerType["None"] = 0] = "None";
|
|
393
|
-
SlashingProposerType[SlashingProposerType["Tally"] = 1] = "Tally";
|
|
394
|
-
SlashingProposerType[SlashingProposerType["Empire"] = 2] = "Empire";
|
|
395
|
-
return SlashingProposerType;
|
|
396
|
-
}({});
|
|
397
392
|
/**
|
|
398
393
|
* Status of a validator/attester in the staking system.
|
|
399
394
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -404,6 +399,16 @@ export var SlashingProposerType = /*#__PURE__*/ function(SlashingProposerType) {
|
|
|
404
399
|
AttesterStatus[AttesterStatus["EXITING"] = 3] = "EXITING";
|
|
405
400
|
return AttesterStatus;
|
|
406
401
|
}({});
|
|
402
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */ export var TempCheckpointLogField = /*#__PURE__*/ function(TempCheckpointLogField) {
|
|
403
|
+
TempCheckpointLogField[TempCheckpointLogField["HeaderHash"] = 0] = "HeaderHash";
|
|
404
|
+
TempCheckpointLogField[TempCheckpointLogField["BlobCommitmentsHash"] = 1] = "BlobCommitmentsHash";
|
|
405
|
+
TempCheckpointLogField[TempCheckpointLogField["OutHash"] = 2] = "OutHash";
|
|
406
|
+
TempCheckpointLogField[TempCheckpointLogField["AttestationsHash"] = 3] = "AttestationsHash";
|
|
407
|
+
TempCheckpointLogField[TempCheckpointLogField["PayloadDigest"] = 4] = "PayloadDigest";
|
|
408
|
+
TempCheckpointLogField[TempCheckpointLogField["SlotNumber"] = 5] = "SlotNumber";
|
|
409
|
+
TempCheckpointLogField[TempCheckpointLogField["FeeHeader"] = 6] = "FeeHeader";
|
|
410
|
+
return TempCheckpointLogField;
|
|
411
|
+
}({});
|
|
407
412
|
export class RollupContract {
|
|
408
413
|
client;
|
|
409
414
|
static{
|
|
@@ -498,6 +503,16 @@ export class RollupContract {
|
|
|
498
503
|
2,
|
|
499
504
|
"getGenesisArchiveTreeRoot"
|
|
500
505
|
],
|
|
506
|
+
[
|
|
507
|
+
memoize,
|
|
508
|
+
2,
|
|
509
|
+
"getVkTreeRoot"
|
|
510
|
+
],
|
|
511
|
+
[
|
|
512
|
+
memoize,
|
|
513
|
+
2,
|
|
514
|
+
"getProtocolContractsHash"
|
|
515
|
+
],
|
|
501
516
|
[
|
|
502
517
|
memoize,
|
|
503
518
|
2,
|
|
@@ -506,7 +521,9 @@ export class RollupContract {
|
|
|
506
521
|
], []));
|
|
507
522
|
}
|
|
508
523
|
rollup;
|
|
524
|
+
logger;
|
|
509
525
|
static cachedStfStorageSlot;
|
|
526
|
+
cachedEscapeHatch;
|
|
510
527
|
static get checkBlobStorageSlot() {
|
|
511
528
|
const asString = RollupStorage.find((storage)=>storage.label === 'checkBlob')?.slot;
|
|
512
529
|
if (asString === undefined) {
|
|
@@ -523,12 +540,12 @@ export class RollupContract {
|
|
|
523
540
|
}
|
|
524
541
|
static getFromConfig(config) {
|
|
525
542
|
const client = getPublicClient(config);
|
|
526
|
-
const address = config.
|
|
543
|
+
const address = config.rollupAddress.toString();
|
|
527
544
|
return new RollupContract(client, address);
|
|
528
545
|
}
|
|
529
546
|
constructor(client, address){
|
|
530
547
|
this.client = client;
|
|
531
|
-
_initProto(this);
|
|
548
|
+
this.logger = (_initProto(this), createLogger('ethereum:rollup'));
|
|
532
549
|
if (address instanceof EthAddress) {
|
|
533
550
|
address = address.toString();
|
|
534
551
|
}
|
|
@@ -553,34 +570,10 @@ export class RollupContract {
|
|
|
553
570
|
return undefined;
|
|
554
571
|
}
|
|
555
572
|
const proposerAddress = await slasher.getProposer();
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
type: 'function',
|
|
559
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
560
|
-
inputs: [],
|
|
561
|
-
outputs: [
|
|
562
|
-
{
|
|
563
|
-
name: '',
|
|
564
|
-
type: 'uint8',
|
|
565
|
-
internalType: 'enum SlasherFlavor'
|
|
566
|
-
}
|
|
567
|
-
],
|
|
568
|
-
stateMutability: 'view'
|
|
569
|
-
}
|
|
570
|
-
];
|
|
571
|
-
const proposer = getContract({
|
|
572
|
-
address: proposerAddress.toString(),
|
|
573
|
-
abi: proposerAbi,
|
|
574
|
-
client: this.client
|
|
575
|
-
});
|
|
576
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
577
|
-
if (proposerType === 1..valueOf()) {
|
|
578
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
579
|
-
} else if (proposerType === 2..valueOf()) {
|
|
580
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
581
|
-
} else {
|
|
582
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
573
|
+
if (proposerAddress.isZero()) {
|
|
574
|
+
return undefined;
|
|
583
575
|
}
|
|
576
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
584
577
|
}
|
|
585
578
|
getL1StartBlock() {
|
|
586
579
|
return this.rollup.read.L1_BLOCK_AT_GENESIS();
|
|
@@ -638,30 +631,98 @@ export class RollupContract {
|
|
|
638
631
|
0n
|
|
639
632
|
]));
|
|
640
633
|
}
|
|
634
|
+
async getVkTreeRoot() {
|
|
635
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
636
|
+
const value = await this.client.getStorageAt({
|
|
637
|
+
address: this.address,
|
|
638
|
+
slot: `0x${slot.toString(16)}`
|
|
639
|
+
});
|
|
640
|
+
return Fr.fromString(value ?? '0x0');
|
|
641
|
+
}
|
|
642
|
+
async getProtocolContractsHash() {
|
|
643
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
644
|
+
const value = await this.client.getStorageAt({
|
|
645
|
+
address: this.address,
|
|
646
|
+
slot: `0x${slot.toString(16)}`
|
|
647
|
+
});
|
|
648
|
+
return Fr.fromString(value ?? '0x0');
|
|
649
|
+
}
|
|
641
650
|
/**
|
|
642
651
|
* Returns rollup constants used for epoch queries.
|
|
643
652
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
644
653
|
* so we cant reference it until we move this contract to that package.
|
|
645
654
|
*/ async getRollupConstants() {
|
|
646
|
-
const [l1StartBlock, l1GenesisTime, slotDuration, epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
655
|
+
const [l1StartBlock, l1GenesisTime, slotDuration, epochDuration, proofSubmissionEpochs, targetCommitteeSize, rollupManaLimit] = await Promise.all([
|
|
647
656
|
this.getL1StartBlock(),
|
|
648
657
|
this.getL1GenesisTime(),
|
|
649
658
|
this.getSlotDuration(),
|
|
650
659
|
this.getEpochDuration(),
|
|
651
|
-
this.getProofSubmissionEpochs()
|
|
660
|
+
this.getProofSubmissionEpochs(),
|
|
661
|
+
this.getTargetCommitteeSize(),
|
|
662
|
+
this.getManaLimit()
|
|
652
663
|
]);
|
|
653
664
|
return {
|
|
654
665
|
l1StartBlock,
|
|
655
666
|
l1GenesisTime,
|
|
656
667
|
slotDuration,
|
|
657
668
|
epochDuration: Number(epochDuration),
|
|
658
|
-
proofSubmissionEpochs: Number(proofSubmissionEpochs)
|
|
669
|
+
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
670
|
+
targetCommitteeSize,
|
|
671
|
+
rollupManaLimit: Number(rollupManaLimit)
|
|
659
672
|
};
|
|
660
673
|
}
|
|
661
674
|
async getSlasherAddress() {
|
|
662
675
|
return EthAddress.fromString(await this.rollup.read.getSlasher());
|
|
663
676
|
}
|
|
664
677
|
/**
|
|
678
|
+
* Returns the configured escape hatch contract address, or zero if disabled.
|
|
679
|
+
*/ async getEscapeHatchAddress() {
|
|
680
|
+
return EthAddress.fromString(await this.rollup.read.getEscapeHatch());
|
|
681
|
+
}
|
|
682
|
+
async getEscapeHatchContract() {
|
|
683
|
+
const escapeHatchAddress = await this.getEscapeHatchAddress();
|
|
684
|
+
if (escapeHatchAddress.isZero()) {
|
|
685
|
+
return undefined;
|
|
686
|
+
}
|
|
687
|
+
// Cache the viem contract wrapper since it will be used frequently.
|
|
688
|
+
if (!this.cachedEscapeHatch || !this.cachedEscapeHatch.address.equals(escapeHatchAddress)) {
|
|
689
|
+
this.cachedEscapeHatch = {
|
|
690
|
+
address: escapeHatchAddress,
|
|
691
|
+
contract: getContract({
|
|
692
|
+
address: escapeHatchAddress.toString(),
|
|
693
|
+
abi: EscapeHatchAbi,
|
|
694
|
+
client: this.client
|
|
695
|
+
})
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
return this.cachedEscapeHatch.contract;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Returns whether the escape hatch is open for the given epoch.
|
|
702
|
+
* If escape hatch is not configured, returns false.
|
|
703
|
+
*
|
|
704
|
+
* This function is intentionally defensive: any failure to query the escape hatch
|
|
705
|
+
* (RPC issues, transient errors, etc.) is treated as "closed" to avoid callers
|
|
706
|
+
* needing to sprinkle try/catch everywhere.
|
|
707
|
+
*/ async isEscapeHatchOpen(epoch) {
|
|
708
|
+
try {
|
|
709
|
+
const escapeHatch = await this.getEscapeHatchContract();
|
|
710
|
+
if (!escapeHatch) {
|
|
711
|
+
return false;
|
|
712
|
+
}
|
|
713
|
+
const [isOpen] = await escapeHatch.read.isHatchOpen([
|
|
714
|
+
BigInt(epoch)
|
|
715
|
+
]);
|
|
716
|
+
return isOpen;
|
|
717
|
+
} catch (err) {
|
|
718
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
719
|
+
epoch: Number(epoch),
|
|
720
|
+
error: err
|
|
721
|
+
});
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
665
726
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
666
727
|
*/ async getSlasherContract() {
|
|
667
728
|
const slasherAddress = await this.getSlasherAddress();
|
|
@@ -686,26 +747,42 @@ export class RollupContract {
|
|
|
686
747
|
getCheckpointReward() {
|
|
687
748
|
return this.rollup.read.getCheckpointReward();
|
|
688
749
|
}
|
|
689
|
-
async getCheckpointNumber() {
|
|
690
|
-
|
|
750
|
+
async getCheckpointNumber(options) {
|
|
751
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
752
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
691
753
|
}
|
|
692
|
-
async getProvenCheckpointNumber() {
|
|
693
|
-
|
|
754
|
+
async getProvenCheckpointNumber(options) {
|
|
755
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
756
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
694
757
|
}
|
|
695
|
-
async getSlotNumber() {
|
|
696
|
-
|
|
758
|
+
async getSlotNumber(options) {
|
|
759
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
760
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
697
761
|
}
|
|
698
|
-
async getL1FeesAt(timestamp) {
|
|
762
|
+
async getL1FeesAt(timestamp, options) {
|
|
763
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
699
764
|
const result = await this.rollup.read.getL1FeesAt([
|
|
700
765
|
timestamp
|
|
701
|
-
]);
|
|
766
|
+
], options);
|
|
702
767
|
return {
|
|
703
768
|
baseFee: result.baseFee,
|
|
704
769
|
blobFee: result.blobFee
|
|
705
770
|
};
|
|
706
771
|
}
|
|
707
|
-
|
|
708
|
-
|
|
772
|
+
async getFeeHeader(checkpointNumber) {
|
|
773
|
+
const result = await this.rollup.read.getFeeHeader([
|
|
774
|
+
checkpointNumber
|
|
775
|
+
]);
|
|
776
|
+
return {
|
|
777
|
+
excessMana: result.excessMana,
|
|
778
|
+
manaUsed: result.manaUsed,
|
|
779
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
780
|
+
congestionCost: result.congestionCost,
|
|
781
|
+
proverCost: result.proverCost
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
getEthPerFeeAsset() {
|
|
785
|
+
return this.rollup.read.getEthPerFeeAsset();
|
|
709
786
|
}
|
|
710
787
|
async getCommitteeAt(timestamp) {
|
|
711
788
|
const { result } = await this.client.simulateContract({
|
|
@@ -772,10 +849,11 @@ export class RollupContract {
|
|
|
772
849
|
});
|
|
773
850
|
return EthAddress.fromString(result);
|
|
774
851
|
}
|
|
775
|
-
async getCheckpoint(checkpointNumber) {
|
|
852
|
+
async getCheckpoint(checkpointNumber, options) {
|
|
853
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
776
854
|
const result = await this.rollup.read.getCheckpoint([
|
|
777
855
|
BigInt(checkpointNumber)
|
|
778
|
-
]);
|
|
856
|
+
], options);
|
|
779
857
|
return {
|
|
780
858
|
archive: Fr.fromString(result.archive),
|
|
781
859
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -786,7 +864,7 @@ export class RollupContract {
|
|
|
786
864
|
feeHeader: {
|
|
787
865
|
excessMana: result.feeHeader.excessMana,
|
|
788
866
|
manaUsed: result.feeHeader.manaUsed,
|
|
789
|
-
|
|
867
|
+
ethPerFeeAsset: result.feeHeader.ethPerFeeAsset,
|
|
790
868
|
congestionCost: result.feeHeader.congestionCost,
|
|
791
869
|
proverCost: result.feeHeader.proverCost
|
|
792
870
|
}
|
|
@@ -805,6 +883,28 @@ export class RollupContract {
|
|
|
805
883
|
0.5
|
|
806
884
|
]));
|
|
807
885
|
}
|
|
886
|
+
/**
|
|
887
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
888
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
889
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
890
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
891
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
892
|
+
*/ getEffectivePendingCheckpoint(atTimestamp, options) {
|
|
893
|
+
return retry(async ()=>{
|
|
894
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
895
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
896
|
+
if (canPrune) {
|
|
897
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
898
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
899
|
+
}
|
|
900
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
901
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
902
|
+
}, 'getting effective pending checkpoint', makeBackoff([
|
|
903
|
+
0.5,
|
|
904
|
+
0.5,
|
|
905
|
+
0.5
|
|
906
|
+
]));
|
|
907
|
+
}
|
|
808
908
|
async getTips() {
|
|
809
909
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
810
910
|
return {
|
|
@@ -889,9 +989,8 @@ export class RollupContract {
|
|
|
889
989
|
* @return [slot, checkpointNumber, timeOfNextL1Slot] - If you can propose, the L2 slot number, checkpoint number and
|
|
890
990
|
* timestamp of the next L1 block
|
|
891
991
|
* @throws otherwise
|
|
892
|
-
*/ async
|
|
893
|
-
const
|
|
894
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
992
|
+
*/ async canProposeAt(archive, account, timestamp, stateOverride = []) {
|
|
993
|
+
const timeOfNextL1Slot = timestamp;
|
|
895
994
|
const who = typeof account === 'string' ? account : account.address;
|
|
896
995
|
try {
|
|
897
996
|
const { result: [slot, checkpointNumber] } = await this.client.simulateContract({
|
|
@@ -904,7 +1003,7 @@ export class RollupContract {
|
|
|
904
1003
|
who
|
|
905
1004
|
],
|
|
906
1005
|
account,
|
|
907
|
-
stateOverride
|
|
1006
|
+
stateOverride
|
|
908
1007
|
});
|
|
909
1008
|
return {
|
|
910
1009
|
slot: SlotNumber.fromBigInt(slot),
|
|
@@ -916,11 +1015,15 @@ export class RollupContract {
|
|
|
916
1015
|
}
|
|
917
1016
|
}
|
|
918
1017
|
/**
|
|
919
|
-
* Returns a state override that sets the pending
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
|
|
923
|
-
|
|
1018
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
1019
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
1020
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
1021
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
1022
|
+
*
|
|
1023
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
1024
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
1025
|
+
*/ async makeChainTipsOverride(override) {
|
|
1026
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
924
1027
|
return [];
|
|
925
1028
|
}
|
|
926
1029
|
const slot = RollupContract.stfStorageSlot;
|
|
@@ -928,8 +1031,15 @@ export class RollupContract {
|
|
|
928
1031
|
address: this.address,
|
|
929
1032
|
slot
|
|
930
1033
|
});
|
|
931
|
-
const
|
|
932
|
-
const
|
|
1034
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
1035
|
+
const currentPending = currentRaw >> 128n;
|
|
1036
|
+
const currentProven = currentRaw & (1n << 128n) - 1n;
|
|
1037
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
1038
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
1039
|
+
if (newProven > newPending) {
|
|
1040
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
1041
|
+
}
|
|
1042
|
+
const newValue = newPending << 128n | newProven;
|
|
933
1043
|
return [
|
|
934
1044
|
{
|
|
935
1045
|
address: this.address,
|
|
@@ -942,9 +1052,165 @@ export class RollupContract {
|
|
|
942
1052
|
}
|
|
943
1053
|
];
|
|
944
1054
|
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
1057
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
1058
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
1059
|
+
*
|
|
1060
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
1061
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
1062
|
+
*/ async makeTempCheckpointLogOverride(checkpointNumber, fields) {
|
|
1063
|
+
const constants = await this.getRollupConstants();
|
|
1064
|
+
const slotAt = (field)=>`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}`;
|
|
1065
|
+
const word = (v)=>`0x${v.toString(16).padStart(64, '0')}`;
|
|
1066
|
+
const stateDiff = [];
|
|
1067
|
+
if (fields.headerHash) {
|
|
1068
|
+
stateDiff.push({
|
|
1069
|
+
slot: slotAt(0),
|
|
1070
|
+
value: fields.headerHash.toString()
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
if (fields.outHash) {
|
|
1074
|
+
stateDiff.push({
|
|
1075
|
+
slot: slotAt(2),
|
|
1076
|
+
value: fields.outHash.toString()
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
if (fields.payloadDigest) {
|
|
1080
|
+
stateDiff.push({
|
|
1081
|
+
slot: slotAt(4),
|
|
1082
|
+
value: fields.payloadDigest.toString()
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
if (fields.slotNumber !== undefined) {
|
|
1086
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
1087
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
1088
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
1089
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
1090
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
1091
|
+
}
|
|
1092
|
+
stateDiff.push({
|
|
1093
|
+
slot: slotAt(5),
|
|
1094
|
+
value: word(slotNumber)
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
if (fields.feeHeader) {
|
|
1098
|
+
stateDiff.push({
|
|
1099
|
+
slot: slotAt(6),
|
|
1100
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader))
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
if (stateDiff.length === 0) {
|
|
1104
|
+
return [];
|
|
1105
|
+
}
|
|
1106
|
+
return [
|
|
1107
|
+
{
|
|
1108
|
+
address: this.address,
|
|
1109
|
+
stateDiff
|
|
1110
|
+
}
|
|
1111
|
+
];
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
1115
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
1116
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
1117
|
+
*/ makeArchiveOverride(checkpointNumber, archive) {
|
|
1118
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
1119
|
+
const archiveSlot = hexToBigInt(keccak256(encodeAbiParameters([
|
|
1120
|
+
{
|
|
1121
|
+
type: 'uint256'
|
|
1122
|
+
},
|
|
1123
|
+
{
|
|
1124
|
+
type: 'uint256'
|
|
1125
|
+
}
|
|
1126
|
+
], [
|
|
1127
|
+
BigInt(checkpointNumber),
|
|
1128
|
+
archivesMappingBase
|
|
1129
|
+
])));
|
|
1130
|
+
return [
|
|
1131
|
+
{
|
|
1132
|
+
address: this.address,
|
|
1133
|
+
stateDiff: [
|
|
1134
|
+
{
|
|
1135
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
1136
|
+
value: archive.toString()
|
|
1137
|
+
}
|
|
1138
|
+
]
|
|
1139
|
+
}
|
|
1140
|
+
];
|
|
1141
|
+
}
|
|
1142
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */ static mergeStateOverrides(...overrides) {
|
|
1143
|
+
const byAddress = new Map();
|
|
1144
|
+
for (const override of overrides){
|
|
1145
|
+
for (const entry of override){
|
|
1146
|
+
const key = entry.address.toLowerCase();
|
|
1147
|
+
const existing = byAddress.get(key);
|
|
1148
|
+
if (existing) {
|
|
1149
|
+
existing.stateDiff.push(...entry.stateDiff ?? []);
|
|
1150
|
+
if (entry.balance !== undefined) {
|
|
1151
|
+
existing.balance = entry.balance;
|
|
1152
|
+
}
|
|
1153
|
+
} else {
|
|
1154
|
+
byAddress.set(key, {
|
|
1155
|
+
address: entry.address,
|
|
1156
|
+
balance: entry.balance,
|
|
1157
|
+
stateDiff: [
|
|
1158
|
+
...entry.stateDiff ?? []
|
|
1159
|
+
]
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return [
|
|
1165
|
+
...byAddress.values()
|
|
1166
|
+
];
|
|
1167
|
+
}
|
|
1168
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */ static compressFeeHeader(feeHeader) {
|
|
1169
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1170
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1171
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1172
|
+
let value = BigInt(feeHeader.manaUsed) & (1n << 32n) - 1n; // bits [0:31]
|
|
1173
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1174
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1175
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1176
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1177
|
+
value |= 1n << 255n; // preheat flag
|
|
1178
|
+
return value;
|
|
1179
|
+
}
|
|
1180
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1181
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */ static computeChildFeeHeader(parentFeeHeader, childManaUsed, feeAssetPriceModifier, manaTarget) {
|
|
1182
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1183
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1184
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1185
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1186
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1187
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1188
|
+
const parentPrice = parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1189
|
+
let newPrice;
|
|
1190
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1191
|
+
newPrice = parentPrice * (10_000n + feeAssetPriceModifier) / 10_000n;
|
|
1192
|
+
} else {
|
|
1193
|
+
const absMod = -feeAssetPriceModifier;
|
|
1194
|
+
newPrice = parentPrice * (10_000n - absMod) / 10_000n;
|
|
1195
|
+
}
|
|
1196
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1197
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1198
|
+
}
|
|
1199
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1200
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1201
|
+
}
|
|
1202
|
+
return {
|
|
1203
|
+
excessMana,
|
|
1204
|
+
manaUsed: childManaUsed,
|
|
1205
|
+
ethPerFeeAsset: newPrice,
|
|
1206
|
+
congestionCost: 0n,
|
|
1207
|
+
proverCost: 0n
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
945
1210
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */ buildInvalidateBadAttestationRequest(checkpointNumber, attestationsAndSigners, committee, invalidIndex) {
|
|
946
1211
|
return {
|
|
947
1212
|
to: this.address,
|
|
1213
|
+
abi: RollupAbi,
|
|
948
1214
|
data: encodeFunctionData({
|
|
949
1215
|
abi: RollupAbi,
|
|
950
1216
|
functionName: 'invalidateBadAttestation',
|
|
@@ -960,6 +1226,7 @@ export class RollupContract {
|
|
|
960
1226
|
/** Creates a request to Rollup#invalidateInsufficientAttestations to be simulated or sent */ buildInvalidateInsufficientAttestationsRequest(checkpointNumber, attestationsAndSigners, committee) {
|
|
961
1227
|
return {
|
|
962
1228
|
to: this.address,
|
|
1229
|
+
abi: RollupAbi,
|
|
963
1230
|
data: encodeFunctionData({
|
|
964
1231
|
abi: RollupAbi,
|
|
965
1232
|
functionName: 'invalidateInsufficientAttestations',
|
|
@@ -981,11 +1248,25 @@ export class RollupContract {
|
|
|
981
1248
|
prover
|
|
982
1249
|
]);
|
|
983
1250
|
}
|
|
984
|
-
getManaMinFeeAt(timestamp, inFeeAsset) {
|
|
1251
|
+
getManaMinFeeAt(timestamp, inFeeAsset, stateOverride) {
|
|
985
1252
|
return this.rollup.read.getManaMinFeeAt([
|
|
986
1253
|
timestamp,
|
|
987
1254
|
inFeeAsset
|
|
1255
|
+
], {
|
|
1256
|
+
stateOverride
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
async getManaMinFeeComponentsAt(timestamp, inFeeAsset) {
|
|
1260
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([
|
|
1261
|
+
timestamp,
|
|
1262
|
+
inFeeAsset
|
|
988
1263
|
]);
|
|
1264
|
+
return {
|
|
1265
|
+
sequencerCost: result.sequencerCost,
|
|
1266
|
+
proverCost: result.proverCost,
|
|
1267
|
+
congestionCost: result.congestionCost,
|
|
1268
|
+
congestionMultiplier: result.congestionMultiplier
|
|
1269
|
+
};
|
|
989
1270
|
}
|
|
990
1271
|
async getSlotAt(timestamp) {
|
|
991
1272
|
return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([
|
|
@@ -1036,10 +1317,10 @@ export class RollupContract {
|
|
|
1036
1317
|
prover
|
|
1037
1318
|
]);
|
|
1038
1319
|
}
|
|
1039
|
-
async getAttesters() {
|
|
1320
|
+
async getAttesters(timestamp) {
|
|
1040
1321
|
const attesterSize = await this.getActiveAttesterCount();
|
|
1041
1322
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
1042
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
1323
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
1043
1324
|
const indices = Array.from({
|
|
1044
1325
|
length: attesterSize
|
|
1045
1326
|
}, (_, i)=>BigInt(i));
|
|
@@ -1105,6 +1386,7 @@ export class RollupContract {
|
|
|
1105
1386
|
setupEpoch(l1TxUtils) {
|
|
1106
1387
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
1107
1388
|
to: this.address,
|
|
1389
|
+
abi: RollupAbi,
|
|
1108
1390
|
data: encodeFunctionData({
|
|
1109
1391
|
abi: RollupAbi,
|
|
1110
1392
|
functionName: 'setupEpoch',
|
|
@@ -1115,6 +1397,7 @@ export class RollupContract {
|
|
|
1115
1397
|
vote(l1TxUtils, proposalId) {
|
|
1116
1398
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
1117
1399
|
to: this.address,
|
|
1400
|
+
abi: RollupAbi,
|
|
1118
1401
|
data: encodeFunctionData({
|
|
1119
1402
|
abi: RollupAbi,
|
|
1120
1403
|
functionName: 'vote',
|
|
@@ -1143,7 +1426,8 @@ export class RollupContract {
|
|
|
1143
1426
|
const args = log.args;
|
|
1144
1427
|
if (args.checkpointNumber !== undefined) {
|
|
1145
1428
|
callback({
|
|
1146
|
-
checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber)
|
|
1429
|
+
checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber),
|
|
1430
|
+
event: log
|
|
1147
1431
|
});
|
|
1148
1432
|
}
|
|
1149
1433
|
}
|
|
@@ -1174,4 +1458,83 @@ export class RollupContract {
|
|
|
1174
1458
|
}
|
|
1175
1459
|
});
|
|
1176
1460
|
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1463
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1464
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1465
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1466
|
+
*/ async getOwnershipTransferredEventsAtDeploy() {
|
|
1467
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1468
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, {
|
|
1469
|
+
fromBlock: l1StartBlock,
|
|
1470
|
+
toBlock: l1StartBlock
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
/** Fetches CheckpointProposed events within the given block range. */ async getCheckpointProposedEvents(fromBlock, toBlock) {
|
|
1474
|
+
const logs = await this.rollup.getEvents.CheckpointProposed({}, {
|
|
1475
|
+
fromBlock,
|
|
1476
|
+
toBlock
|
|
1477
|
+
});
|
|
1478
|
+
return logs.filter((log)=>log.blockNumber >= fromBlock && log.blockNumber <= toBlock).map((log)=>({
|
|
1479
|
+
l1BlockNumber: log.blockNumber,
|
|
1480
|
+
l1BlockHash: Buffer32.fromString(log.blockHash),
|
|
1481
|
+
l1TransactionHash: log.transactionHash,
|
|
1482
|
+
args: {
|
|
1483
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber),
|
|
1484
|
+
archive: Fr.fromString(log.args.archive),
|
|
1485
|
+
versionedBlobHashes: log.args.versionedBlobHashes.map((h)=>Buffer.from(h.slice(2), 'hex')),
|
|
1486
|
+
attestationsHash: (()=>{
|
|
1487
|
+
if (!log.args.attestationsHash) {
|
|
1488
|
+
throw new Error(`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`);
|
|
1489
|
+
}
|
|
1490
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1491
|
+
})(),
|
|
1492
|
+
payloadDigest: (()=>{
|
|
1493
|
+
if (!log.args.payloadDigest) {
|
|
1494
|
+
throw new Error(`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`);
|
|
1495
|
+
}
|
|
1496
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1497
|
+
})()
|
|
1498
|
+
}
|
|
1499
|
+
}));
|
|
1500
|
+
}
|
|
1501
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */ static packChainTips(pendingCheckpointNumber, provenCheckpointNumber) {
|
|
1502
|
+
return pendingCheckpointNumber << 128n | provenCheckpointNumber & (1n << 128n) - 1n;
|
|
1503
|
+
}
|
|
1504
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */ static get chainTipsStorageSlot() {
|
|
1505
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1509
|
+
* @param checkpointNumber - The checkpoint number
|
|
1510
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1511
|
+
*/ async getTempCheckpointLogStorageSlot(checkpointNumber, field) {
|
|
1512
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1513
|
+
this.getEpochDuration(),
|
|
1514
|
+
this.getProofSubmissionEpochs()
|
|
1515
|
+
]);
|
|
1516
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, {
|
|
1517
|
+
epochDuration,
|
|
1518
|
+
proofSubmissionEpochs
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants) {
|
|
1522
|
+
const fieldOffset = BigInt(field);
|
|
1523
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1524
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1525
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1526
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1527
|
+
const entryBase = BigInt(keccak256(encodeAbiParameters([
|
|
1528
|
+
{
|
|
1529
|
+
type: 'uint256'
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
type: 'uint256'
|
|
1533
|
+
}
|
|
1534
|
+
], [
|
|
1535
|
+
circularIndex,
|
|
1536
|
+
tempCheckpointLogsBase
|
|
1537
|
+
])));
|
|
1538
|
+
return entryBase + fieldOffset;
|
|
1539
|
+
}
|
|
1177
1540
|
}
|