@aztec/ethereum 0.0.1-commit.86469d5 → 0.0.1-commit.8655d4a
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 +8 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +15 -11
- 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_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 +108 -33
- package/dest/contracts/governance.d.ts.map +1 -1
- package/dest/contracts/governance.js +196 -15
- 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 +53 -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 +4 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +3 -2
- package/dest/contracts/multicall.d.ts +127 -12
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +201 -94
- 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 +5259 -29
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +364 -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} +13 -15
- package/dest/deploy_aztec_l1_contracts.d.ts +4 -8
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +36 -26
- package/dest/deploy_l1_contract.js +3 -3
- 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 +14259 -15724
- 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/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 +95 -60
- 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 +8 -4
- 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 -7
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +81 -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/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 +12 -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 +31 -3
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +59 -7
- 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 +8 -1
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +35 -12
- package/package.json +6 -8
- package/src/client.ts +28 -2
- package/src/config.ts +24 -15
- package/src/contracts/chain_state_override.ts +200 -0
- package/src/contracts/fee_asset_price_oracle.ts +285 -0
- package/src/contracts/governance.ts +269 -12
- package/src/contracts/governance_proposer.ts +54 -1
- package/src/contracts/inbox.ts +13 -5
- package/src/contracts/index.ts +3 -2
- package/src/contracts/multicall.ts +243 -105
- package/src/contracts/outbox.ts +38 -8
- package/src/contracts/registry.ts +31 -1
- package/src/contracts/rollup.ts +407 -71
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +14 -16
- package/src/deploy_aztec_l1_contracts.ts +58 -34
- package/src/deploy_l1_contract.ts +3 -3
- 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 +17 -10
- package/src/l1_tx_utils/config.ts +20 -0
- 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 +93 -42
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +8 -4
- package/src/{test → l1_tx_utils}/tx_delayer.ts +93 -56
- package/src/publisher_manager.ts +105 -10
- package/src/queries.ts +70 -4
- 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 +64 -6
- package/src/test/start_anvil.ts +177 -29
- package/src/test/upgrade_utils.ts +2 -2
- package/src/utils.ts +35 -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 -207
- 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 -259
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +0 -77
- package/src/test/delayed_tx_utils.ts +0 -52
package/src/contracts/rollup.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
9
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -14,8 +15,10 @@ import {
|
|
|
14
15
|
type Account,
|
|
15
16
|
type GetContractReturnType,
|
|
16
17
|
type Hex,
|
|
18
|
+
type Log,
|
|
17
19
|
type StateOverride,
|
|
18
20
|
type WatchContractEventReturnType,
|
|
21
|
+
encodeAbiParameters,
|
|
19
22
|
encodeFunctionData,
|
|
20
23
|
getContract,
|
|
21
24
|
hexToBigInt,
|
|
@@ -29,11 +32,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
29
32
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
30
33
|
import type { ViemClient } from '../types.js';
|
|
31
34
|
import { formatViemError } from '../utils.js';
|
|
32
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
33
35
|
import { GSEContract } from './gse.js';
|
|
34
36
|
import type { L1EventLog } from './log.js';
|
|
35
37
|
import { SlasherContract } from './slasher_contract.js';
|
|
36
|
-
import {
|
|
38
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
37
39
|
import { checkBlockTag } from './utils.js';
|
|
38
40
|
|
|
39
41
|
export type ViemCommitteeAttestation = {
|
|
@@ -55,7 +57,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
55
57
|
| 'feeJuiceAddress'
|
|
56
58
|
| 'stakingAssetAddress'
|
|
57
59
|
| 'rewardDistributorAddress'
|
|
58
|
-
| 'slashFactoryAddress'
|
|
59
60
|
| 'gseAddress'
|
|
60
61
|
>;
|
|
61
62
|
|
|
@@ -85,12 +86,6 @@ export type ViemGasFees = {
|
|
|
85
86
|
feePerL2Gas: bigint;
|
|
86
87
|
};
|
|
87
88
|
|
|
88
|
-
export enum SlashingProposerType {
|
|
89
|
-
None = 0,
|
|
90
|
-
Tally = 1,
|
|
91
|
-
Empire = 2,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
/**
|
|
95
90
|
* Status of a validator/attester in the staking system.
|
|
96
91
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -134,6 +129,39 @@ export type L1FeeData = {
|
|
|
134
129
|
blobFee: bigint;
|
|
135
130
|
};
|
|
136
131
|
|
|
132
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
133
|
+
export enum TempCheckpointLogField {
|
|
134
|
+
HeaderHash = 0,
|
|
135
|
+
BlobCommitmentsHash = 1,
|
|
136
|
+
OutHash = 2,
|
|
137
|
+
AttestationsHash = 3,
|
|
138
|
+
PayloadDigest = 4,
|
|
139
|
+
SlotNumber = 5,
|
|
140
|
+
FeeHeader = 6,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Field-level override input for `tempCheckpointLogs[checkpointNumber]`. Covers the fields the
|
|
145
|
+
* `propose()` path actually reads back. `payloadDigest` is `Buffer32` because it carries an
|
|
146
|
+
* arbitrary `bytes32` value rather than a BN254 scalar. `slotNumber` carries the uint32 portion
|
|
147
|
+
* of the on-chain `CompressedSlot`.
|
|
148
|
+
*/
|
|
149
|
+
export type TempCheckpointLogOverrideFields = {
|
|
150
|
+
headerHash?: Fr;
|
|
151
|
+
outHash?: Fr;
|
|
152
|
+
payloadDigest?: Buffer32;
|
|
153
|
+
slotNumber?: SlotNumber;
|
|
154
|
+
feeHeader?: FeeHeader;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
158
|
+
export type ManaMinFeeComponents = {
|
|
159
|
+
sequencerCost: bigint;
|
|
160
|
+
proverCost: bigint;
|
|
161
|
+
congestionCost: bigint;
|
|
162
|
+
congestionMultiplier: bigint;
|
|
163
|
+
};
|
|
164
|
+
|
|
137
165
|
/**
|
|
138
166
|
* Reward configuration for the rollup
|
|
139
167
|
*/
|
|
@@ -193,10 +221,10 @@ export type CheckpointProposedArgs = {
|
|
|
193
221
|
checkpointNumber: CheckpointNumber;
|
|
194
222
|
archive: Fr;
|
|
195
223
|
versionedBlobHashes: Buffer[];
|
|
196
|
-
/** Hash of attestations
|
|
197
|
-
attestationsHash
|
|
198
|
-
/** Digest of the payload
|
|
199
|
-
payloadDigest
|
|
224
|
+
/** Hash of attestations emitted in the CheckpointProposed event. */
|
|
225
|
+
attestationsHash: Buffer32;
|
|
226
|
+
/** Digest of the payload emitted in the CheckpointProposed event. */
|
|
227
|
+
payloadDigest: Buffer32;
|
|
200
228
|
};
|
|
201
229
|
|
|
202
230
|
/** Log type for CheckpointProposed events. */
|
|
@@ -204,6 +232,7 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
204
232
|
|
|
205
233
|
export class RollupContract {
|
|
206
234
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
235
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
207
236
|
|
|
208
237
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
209
238
|
private cachedEscapeHatch?: {
|
|
@@ -233,7 +262,7 @@ export class RollupContract {
|
|
|
233
262
|
|
|
234
263
|
static getFromConfig(config: L1ReaderConfig) {
|
|
235
264
|
const client = getPublicClient(config);
|
|
236
|
-
const address = config.
|
|
265
|
+
const address = config.rollupAddress.toString();
|
|
237
266
|
return new RollupContract(client, address);
|
|
238
267
|
}
|
|
239
268
|
|
|
@@ -259,34 +288,18 @@ export class RollupContract {
|
|
|
259
288
|
return this.rollup;
|
|
260
289
|
}
|
|
261
290
|
|
|
262
|
-
public async getSlashingProposer(): Promise<
|
|
263
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
264
|
-
> {
|
|
291
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
265
292
|
const slasher = await this.getSlasherContract();
|
|
266
293
|
if (!slasher) {
|
|
267
294
|
return undefined;
|
|
268
295
|
}
|
|
269
296
|
|
|
270
297
|
const proposerAddress = await slasher.getProposer();
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
type: 'function',
|
|
274
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
275
|
-
inputs: [],
|
|
276
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
277
|
-
stateMutability: 'view',
|
|
278
|
-
},
|
|
279
|
-
] as const;
|
|
280
|
-
|
|
281
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
282
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
283
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
284
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
285
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
286
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
287
|
-
} else {
|
|
288
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
298
|
+
if (proposerAddress.isZero()) {
|
|
299
|
+
return undefined;
|
|
289
300
|
}
|
|
301
|
+
|
|
302
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
290
303
|
}
|
|
291
304
|
|
|
292
305
|
@memoize
|
|
@@ -379,6 +392,20 @@ export class RollupContract {
|
|
|
379
392
|
return Fr.fromString(await this.rollup.read.archiveAt([0n]));
|
|
380
393
|
}
|
|
381
394
|
|
|
395
|
+
@memoize
|
|
396
|
+
async getVkTreeRoot(): Promise<Fr> {
|
|
397
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 3n;
|
|
398
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
399
|
+
return Fr.fromString(value ?? '0x0');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
@memoize
|
|
403
|
+
async getProtocolContractsHash(): Promise<Fr> {
|
|
404
|
+
const slot = BigInt(RollupContract.stfStorageSlot) + 4n;
|
|
405
|
+
const value = await this.client.getStorageAt({ address: this.address, slot: `0x${slot.toString(16)}` });
|
|
406
|
+
return Fr.fromString(value ?? '0x0');
|
|
407
|
+
}
|
|
408
|
+
|
|
382
409
|
/**
|
|
383
410
|
* Returns rollup constants used for epoch queries.
|
|
384
411
|
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
@@ -391,13 +418,25 @@ export class RollupContract {
|
|
|
391
418
|
slotDuration: number;
|
|
392
419
|
epochDuration: number;
|
|
393
420
|
proofSubmissionEpochs: number;
|
|
421
|
+
targetCommitteeSize: number;
|
|
422
|
+
rollupManaLimit: number;
|
|
394
423
|
}> {
|
|
395
|
-
const [
|
|
424
|
+
const [
|
|
425
|
+
l1StartBlock,
|
|
426
|
+
l1GenesisTime,
|
|
427
|
+
slotDuration,
|
|
428
|
+
epochDuration,
|
|
429
|
+
proofSubmissionEpochs,
|
|
430
|
+
targetCommitteeSize,
|
|
431
|
+
rollupManaLimit,
|
|
432
|
+
] = await Promise.all([
|
|
396
433
|
this.getL1StartBlock(),
|
|
397
434
|
this.getL1GenesisTime(),
|
|
398
435
|
this.getSlotDuration(),
|
|
399
436
|
this.getEpochDuration(),
|
|
400
437
|
this.getProofSubmissionEpochs(),
|
|
438
|
+
this.getTargetCommitteeSize(),
|
|
439
|
+
this.getManaLimit(),
|
|
401
440
|
]);
|
|
402
441
|
return {
|
|
403
442
|
l1StartBlock,
|
|
@@ -405,6 +444,8 @@ export class RollupContract {
|
|
|
405
444
|
slotDuration,
|
|
406
445
|
epochDuration: Number(epochDuration),
|
|
407
446
|
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
447
|
+
targetCommitteeSize,
|
|
448
|
+
rollupManaLimit: Number(rollupManaLimit),
|
|
408
449
|
};
|
|
409
450
|
}
|
|
410
451
|
|
|
@@ -459,7 +500,11 @@ export class RollupContract {
|
|
|
459
500
|
|
|
460
501
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
461
502
|
return isOpen;
|
|
462
|
-
} catch {
|
|
503
|
+
} catch (err) {
|
|
504
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
505
|
+
epoch: Number(epoch),
|
|
506
|
+
error: err,
|
|
507
|
+
});
|
|
463
508
|
return false;
|
|
464
509
|
}
|
|
465
510
|
}
|
|
@@ -495,26 +540,41 @@ export class RollupContract {
|
|
|
495
540
|
return this.rollup.read.getCheckpointReward();
|
|
496
541
|
}
|
|
497
542
|
|
|
498
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
499
|
-
|
|
543
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
544
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
545
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
500
546
|
}
|
|
501
547
|
|
|
502
|
-
async getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
503
|
-
|
|
548
|
+
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
549
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
550
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
504
551
|
}
|
|
505
552
|
|
|
506
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
507
|
-
|
|
553
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
554
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
555
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
508
556
|
}
|
|
509
557
|
|
|
510
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
511
|
-
|
|
558
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
559
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
560
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
512
561
|
return {
|
|
513
562
|
baseFee: result.baseFee,
|
|
514
563
|
blobFee: result.blobFee,
|
|
515
564
|
};
|
|
516
565
|
}
|
|
517
566
|
|
|
567
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
568
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
569
|
+
return {
|
|
570
|
+
excessMana: result.excessMana,
|
|
571
|
+
manaUsed: result.manaUsed,
|
|
572
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
573
|
+
congestionCost: result.congestionCost,
|
|
574
|
+
proverCost: result.proverCost,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
518
578
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
519
579
|
return this.rollup.read.getEthPerFeeAsset();
|
|
520
580
|
}
|
|
@@ -589,8 +649,9 @@ export class RollupContract {
|
|
|
589
649
|
return EthAddress.fromString(result);
|
|
590
650
|
}
|
|
591
651
|
|
|
592
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
593
|
-
|
|
652
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
653
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
654
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
594
655
|
return {
|
|
595
656
|
archive: Fr.fromString(result.archive),
|
|
596
657
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -623,6 +684,30 @@ export class RollupContract {
|
|
|
623
684
|
);
|
|
624
685
|
}
|
|
625
686
|
|
|
687
|
+
/**
|
|
688
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
689
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
690
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
691
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
692
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
693
|
+
*/
|
|
694
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
695
|
+
return retry(
|
|
696
|
+
async () => {
|
|
697
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
698
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
699
|
+
if (canPrune) {
|
|
700
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
701
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
702
|
+
}
|
|
703
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
704
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
705
|
+
},
|
|
706
|
+
'getting effective pending checkpoint',
|
|
707
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
|
|
626
711
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
627
712
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
628
713
|
return {
|
|
@@ -741,14 +826,13 @@ export class RollupContract {
|
|
|
741
826
|
* timestamp of the next L1 block
|
|
742
827
|
* @throws otherwise
|
|
743
828
|
*/
|
|
744
|
-
public async
|
|
829
|
+
public async canProposeAt(
|
|
745
830
|
archive: Buffer,
|
|
746
831
|
account: `0x${string}` | Account,
|
|
747
|
-
|
|
748
|
-
|
|
832
|
+
timestamp: bigint,
|
|
833
|
+
stateOverride: StateOverride = [],
|
|
749
834
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
750
|
-
const
|
|
751
|
-
const timeOfNextL1Slot = latestBlock.timestamp + BigInt(slotDuration);
|
|
835
|
+
const timeOfNextL1Slot = timestamp;
|
|
752
836
|
const who = typeof account === 'string' ? account : account.address;
|
|
753
837
|
|
|
754
838
|
try {
|
|
@@ -760,7 +844,7 @@ export class RollupContract {
|
|
|
760
844
|
functionName: 'canProposeAtTime',
|
|
761
845
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
762
846
|
account,
|
|
763
|
-
stateOverride
|
|
847
|
+
stateOverride,
|
|
764
848
|
});
|
|
765
849
|
|
|
766
850
|
return {
|
|
@@ -774,20 +858,32 @@ export class RollupContract {
|
|
|
774
858
|
}
|
|
775
859
|
|
|
776
860
|
/**
|
|
777
|
-
* Returns a state override that sets the pending
|
|
778
|
-
*
|
|
779
|
-
*
|
|
861
|
+
* Returns a state override that sets the pending and/or proven checkpoint numbers. Useful for simulations.
|
|
862
|
+
* Both values share a single storage slot (pending in the upper 128 bits, proven in the lower 128 bits), so
|
|
863
|
+
* a single combined override is emitted to avoid the second state-diff clobbering the first. The current live
|
|
864
|
+
* value is read once to preserve any half not being overridden. Returns an empty override if neither is set.
|
|
865
|
+
*
|
|
866
|
+
* Throws if the resulting `proven > pending`, which would crash the simulation: `STFLib.canPruneAtTime` calls
|
|
867
|
+
* `getEpochForCheckpoint(proven + 1)` whenever `pending != proven`, and that asserts `_n <= tips.pending`.
|
|
780
868
|
*/
|
|
781
|
-
public async
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
869
|
+
public async makeChainTipsOverride(override: {
|
|
870
|
+
pending?: CheckpointNumber;
|
|
871
|
+
proven?: CheckpointNumber;
|
|
872
|
+
}): Promise<StateOverride> {
|
|
873
|
+
if (override.pending === undefined && override.proven === undefined) {
|
|
785
874
|
return [];
|
|
786
875
|
}
|
|
787
876
|
const slot = RollupContract.stfStorageSlot;
|
|
788
877
|
const currentValue = await this.client.getStorageAt({ address: this.address, slot });
|
|
789
|
-
const
|
|
790
|
-
const
|
|
878
|
+
const currentRaw = currentValue ? hexToBigInt(currentValue) : 0n;
|
|
879
|
+
const currentPending = currentRaw >> 128n;
|
|
880
|
+
const currentProven = currentRaw & ((1n << 128n) - 1n);
|
|
881
|
+
const newPending = override.pending !== undefined ? BigInt(override.pending) : currentPending;
|
|
882
|
+
const newProven = override.proven !== undefined ? BigInt(override.proven) : currentProven;
|
|
883
|
+
if (newProven > newPending) {
|
|
884
|
+
throw new Error(`Invalid chain tips override: proven (${newProven}) > pending (${newPending})`);
|
|
885
|
+
}
|
|
886
|
+
const newValue = (newPending << 128n) | newProven;
|
|
791
887
|
return [
|
|
792
888
|
{
|
|
793
889
|
address: this.address,
|
|
@@ -796,6 +892,168 @@ export class RollupContract {
|
|
|
796
892
|
];
|
|
797
893
|
}
|
|
798
894
|
|
|
895
|
+
/**
|
|
896
|
+
* Returns a state override that patches `tempCheckpointLogs[checkpointNumber]` with every field that
|
|
897
|
+
* the L1 contract reads during `propose()` for the checkpoint that builds on top of it (proposer
|
|
898
|
+
* pipelining simulation). Mirrors the writes done by `ProposeLib.addTempCheckpointLog`.
|
|
899
|
+
*
|
|
900
|
+
* `blobCommitmentsHash` and `attestationsHash` are intentionally not exposed here — the propose path
|
|
901
|
+
* never asserts against them, so leaving them at storage zero is harmless.
|
|
902
|
+
*/
|
|
903
|
+
public async makeTempCheckpointLogOverride(
|
|
904
|
+
checkpointNumber: CheckpointNumber,
|
|
905
|
+
fields: TempCheckpointLogOverrideFields,
|
|
906
|
+
): Promise<StateOverride> {
|
|
907
|
+
const constants = await this.getRollupConstants();
|
|
908
|
+
const slotAt = (field: TempCheckpointLogField) =>
|
|
909
|
+
`0x${this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, constants).toString(16).padStart(64, '0')}` as const;
|
|
910
|
+
const word = (v: bigint) => `0x${v.toString(16).padStart(64, '0')}` as const;
|
|
911
|
+
|
|
912
|
+
const stateDiff: { slot: `0x${string}`; value: `0x${string}` }[] = [];
|
|
913
|
+
|
|
914
|
+
if (fields.headerHash) {
|
|
915
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.HeaderHash), value: fields.headerHash.toString() });
|
|
916
|
+
}
|
|
917
|
+
if (fields.outHash) {
|
|
918
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.OutHash), value: fields.outHash.toString() });
|
|
919
|
+
}
|
|
920
|
+
if (fields.payloadDigest) {
|
|
921
|
+
stateDiff.push({
|
|
922
|
+
slot: slotAt(TempCheckpointLogField.PayloadDigest),
|
|
923
|
+
value: fields.payloadDigest.toString() as `0x${string}`,
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
if (fields.slotNumber !== undefined) {
|
|
927
|
+
// CompressedSlot is uint32 on L1 (SafeCast.toUint32 reverts on overflow). Match that behavior here
|
|
928
|
+
// so a malformed override surfaces immediately rather than silently truncating into a wrong slot.
|
|
929
|
+
const slotNumber = BigInt(fields.slotNumber);
|
|
930
|
+
if (slotNumber < 0n || slotNumber > 0xffffffffn) {
|
|
931
|
+
throw new Error(`slotNumber ${slotNumber} does not fit in uint32`);
|
|
932
|
+
}
|
|
933
|
+
stateDiff.push({ slot: slotAt(TempCheckpointLogField.SlotNumber), value: word(slotNumber) });
|
|
934
|
+
}
|
|
935
|
+
if (fields.feeHeader) {
|
|
936
|
+
stateDiff.push({
|
|
937
|
+
slot: slotAt(TempCheckpointLogField.FeeHeader),
|
|
938
|
+
value: word(RollupContract.compressFeeHeader(fields.feeHeader)),
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (stateDiff.length === 0) {
|
|
943
|
+
return [];
|
|
944
|
+
}
|
|
945
|
+
return [{ address: this.address, stateDiff }];
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
950
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
951
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
952
|
+
*/
|
|
953
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
954
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
955
|
+
const archiveSlot = hexToBigInt(
|
|
956
|
+
keccak256(
|
|
957
|
+
encodeAbiParameters(
|
|
958
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
959
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
960
|
+
),
|
|
961
|
+
),
|
|
962
|
+
);
|
|
963
|
+
return [
|
|
964
|
+
{
|
|
965
|
+
address: this.address,
|
|
966
|
+
stateDiff: [
|
|
967
|
+
{
|
|
968
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
969
|
+
value: archive.toString(),
|
|
970
|
+
},
|
|
971
|
+
],
|
|
972
|
+
},
|
|
973
|
+
];
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
977
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
978
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
979
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
980
|
+
for (const override of overrides) {
|
|
981
|
+
for (const entry of override) {
|
|
982
|
+
const key = entry.address.toLowerCase();
|
|
983
|
+
const existing = byAddress.get(key);
|
|
984
|
+
if (existing) {
|
|
985
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
986
|
+
if (entry.balance !== undefined) {
|
|
987
|
+
existing.balance = entry.balance;
|
|
988
|
+
}
|
|
989
|
+
} else {
|
|
990
|
+
byAddress.set(key, {
|
|
991
|
+
address: entry.address,
|
|
992
|
+
balance: entry.balance,
|
|
993
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return [...byAddress.values()];
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
1002
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
1003
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
1004
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
1005
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
1006
|
+
|
|
1007
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
1008
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
1009
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
1010
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
1011
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
1012
|
+
value |= 1n << 255n; // preheat flag
|
|
1013
|
+
return value;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
1017
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
1018
|
+
public static computeChildFeeHeader(
|
|
1019
|
+
parentFeeHeader: FeeHeader,
|
|
1020
|
+
childManaUsed: bigint,
|
|
1021
|
+
feeAssetPriceModifier: bigint,
|
|
1022
|
+
manaTarget: bigint,
|
|
1023
|
+
): FeeHeader {
|
|
1024
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
1025
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
1026
|
+
|
|
1027
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
1028
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
1029
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
1030
|
+
|
|
1031
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
1032
|
+
const parentPrice =
|
|
1033
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
1034
|
+
let newPrice: bigint;
|
|
1035
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
1036
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
1037
|
+
} else {
|
|
1038
|
+
const absMod = -feeAssetPriceModifier;
|
|
1039
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
1040
|
+
}
|
|
1041
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
1042
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
1043
|
+
}
|
|
1044
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1045
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
return {
|
|
1049
|
+
excessMana,
|
|
1050
|
+
manaUsed: childManaUsed,
|
|
1051
|
+
ethPerFeeAsset: newPrice,
|
|
1052
|
+
congestionCost: 0n,
|
|
1053
|
+
proverCost: 0n,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
|
|
799
1057
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
800
1058
|
public buildInvalidateBadAttestationRequest(
|
|
801
1059
|
checkpointNumber: CheckpointNumber,
|
|
@@ -844,8 +1102,18 @@ export class RollupContract {
|
|
|
844
1102
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
845
1103
|
}
|
|
846
1104
|
|
|
847
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
848
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1105
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1106
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
1110
|
+
const result = await this.rollup.read.getManaMinFeeComponentsAt([timestamp, inFeeAsset]);
|
|
1111
|
+
return {
|
|
1112
|
+
sequencerCost: result.sequencerCost,
|
|
1113
|
+
proverCost: result.proverCost,
|
|
1114
|
+
congestionCost: result.congestionCost,
|
|
1115
|
+
congestionMultiplier: result.congestionMultiplier,
|
|
1116
|
+
};
|
|
849
1117
|
}
|
|
850
1118
|
|
|
851
1119
|
async getSlotAt(timestamp: bigint): Promise<SlotNumber> {
|
|
@@ -891,11 +1159,10 @@ export class RollupContract {
|
|
|
891
1159
|
return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]);
|
|
892
1160
|
}
|
|
893
1161
|
|
|
894
|
-
async getAttesters(): Promise<EthAddress[]> {
|
|
1162
|
+
async getAttesters(timestamp?: bigint): Promise<EthAddress[]> {
|
|
895
1163
|
const attesterSize = await this.getActiveAttesterCount();
|
|
896
1164
|
const gse = new GSEContract(this.client, await this.getGSE());
|
|
897
|
-
const ts = (await this.client.getBlock()).timestamp;
|
|
898
|
-
|
|
1165
|
+
const ts = timestamp ?? (await this.client.getBlock()).timestamp;
|
|
899
1166
|
const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i));
|
|
900
1167
|
const chunks = chunk(indices, 1000);
|
|
901
1168
|
|
|
@@ -1001,7 +1268,7 @@ export class RollupContract {
|
|
|
1001
1268
|
}
|
|
1002
1269
|
|
|
1003
1270
|
public listenToCheckpointInvalidated(
|
|
1004
|
-
callback: (args: { checkpointNumber: CheckpointNumber }) => unknown,
|
|
1271
|
+
callback: (args: { checkpointNumber: CheckpointNumber; event: Log }) => unknown,
|
|
1005
1272
|
): WatchContractEventReturnType {
|
|
1006
1273
|
return this.rollup.watchEvent.CheckpointInvalidated(
|
|
1007
1274
|
{},
|
|
@@ -1010,7 +1277,7 @@ export class RollupContract {
|
|
|
1010
1277
|
for (const log of logs) {
|
|
1011
1278
|
const args = log.args;
|
|
1012
1279
|
if (args.checkpointNumber !== undefined) {
|
|
1013
|
-
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber) });
|
|
1280
|
+
callback({ checkpointNumber: CheckpointNumber.fromBigInt(args.checkpointNumber), event: log });
|
|
1014
1281
|
}
|
|
1015
1282
|
}
|
|
1016
1283
|
},
|
|
@@ -1043,6 +1310,17 @@ export class RollupContract {
|
|
|
1043
1310
|
);
|
|
1044
1311
|
}
|
|
1045
1312
|
|
|
1313
|
+
/**
|
|
1314
|
+
* Fetches OwnershipTransferred events emitted on the L1 block this rollup was deployed on.
|
|
1315
|
+
* The Rollup inherits from Ownable and emits this event in its constructor, so the event
|
|
1316
|
+
* is guaranteed to exist on `l1StartBlock` for any correctly deployed rollup. Used as a
|
|
1317
|
+
* probe to detect RPC nodes that prune historical logs.
|
|
1318
|
+
*/
|
|
1319
|
+
async getOwnershipTransferredEventsAtDeploy() {
|
|
1320
|
+
const l1StartBlock = await this.getL1StartBlock();
|
|
1321
|
+
return await this.rollup.getEvents.OwnershipTransferred({}, { fromBlock: l1StartBlock, toBlock: l1StartBlock });
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1046
1324
|
/** Fetches CheckpointProposed events within the given block range. */
|
|
1047
1325
|
async getCheckpointProposedEvents(fromBlock: bigint, toBlock: bigint): Promise<CheckpointProposedLog[]> {
|
|
1048
1326
|
const logs = await this.rollup.getEvents.CheckpointProposed({}, { fromBlock, toBlock });
|
|
@@ -1056,9 +1334,67 @@ export class RollupContract {
|
|
|
1056
1334
|
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber!),
|
|
1057
1335
|
archive: Fr.fromString(log.args.archive!),
|
|
1058
1336
|
versionedBlobHashes: log.args.versionedBlobHashes!.map(h => Buffer.from(h.slice(2), 'hex')),
|
|
1059
|
-
attestationsHash:
|
|
1060
|
-
|
|
1337
|
+
attestationsHash: (() => {
|
|
1338
|
+
if (!log.args.attestationsHash) {
|
|
1339
|
+
throw new Error(
|
|
1340
|
+
`CheckpointProposed event missing attestationsHash for checkpoint ${log.args.checkpointNumber}`,
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
return Buffer32.fromString(log.args.attestationsHash);
|
|
1344
|
+
})(),
|
|
1345
|
+
payloadDigest: (() => {
|
|
1346
|
+
if (!log.args.payloadDigest) {
|
|
1347
|
+
throw new Error(
|
|
1348
|
+
`CheckpointProposed event missing payloadDigest for checkpoint ${log.args.checkpointNumber}`,
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
return Buffer32.fromString(log.args.payloadDigest);
|
|
1352
|
+
})(),
|
|
1061
1353
|
},
|
|
1062
1354
|
}));
|
|
1063
1355
|
}
|
|
1356
|
+
|
|
1357
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1358
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1359
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1363
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1364
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1369
|
+
* @param checkpointNumber - The checkpoint number
|
|
1370
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1371
|
+
*/
|
|
1372
|
+
async getTempCheckpointLogStorageSlot(
|
|
1373
|
+
checkpointNumber: CheckpointNumber,
|
|
1374
|
+
field: TempCheckpointLogField,
|
|
1375
|
+
): Promise<bigint> {
|
|
1376
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1377
|
+
this.getEpochDuration(),
|
|
1378
|
+
this.getProofSubmissionEpochs(),
|
|
1379
|
+
]);
|
|
1380
|
+
return this.computeTempCheckpointLogStorageSlot(checkpointNumber, field, { epochDuration, proofSubmissionEpochs });
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
private computeTempCheckpointLogStorageSlot(
|
|
1384
|
+
checkpointNumber: CheckpointNumber,
|
|
1385
|
+
field: TempCheckpointLogField,
|
|
1386
|
+
constants: { epochDuration: number; proofSubmissionEpochs: number },
|
|
1387
|
+
): bigint {
|
|
1388
|
+
const fieldOffset = BigInt(field);
|
|
1389
|
+
const { epochDuration, proofSubmissionEpochs } = constants;
|
|
1390
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1391
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1392
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1393
|
+
const entryBase = BigInt(
|
|
1394
|
+
keccak256(
|
|
1395
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1396
|
+
),
|
|
1397
|
+
);
|
|
1398
|
+
return entryBase + fieldOffset;
|
|
1399
|
+
}
|
|
1064
1400
|
}
|