From 2c421514e175b9cc25d5b488bb8cb150d7ffbd9b Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 23 Dec 2025 19:01:04 -0300 Subject: [PATCH] chore: Proper types for rollup contract responses Instead of using plain strings, use proper types, like AztecAddress, EthAddress, Fr, Buffer32, CheckpointNumber, etc. --- .../archiver/src/archiver/archiver.ts | 64 ++-- .../archiver/src/archiver/validation.ts | 2 +- .../aztec-node/src/sentinel/sentinel.test.ts | 3 +- .../aztec-node/src/sentinel/sentinel.ts | 2 +- .../cli/src/cmds/infrastructure/sequencers.ts | 2 +- .../epochs_proof_fails.parallel.test.ts | 2 +- .../end-to-end/src/e2e_fees/fees_test.ts | 6 +- .../e2e_l1_publisher/e2e_l1_publisher.test.ts | 6 +- .../e2e_p2p/gossip_network_no_cheat.test.ts | 10 +- ...tiple_validators_sentinel.parallel.test.ts | 3 +- .../end-to-end/src/e2e_p2p/p2p_network.ts | 2 +- .../end-to-end/src/e2e_p2p/reqresp.test.ts | 6 +- .../src/e2e_p2p/reqresp_no_handshake.test.ts | 6 +- yarn-project/end-to-end/src/e2e_p2p/shared.ts | 11 +- .../src/e2e_p2p/slash_veto_demo.test.ts | 8 +- .../src/spartan/slash_inactivity.test.ts | 2 +- .../epoch-cache/src/epoch_cache.test.ts | 31 +- yarn-project/epoch-cache/src/epoch_cache.ts | 15 +- yarn-project/ethereum/src/contracts/rollup.ts | 318 +++++++++++++----- .../contracts/tally_slashing_proposer.test.ts | 2 +- yarn-project/ethereum/src/queries.ts | 4 +- .../ethereum/src/test/chain_monitor.ts | 2 +- .../testbench/p2p_client_testbench_worker.ts | 3 +- .../src/prover-node-publisher.test.ts | 31 +- .../prover-node/src/prover-node-publisher.ts | 10 +- .../global_variable_builder/global_builder.ts | 2 +- .../src/publisher/sequencer-publisher.test.ts | 5 +- .../src/sequencer/checkpoint_proposal_job.ts | 2 +- .../src/sequencer/sequencer.test.ts | 11 +- .../slasher/src/tally_slasher_client.test.ts | 7 +- .../watchers/attestations_block_watcher.ts | 8 +- .../src/watchers/epoch_prune_watcher.test.ts | 7 +- .../txe/src/state_machine/mock_epoch_cache.ts | 3 +- 33 files changed, 382 insertions(+), 214 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index abc0705478a0..693c94097d8d 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -275,7 +275,7 @@ export class Archiver slotDuration, ethereumSlotDuration, proofSubmissionEpochs: Number(proofSubmissionEpochs), - genesisArchiveRoot: Fr.fromHexString(genesisArchiveRoot), + genesisArchiveRoot: Fr.fromString(genesisArchiveRoot.toString()), }; const opts = merge( @@ -789,22 +789,17 @@ export class Archiver private async handleCheckpoints(blocksSynchedTo: bigint, currentL1BlockNumber: bigint): Promise { const localPendingCheckpointNumber = await this.getSynchedCheckpointNumber(); const initialValidationResult: ValidateBlockResult | undefined = await this.store.getPendingChainValidationStatus(); - const [ - rollupProvenCheckpointNumber, - provenArchive, - rollupPendingCheckpointNumber, - pendingArchive, - archiveForLocalPendingCheckpointNumber, - ] = await this.rollup.status(localPendingCheckpointNumber, { blockNumber: currentL1BlockNumber }); - const provenCheckpointNumber = CheckpointNumber.fromBigInt(rollupProvenCheckpointNumber); - const pendingCheckpointNumber = CheckpointNumber.fromBigInt(rollupPendingCheckpointNumber); - const rollupStatus = { - provenCheckpointNumber, - provenArchive, - pendingCheckpointNumber, - pendingArchive, + const checkpointStatus = await this.rollup.status(localPendingCheckpointNumber, { + blockNumber: currentL1BlockNumber, + }); + const rollupStatus: RollupStatus = { + provenCheckpointNumber: checkpointStatus.provenCheckpointNumber, + provenArchive: checkpointStatus.provenArchive.toString(), + pendingCheckpointNumber: checkpointStatus.pendingCheckpointNumber, + pendingArchive: checkpointStatus.pendingArchive.toString(), validationResult: initialValidationResult, }; + const archiveForLocalPendingCheckpointNumber = checkpointStatus.archiveOfMyCheckpoint; this.log.trace(`Retrieved rollup status at current L1 block ${currentL1BlockNumber}.`, { localPendingCheckpointNumber, blocksSynchedTo, @@ -817,16 +812,19 @@ export class Archiver // Annoying edge case: if proven checkpoint is moved back to 0 due to a reorg at the beginning of the chain, // we need to set it to zero. This is an edge case because we dont have a checkpoint zero (initial checkpoint is one), // so localCheckpointForDestinationProvenCheckpointNumber would not be found below. - if (provenCheckpointNumber === 0) { + if (rollupStatus.provenCheckpointNumber === CheckpointNumber(0)) { const localProvenCheckpointNumber = await this.getProvenCheckpointNumber(); - if (localProvenCheckpointNumber !== provenCheckpointNumber) { - await this.setProvenCheckpointNumber(provenCheckpointNumber); - this.log.info(`Rolled back proven chain to checkpoint ${provenCheckpointNumber}`, { provenCheckpointNumber }); + if (localProvenCheckpointNumber !== rollupStatus.provenCheckpointNumber) { + await this.setProvenCheckpointNumber(rollupStatus.provenCheckpointNumber); + this.log.info(`Rolled back proven chain to checkpoint ${rollupStatus.provenCheckpointNumber}`, { + provenCheckpointNumber: rollupStatus.provenCheckpointNumber, + }); } } - const localCheckpointForDestinationProvenCheckpointNumber = - await this.store.getCheckpointData(provenCheckpointNumber); + const localCheckpointForDestinationProvenCheckpointNumber = await this.store.getCheckpointData( + rollupStatus.provenCheckpointNumber, + ); // Sanity check. I've hit what seems to be a state where the proven checkpoint is set to a value greater than the latest // synched checkpoint when requesting L2Tips from the archiver. This is the only place where the proven checkpoint is set. @@ -841,20 +839,20 @@ export class Archiver } this.log.trace( - `Local checkpoint for remote proven checkpoint ${provenCheckpointNumber} is ${ + `Local checkpoint for remote proven checkpoint ${rollupStatus.provenCheckpointNumber} is ${ localCheckpointForDestinationProvenCheckpointNumber?.archive.root.toString() ?? 'undefined' }`, ); if ( localCheckpointForDestinationProvenCheckpointNumber && - provenArchive === localCheckpointForDestinationProvenCheckpointNumber.archive.root.toString() + rollupStatus.provenArchive === localCheckpointForDestinationProvenCheckpointNumber.archive.root.toString() ) { const localProvenCheckpointNumber = await this.getProvenCheckpointNumber(); - if (localProvenCheckpointNumber !== provenCheckpointNumber) { - await this.setProvenCheckpointNumber(provenCheckpointNumber); - this.log.info(`Updated proven chain to checkpoint ${provenCheckpointNumber}`, { - provenCheckpointNumber, + if (localProvenCheckpointNumber !== rollupStatus.provenCheckpointNumber) { + await this.setProvenCheckpointNumber(rollupStatus.provenCheckpointNumber); + this.log.info(`Updated proven chain to checkpoint ${rollupStatus.provenCheckpointNumber}`, { + provenCheckpointNumber: rollupStatus.provenCheckpointNumber, }); const provenSlotNumber = localCheckpointForDestinationProvenCheckpointNumber.header.slotNumber; const provenEpochNumber: EpochNumber = getEpochAtSlot(provenSlotNumber, this.l1constants); @@ -871,14 +869,15 @@ export class Archiver }); this.instrumentation.updateLastProvenBlock(lastBlockNumberInCheckpoint); } else { - this.log.trace(`Proven checkpoint ${provenCheckpointNumber} already stored.`); + this.log.trace(`Proven checkpoint ${rollupStatus.provenCheckpointNumber} already stored.`); } } }; // This is an edge case that we only hit if there are no proposed checkpoints. // If we have 0 checkpoints locally and there are no checkpoints onchain there is nothing to do. - const noCheckpoints = localPendingCheckpointNumber === 0 && pendingCheckpointNumber === 0; + const noCheckpoints = + localPendingCheckpointNumber === 0 && rollupStatus.pendingCheckpointNumber === CheckpointNumber(0); if (noCheckpoints) { await this.store.setCheckpointSynchedL1BlockNumber(currentL1BlockNumber); this.log.debug( @@ -898,7 +897,7 @@ export class Archiver } const localPendingArchiveRoot = localPendingCheckpoint.archive.root.toString(); - const noCheckpointSinceLast = localPendingCheckpoint && pendingArchive === localPendingArchiveRoot; + const noCheckpointSinceLast = localPendingCheckpoint && rollupStatus.pendingArchive === localPendingArchiveRoot; if (noCheckpointSinceLast) { // We believe the following line causes a problem when we encounter L1 re-orgs. // Basically, by setting the synched L1 block number here, we are saying that we have @@ -912,7 +911,8 @@ export class Archiver return rollupStatus; } - const localPendingCheckpointInChain = archiveForLocalPendingCheckpointNumber === localPendingArchiveRoot; + const localPendingCheckpointInChain = + archiveForLocalPendingCheckpointNumber.toString() === localPendingArchiveRoot; if (!localPendingCheckpointInChain) { // If our local pending checkpoint tip is not in the chain on L1 a "prune" must have happened // or the L1 have reorged. @@ -938,7 +938,7 @@ export class Archiver archiveLocal: candidateCheckpoint.archive.root.toString(), }, ); - if (archiveAtContract === candidateCheckpoint.archive.root.toString()) { + if (archiveAtContract.equals(candidateCheckpoint.archive.root)) { break; } tipAfterUnwind--; diff --git a/yarn-project/archiver/src/archiver/validation.ts b/yarn-project/archiver/src/archiver/validation.ts index 63077d77b3ee..ad55d2aab494 100644 --- a/yarn-project/archiver/src/archiver/validation.ts +++ b/yarn-project/archiver/src/archiver/validation.ts @@ -68,7 +68,7 @@ export async function validateCheckpointAttestations( reason, block: checkpoint.blocks[0].toBlockInfo(), committee, - seed, + seed: seed.toBigInt(), epoch, attestors, attestations, diff --git a/yarn-project/aztec-node/src/sentinel/sentinel.test.ts b/yarn-project/aztec-node/src/sentinel/sentinel.test.ts index cccca2afbb57..7aa6d3fe40e1 100644 --- a/yarn-project/aztec-node/src/sentinel/sentinel.test.ts +++ b/yarn-project/aztec-node/src/sentinel/sentinel.test.ts @@ -1,5 +1,6 @@ import type { EpochCache } from '@aztec/epoch-cache'; import { BlockNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { compactArray, times } from '@aztec/foundation/collection'; import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -536,7 +537,7 @@ describe('sentinel', () => { epochCache.getCommittee.mockResolvedValue({ committee: [validator1, validator2, validator3], - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: epochNumber, }); diff --git a/yarn-project/aztec-node/src/sentinel/sentinel.ts b/yarn-project/aztec-node/src/sentinel/sentinel.ts index 9a3cb4e8fde4..d6b6c005939b 100644 --- a/yarn-project/aztec-node/src/sentinel/sentinel.ts +++ b/yarn-project/aztec-node/src/sentinel/sentinel.ts @@ -313,7 +313,7 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme this.lastProcessedSlot = slot; return; } - const proposerIndex = this.epochCache.computeProposerIndex(slot, epoch, seed, BigInt(committee.length)); + const proposerIndex = this.epochCache.computeProposerIndex(slot, epoch, seed.toBigInt(), BigInt(committee.length)); const proposer = committee[Number(proposerIndex)]; const stats = await this.getSlotActivity(slot, epoch, proposer, committee); this.logger.verbose(`Updating L2 slot ${slot} observed activity`, stats); diff --git a/yarn-project/cli/src/cmds/infrastructure/sequencers.ts b/yarn-project/cli/src/cmds/infrastructure/sequencers.ts index 5a00230a86e6..f00e089706cf 100644 --- a/yarn-project/cli/src/cmds/infrastructure/sequencers.ts +++ b/yarn-project/cli/src/cmds/infrastructure/sequencers.ts @@ -67,7 +67,7 @@ export async function sequencers(opts: { log(`Adding ${who} as sequencer`); const stakingAsset = getContract({ - address: await rollup.getStakingAsset(), + address: (await rollup.getStakingAsset()).toString() as `0x${string}`, abi: TestERC20Abi, client: walletClient, }); diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_fails.parallel.test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_fails.parallel.test.ts index c4ba33417359..18c6209ef233 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_fails.parallel.test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_fails.parallel.test.ts @@ -64,7 +64,7 @@ describe('e2e_epochs/epochs_proof_fails', () => { const firstCheckpointNumber = (await test.monitor.run()).checkpointNumber; expect(firstCheckpointNumber).toBeGreaterThanOrEqual(CheckpointNumber(1)); const firstCheckpoint = await rollup.getCheckpoint(CheckpointNumber(1)); - const firstCheckpointEpoch = getEpochAtSlot(SlotNumber.fromBigInt(firstCheckpoint.slotNumber), test.constants); + const firstCheckpointEpoch = getEpochAtSlot(firstCheckpoint.slotNumber, test.constants); expect(firstCheckpointEpoch).toEqual(EpochNumber(0)); // Create prover node after test setup to avoid early proving. We ensure the prover does not retry txs. diff --git a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts index 8489aebf5889..8a031a95352d 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts @@ -144,9 +144,7 @@ export class FeesTest { const blockReward = await this.rollupContract.getCheckpointReward(); const rewardConfig = await this.rollupContract.getRewardConfig(); - const balance = await this.feeJuiceBridgeTestHarness.getL1FeeJuiceBalance( - EthAddress.fromString(rewardConfig.rewardDistributor), - ); + const balance = await this.feeJuiceBridgeTestHarness.getL1FeeJuiceBalance(rewardConfig.rewardDistributor); const toDistribute = balance > blockReward ? blockReward : balance; const sequencerBlockRewards = (toDistribute * BigInt(rewardConfig.sequencerBps)) / 10000n; @@ -325,7 +323,7 @@ export class FeesTest { const { baseFee } = await this.rollupContract.getL1FeesAt(block!.header.globalVariables.timestamp); const proverCost = mulDiv( - mulDiv(L1_GAS_PER_EPOCH_VERIFIED, baseFee, await this.rollupContract.getEpochDuration()), + mulDiv(L1_GAS_PER_EPOCH_VERIFIED, baseFee, BigInt(await this.rollupContract.getEpochDuration())), 1n, await this.rollupContract.getManaTarget(), ) + (await this.rollupContract.getProvingCostPerMana()); diff --git a/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts b/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts index b7cf215904df..cd6d660751e8 100644 --- a/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts @@ -438,7 +438,7 @@ describe('L1Publisher integration', () => { sha256ToField(blockBlobs.map(b => b.getEthVersionedBlobHash())), ); - let prevBlobAccumulatorHash = hexToBuffer(await rollup.getCurrentBlobCommitmentsHash()); + let prevBlobAccumulatorHash = (await rollup.getCurrentBlobCommitmentsHash()).toBuffer(); blocks.push(block); blobFieldsPerCheckpoint.push(checkpointBlobFields); @@ -481,7 +481,7 @@ describe('L1Publisher integration', () => { (await rollup.getEpochNumberForCheckpoint(prevCheckpointNumber)); // If we are at the first blob of the epoch, we must initialize the hash: prevBlobAccumulatorHash = isFirstCheckpointOfEpoch ? Buffer.alloc(0) : prevBlobAccumulatorHash; - const currentBlobAccumulatorHash = hexToBuffer(await rollup.getCurrentBlobCommitmentsHash()); + const currentBlobAccumulatorHash = (await rollup.getCurrentBlobCommitmentsHash()).toBuffer(); let expectedBlobAccumulatorHash = prevBlobAccumulatorHash; blockBlobs .map(b => b.commitment) @@ -980,7 +980,7 @@ describe('L1Publisher integration', () => { expect(sendRequestsResult!.failedActions).toEqual([]); expect(await rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(block2.number)); const rollupBlock = await rollup.getCheckpoint(CheckpointNumber.fromBlockNumber(block2.number)); - expect(SlotNumber.fromBigInt(rollupBlock.slotNumber)).toEqual(block2.slot); + expect(rollupBlock.slotNumber).toEqual(block2.slot); }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts index e3c77aec6b30..8ebb054295fe 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts @@ -10,7 +10,6 @@ import { Signature } from '@aztec/foundation/eth-signature'; import { sleep } from '@aztec/foundation/sleep'; import { MockZKPassportVerifierAbi } from '@aztec/l1-artifacts/MockZKPassportVerifierAbi'; import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi'; -import { StakingAssetHandlerAbi } from '@aztec/l1-artifacts/StakingAssetHandlerAbi'; import type { SequencerClient } from '@aztec/sequencer-client'; import { BlockAttestation, ConsensusPayload } from '@aztec/stdlib/p2p'; import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport'; @@ -104,12 +103,6 @@ describe('e2e_p2p_network', () => { client: t.ctx.deployL1ContractsValues.l1Client, }); - const stakingAssetHandler = getContract({ - address: t.ctx.deployL1ContractsValues.l1ContractAddresses.stakingAssetHandlerAddress!.toString(), - abi: StakingAssetHandlerAbi, - client: t.ctx.deployL1ContractsValues.l1Client, - }); - const zkPassportVerifier = getContract({ address: t.ctx.deployL1ContractsValues.l1ContractAddresses.zkPassportVerifierAddress!.toString(), abi: MockZKPassportVerifierAbi, @@ -151,10 +144,9 @@ describe('e2e_p2p_network', () => { expect(attestersImmedatelyAfterAdding.length).toBe(validators.length); // Check that the validators are added correctly - const withdrawer = await stakingAssetHandler.read.withdrawer(); for (const validator of validators) { const info = await rollupWrapper.getAttesterView(validator.attester.toString()); - expect(info.config.withdrawer).toBe(withdrawer); + expect(info.config.publicKey).toBeDefined(); } // Wait for the validators to be added to the rollup diff --git a/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts b/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts index 5171ded95400..debe6ee71789 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/multiple_validators_sentinel.parallel.test.ts @@ -1,6 +1,5 @@ import type { AztecNodeService } from '@aztec/aztec-node'; import { RollupContract } from '@aztec/ethereum/contracts'; -import { EthAddress } from '@aztec/foundation/eth-address'; import { retryUntil } from '@aztec/foundation/retry'; import { tryStop } from '@aztec/stdlib/interfaces/server'; @@ -155,7 +154,7 @@ describe('e2e_p2p_multiple_validators_sentinel', () => { await Promise.all([ retryUntil(() => t.monitor.l2SlotNumber >= targetSlot, `reached slot ${targetSlot}`, timeout), retryUntil( - () => rollup.getCurrentProposer().then(p => firstNodeValidators.some(v => v.equals(EthAddress.fromString(p)))), + () => rollup.getCurrentProposer().then(p => firstNodeValidators.some(v => v.equals(p))), 'proposer is first node', timeout, ), diff --git a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts index 3660976c1724..17d56816c479 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/p2p_network.ts @@ -451,7 +451,7 @@ export class P2PNetworkTest { ); const slasherContract = getContract({ - address: getAddress(await rollup.getSlasherAddress()), + address: getAddress((await rollup.getSlasherAddress()).toString()), abi: SlasherAbi, client: this.ctx.deployL1ContractsValues.l1Client, }); diff --git a/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts index 192967d51b03..555c146f8a24 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reqresp.test.ts @@ -155,7 +155,7 @@ describe('e2e_p2p_reqresp_tx', () => { t.ctx.deployL1ContractsValues.l1ContractAddresses.rollupAddress, ); - const attesters = await rollupContract.getAttesters(); + const attesters = (await rollupContract.getAttesters()).map(a => a.toString() as `0x${string}`); const currentTime = await t.ctx.cheatCodes.eth.timestamp(); const slotDuration = await rollupContract.getSlotDuration(); @@ -168,12 +168,12 @@ describe('e2e_p2p_reqresp_tx', () => { proposers.push(proposer); } // Get the indexes of the nodes that are responsible for the next two slots - const proposerIndexes = proposers.map(proposer => attesters.indexOf(proposer as `0x${string}`)); + const proposerIndexes = proposers.map(proposer => attesters.indexOf(proposer.toString() as `0x${string}`)); if (proposerIndexes.some(i => i === -1)) { throw new Error( `Proposer index not found for proposer ` + - `(proposers=${proposers.join(',')}, indices=${proposerIndexes.join(',')})`, + `(proposers=${proposers.map(p => p.toString()).join(',')}, indices=${proposerIndexes.join(',')})`, ); } diff --git a/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts index b63cdebb893d..b8b39b7c754b 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reqresp_no_handshake.test.ts @@ -160,7 +160,7 @@ describe('e2e_p2p_reqresp_tx_no_handshake', () => { t.ctx.deployL1ContractsValues.l1ContractAddresses.rollupAddress, ); - const attesters = await rollupContract.getAttesters(); + const attesters = (await rollupContract.getAttesters()).map(a => a.toString() as `0x${string}`); const currentTime = await t.ctx.cheatCodes.eth.timestamp(); const slotDuration = await rollupContract.getSlotDuration(); @@ -173,12 +173,12 @@ describe('e2e_p2p_reqresp_tx_no_handshake', () => { proposers.push(proposer); } // Get the indexes of the nodes that are responsible for the next two slots - const proposerIndexes = proposers.map(proposer => attesters.indexOf(proposer as `0x${string}`)); + const proposerIndexes = proposers.map(proposer => attesters.indexOf(proposer.toString() as `0x${string}`)); if (proposerIndexes.some(i => i === -1)) { throw new Error( `Proposer index not found for proposer ` + - `(proposers=${proposers.join(',')}, indices=${proposerIndexes.join(',')})`, + `(proposers=${proposers.map(p => p.toString()).join(',')}, indices=${proposerIndexes.join(',')})`, ); } diff --git a/yarn-project/end-to-end/src/e2e_p2p/shared.ts b/yarn-project/end-to-end/src/e2e_p2p/shared.ts index 87e47fe685e1..e81511b7ecb4 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/shared.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/shared.ts @@ -13,6 +13,7 @@ import type { } from '@aztec/ethereum/contracts'; import { EpochNumber } from '@aztec/foundation/branded-types'; import { timesAsync, unique } from '@aztec/foundation/collection'; +import { EthAddress } from '@aztec/foundation/eth-address'; import { retryUntil } from '@aztec/foundation/retry'; import { pluralize } from '@aztec/foundation/string'; import type { SpamContract } from '@aztec/noir-test-contracts.js/Spam'; @@ -137,7 +138,7 @@ export async function awaitCommitteeExists({ logger: Logger; }): Promise { logger.info(`Waiting for committee to be set`); - let committee: readonly `0x${string}`[] | undefined; + let committee: EthAddress[] | undefined; await retryUntil( async () => { committee = await rollup.getCurrentEpochCommittee(); @@ -146,7 +147,7 @@ export async function awaitCommitteeExists({ 'non-empty committee', 60, ); - return committee!; + return committee!.map(c => c.toString() as `0x${string}`); } export async function awaitOffenseDetected({ @@ -218,7 +219,7 @@ export async function awaitCommitteeKicked({ if (slashingProposer.type === 'empire') { // Await for the slash payload to be created if empire (no payload is created on tally until execution time) - const targetEpoch = BigInt(await cheatCodes.getEpoch()) + (await rollup.getLagInEpochsForValidatorSet()) + 1n; + const targetEpoch = BigInt(await cheatCodes.getEpoch()) + BigInt(await rollup.getLagInEpochsForValidatorSet()) + 1n; logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`); await cheatCodes.advanceToEpoch(EpochNumber.fromBigInt(targetEpoch)); @@ -275,7 +276,9 @@ export async function awaitCommitteeKicked({ logger.info(`Advancing to check current committee`); await cheatCodes.debugRollup(); await cheatCodes.advanceToEpoch( - EpochNumber.fromBigInt(BigInt(await cheatCodes.getEpoch()) + (await rollup.getLagInEpochsForValidatorSet()) + 1n), + EpochNumber.fromBigInt( + BigInt(await cheatCodes.getEpoch()) + BigInt(await rollup.getLagInEpochsForValidatorSet()) + 1n, + ), ); await cheatCodes.debugRollup(); diff --git a/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts b/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts index 113a3e81dafa..ce52f857015d 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/slash_veto_demo.test.ts @@ -294,10 +294,10 @@ describe('veto slash', () => { await t.ctx.cheatCodes.eth.stopImpersonating(t.ctx.deployL1ContractsValues.l1ContractAddresses.governanceAddress); const slasherAddress = await rollup.getSlasherAddress(); - expect(slasherAddress.toLowerCase()).toEqual(newSlasherAddress.toString().toLowerCase()); + expect(slasherAddress.toString().toLowerCase()).toEqual(newSlasherAddress.toString().toLowerCase()); debugLogger.info(`\n\nnew slasher address: ${slasherAddress}\n\n`); const slasher = getContract({ - address: slasherAddress, + address: slasherAddress.toString() as `0x${string}`, abi: SlasherAbi, client: t.ctx.deployL1ContractsValues.l1Client, }); @@ -344,7 +344,7 @@ describe('veto slash', () => { const attester = privateKeyToAccount(attesterPrivateKey); const gseAddress = await rollup.getGSE(); const gse = getContract({ - address: gseAddress, + address: gseAddress.toString() as `0x${string}`, abi: GSEAbi, client: t.ctx.deployL1ContractsValues.l1Client, }); @@ -363,7 +363,7 @@ describe('veto slash', () => { if (shouldVeto) { const slasherAddress = await rollup.getSlasherAddress(); const { receipt } = await vetoerL1TxUtils.sendAndMonitorTransaction({ - to: slasherAddress, + to: slasherAddress.toString() as `0x${string}`, data: encodeFunctionData({ abi: SlasherAbi, functionName: 'vetoPayload', diff --git a/yarn-project/end-to-end/src/spartan/slash_inactivity.test.ts b/yarn-project/end-to-end/src/spartan/slash_inactivity.test.ts index 3e83369e0412..47df86821e21 100644 --- a/yarn-project/end-to-end/src/spartan/slash_inactivity.test.ts +++ b/yarn-project/end-to-end/src/spartan/slash_inactivity.test.ts @@ -130,7 +130,7 @@ describe('slash inactivity test', () => { // Choose the first committee member for the next epoch as the validator to disable const { committee, epoch } = await getNextEpochCommittee(); - offlineValidator = EthAddress.fromString(committee[0]); + offlineValidator = committee[0]; // Wait until we're near the end of the previous epoch const lastSlotBeforeEpoch = SlotNumber(getSlotRangeForEpoch(epoch, constants)[0] - 1); diff --git a/yarn-project/epoch-cache/src/epoch_cache.test.ts b/yarn-project/epoch-cache/src/epoch_cache.test.ts index b87d3f6a6c8b..84108443a757 100644 --- a/yarn-project/epoch-cache/src/epoch_cache.test.ts +++ b/yarn-project/epoch-cache/src/epoch_cache.test.ts @@ -1,6 +1,7 @@ import type { RollupContract } from '@aztec/ethereum/contracts'; import type { ViemPublicClient } from '@aztec/ethereum/types'; import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { times } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers'; @@ -44,9 +45,9 @@ describe('EpochCache', () => { rollupContract = mock(); // Mock the getCommitteeAt method - rollupContract.getCommitteeAt.mockResolvedValue(testCommittee.map(v => v.toString())); - rollupContract.getSampleSeedAt.mockResolvedValue(0n); - rollupContract.getAttesters.mockResolvedValue(testCommittee.map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue(testCommittee); + rollupContract.getSampleSeedAt.mockResolvedValue(Buffer32.fromBigInt(0n)); + rollupContract.getAttesters.mockResolvedValue(testCommittee); l1GenesisTime = BigInt(Math.floor(Date.now() / 1000)); @@ -76,7 +77,11 @@ describe('EpochCache', () => { epochCache = new TestEpochCache(rollupContract, testConstants); // Initialize the cache with the initial epoch's committee - epochCache.seedCache(EpochNumber(0), { epoch: EpochNumber(0), committee: testCommittee, seed: 0n }); + epochCache.seedCache(EpochNumber(0), { + epoch: EpochNumber(0), + committee: testCommittee, + seed: Buffer32.fromBigInt(0n), + }); }); afterEach(() => { @@ -94,7 +99,7 @@ describe('EpochCache', () => { jest.setSystemTime(Date.now() + (Number(EPOCH_DURATION * SLOT_DURATION) / 4) * 1000); // Add another validator to the set - rollupContract.getCommitteeAt.mockResolvedValue([...testCommittee, extraTestValidator].map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue([...testCommittee, extraTestValidator]); // Should use cached validators const { committee: midEpochCommittee } = await epochCache.getCommittee(); @@ -156,8 +161,8 @@ describe('EpochCache', () => { const epochStartTimestamp = l1GenesisTime + epochStartSlot * BigInt(slotDuration); const expectedCommittee = [EthAddress.fromString('0x000000000000000000000000000000000000BEEF')]; - const expectedSeed = 999n; - rollupContract.getCommitteeAt.mockResolvedValue(expectedCommittee.map(v => v.toString())); + const expectedSeed = Buffer32.fromBigInt(999n); + rollupContract.getCommitteeAt.mockResolvedValue(expectedCommittee); rollupContract.getSampleSeedAt.mockResolvedValue(expectedSeed); await epochCache.getCommittee(SlotNumber.fromBigInt(targetSlot)); @@ -178,7 +183,7 @@ describe('EpochCache', () => { jest.setSystemTime(Date.now() + Number(EPOCH_DURATION * SLOT_DURATION) * 1000); // Add another validator to the set - rollupContract.getCommitteeAt.mockResolvedValue([...testCommittee, extraTestValidator].map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue([...testCommittee, extraTestValidator]); // Should fetch new validator const { committee: nextEpochCommittee } = await epochCache.getCommittee(); @@ -201,7 +206,7 @@ describe('EpochCache', () => { // Seed the cache with 3 epochs worth of data for (let i = 0; i < 3; i++) { - rollupContract.getCommitteeAt.mockResolvedValue(committees[i].map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue(committees[i]); const { committee: actual } = await epochCache.getCommittee(SlotNumber(i * EPOCH_DURATION)); expect(actual).toEqual(committees[i]); expect(rollupContract.getCommitteeAt).toHaveBeenCalledTimes(i); // Epoch 0 is already initialized @@ -216,14 +221,14 @@ describe('EpochCache', () => { } // Requesting another epoch should cause the oldest to be purged - rollupContract.getCommitteeAt.mockResolvedValue(committees[3].map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue(committees[3]); const { committee: fourth } = await epochCache.getCommittee(SlotNumber(3 * EPOCH_DURATION)); expect(fourth).toEqual(committees[3]); expect(rollupContract.getCommitteeAt).toHaveBeenCalledTimes(1); rollupContract.getCommitteeAt.mockClear(); // So when going back to the first epoch, it should be re-requested from the contract - rollupContract.getCommitteeAt.mockResolvedValue(committees[0].map(v => v.toString())); + rollupContract.getCommitteeAt.mockResolvedValue(committees[0]); const { committee: first } = await epochCache.getCommittee(SlotNumber(0 * EPOCH_DURATION)); expect(first).toEqual(committees[0]); expect(rollupContract.getCommitteeAt).toHaveBeenCalledTimes(1); @@ -234,7 +239,7 @@ describe('EpochCache', () => { jest.setSystemTime(testTime); const initialValidators = times(100, i => EthAddress.fromNumber(i + 1)); const updatedValidators = times(100, i => EthAddress.fromNumber(i + 101)); - rollupContract.getAttesters.mockResolvedValueOnce(initialValidators.map(x => x.toString())); + rollupContract.getAttesters.mockResolvedValueOnce(initialValidators); const validators = await epochCache.getRegisteredValidators(); expect(validators.map(v => v.toString())).toEqual(initialValidators.map(v => v.toString())); expect(rollupContract.getAttesters).toHaveBeenCalledTimes(1); @@ -249,7 +254,7 @@ describe('EpochCache', () => { // Move forward in time past 60 seconds and we should query the contract again testTime = new Date(testTime.getTime() + 31 * 1000); jest.setSystemTime(testTime); - rollupContract.getAttesters.mockResolvedValueOnce(updatedValidators.map(x => x.toString())); + rollupContract.getAttesters.mockResolvedValueOnce(updatedValidators); const validators3 = await epochCache.getRegisteredValidators(); expect(validators3.map(v => v.toString())).toEqual(updatedValidators.map(v => v.toString())); expect(rollupContract.getAttesters).toHaveBeenCalledTimes(2); diff --git a/yarn-project/epoch-cache/src/epoch_cache.ts b/yarn-project/epoch-cache/src/epoch_cache.ts index 209d166eda32..381df15cc4ed 100644 --- a/yarn-project/epoch-cache/src/epoch_cache.ts +++ b/yarn-project/epoch-cache/src/epoch_cache.ts @@ -1,6 +1,7 @@ import { createEthereumChain } from '@aztec/ethereum/chain'; import { NoCommitteeError, RollupContract } from '@aztec/ethereum/contracts'; import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { type Logger, createLogger } from '@aztec/foundation/log'; import { DateProvider } from '@aztec/foundation/timer'; @@ -26,7 +27,7 @@ export type EpochAndSlot = { export type EpochCommitteeInfo = { committee: EthAddress[] | undefined; - seed: bigint; + seed: Buffer32; epoch: EpochNumber; }; @@ -61,7 +62,8 @@ export interface EpochCacheInterface { export class EpochCache implements EpochCacheInterface { // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections protected cache: Map = new Map(); - private allValidators: Set = new Set(); + // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections + private allValidators: Set = new Set(); private lastValidatorRefresh = 0; private readonly log: Logger = createLogger('epoch-cache'); @@ -210,7 +212,7 @@ export class EpochCache implements EpochCacheInterface { private async computeCommittee(when: { epoch: EpochNumber; ts: bigint }): Promise { const { ts, epoch } = when; - const [committeeHex, seed, l1Timestamp] = await Promise.all([ + const [committee, seed, l1Timestamp] = await Promise.all([ this.rollup.getCommitteeAt(ts), this.rollup.getSampleSeedAt(ts), this.rollup.client.getBlock({ includeTransactions: false }).then(b => b.timestamp), @@ -222,7 +224,6 @@ export class EpochCache implements EpochCacheInterface { `Cannot query committee for future epoch ${epoch} with timestamp ${ts} (current L1 time is ${l1Timestamp}). Check your Ethereum node is synced.`, ); } - const committee = committeeHex?.map((v: `0x${string}`) => EthAddress.fromString(v)); return { committee, seed, epoch }; } @@ -306,7 +307,7 @@ export class EpochCache implements EpochCacheInterface { return undefined; } - const proposerIndex = this.computeProposerIndex(slot, epoch, seed, BigInt(committee.length)); + const proposerIndex = this.computeProposerIndex(slot, epoch, seed.toBigInt(), BigInt(committee.length)); return committee[Number(proposerIndex)]; } @@ -320,7 +321,7 @@ export class EpochCache implements EpochCacheInterface { const proposerIndex = this.computeProposerIndex( slot, epochCommitteeInfo.epoch, - epochCommitteeInfo.seed, + epochCommitteeInfo.seed.toBigInt(), BigInt(epochCommitteeInfo.committee.length), ); @@ -354,6 +355,6 @@ export class EpochCache implements EpochCacheInterface { this.allValidators = new Set(currentSet); this.lastValidatorRefresh = this.dateProvider.now(); } - return Array.from(this.allValidators.keys().map(v => EthAddress.fromString(v))); + return Array.from(this.allValidators.keys()); } } diff --git a/yarn-project/ethereum/src/contracts/rollup.ts b/yarn-project/ethereum/src/contracts/rollup.ts index c28b2dc79b47..8ec3cd513806 100644 --- a/yarn-project/ethereum/src/contracts/rollup.ts +++ b/yarn-project/ethereum/src/contracts/rollup.ts @@ -1,4 +1,6 @@ import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; +import { Fr } from '@aztec/foundation/curves/bn254'; import { memoize } from '@aztec/foundation/decorators'; import { EthAddress } from '@aztec/foundation/eth-address'; import type { ViemSignature } from '@aztec/foundation/eth-signature'; @@ -90,6 +92,102 @@ export enum SlashingProposerType { Empire = 2, } +/** + * Status of a validator/attester in the staking system. + * Matches the Status enum in StakingLib.sol + */ +export enum AttesterStatus { + NONE = 0, + VALIDATING = 1, + ZOMBIE = 2, + EXITING = 3, +} + +/** + * Fee header data for a checkpoint + */ +export type FeeHeader = { + excessMana: bigint; + manaUsed: bigint; + feeAssetPriceNumerator: bigint; + congestionCost: bigint; + proverCost: bigint; +}; + +/** + * Checkpoint log data returned from the rollup contract + */ +export type CheckpointLog = { + archive: Fr; + headerHash: Buffer32; + blobCommitmentsHash: Buffer32; + attestationsHash: Buffer32; + payloadDigest: Buffer32; + slotNumber: SlotNumber; + feeHeader: FeeHeader; +}; + +/** + * L1 fee data (base fee and blob fee) + */ +export type L1FeeData = { + baseFee: bigint; + blobFee: bigint; +}; + +/** + * Reward configuration for the rollup + */ +export type RewardConfig = { + rewardDistributor: EthAddress; + sequencerBps: bigint; + booster: EthAddress; + checkpointReward: bigint; +}; + +/** + * Exit information for a validator + */ +export type Exit = { + withdrawalId: bigint; + amount: bigint; + exitableAt: bigint; + recipientOrWithdrawer: EthAddress; + isRecipient: boolean; + exists: boolean; +}; + +/** + * Attester configuration including public key + */ +export type AttesterConfig = { + publicKey: { + x: bigint; + y: bigint; + }; +}; + +/** + * Complete view of an attester's state + */ +export type AttesterView = { + status: AttesterStatus; + effectiveBalance: bigint; + exit: Exit; + config: AttesterConfig; +}; + +/** + * Return for a status call + */ +export type RollupStatusResponse = { + provenCheckpointNumber: CheckpointNumber; + provenArchive: Fr; + pendingCheckpointNumber: CheckpointNumber; + pendingArchive: Fr; + archiveOfMyCheckpoint: Fr; +}; + export class RollupContract { private readonly rollup: GetContractReturnType; @@ -131,8 +229,8 @@ export class RollupContract { this.rollup = getContract({ address, abi: RollupAbi, client }); } - getGSE() { - return this.rollup.read.getGSE(); + async getGSE(): Promise { + return EthAddress.fromString(await this.rollup.read.getGSE()); } public get address() { @@ -174,23 +272,23 @@ export class RollupContract { } @memoize - getL1StartBlock() { + getL1StartBlock(): Promise { return this.rollup.read.L1_BLOCK_AT_GENESIS(); } @memoize - getL1GenesisTime() { + getL1GenesisTime(): Promise { return this.rollup.read.getGenesisTime(); } @memoize - getProofSubmissionEpochs() { - return this.rollup.read.getProofSubmissionEpochs(); + async getProofSubmissionEpochs(): Promise { + return Number(await this.rollup.read.getProofSubmissionEpochs()); } @memoize - getEpochDuration() { - return this.rollup.read.getEpochDuration(); + async getEpochDuration(): Promise { + return Number(await this.rollup.read.getEpochDuration()); } @memoize @@ -199,68 +297,68 @@ export class RollupContract { } @memoize - getTargetCommitteeSize() { - return this.rollup.read.getTargetCommitteeSize(); + async getTargetCommitteeSize(): Promise { + return Number(await this.rollup.read.getTargetCommitteeSize()); } @memoize - getEjectionThreshold() { + getEjectionThreshold(): Promise { return this.rollup.read.getEjectionThreshold(); } @memoize - getLocalEjectionThreshold() { + getLocalEjectionThreshold(): Promise { return this.rollup.read.getLocalEjectionThreshold(); } @memoize - getLagInEpochsForValidatorSet() { - return this.rollup.read.getLagInEpochsForValidatorSet(); + async getLagInEpochsForValidatorSet(): Promise { + return Number(await this.rollup.read.getLagInEpochsForValidatorSet()); } @memoize - getLagInEpochsForRandao() { - return this.rollup.read.getLagInEpochsForRandao(); + async getLagInEpochsForRandao(): Promise { + return Number(await this.rollup.read.getLagInEpochsForRandao()); } @memoize - getActivationThreshold() { + getActivationThreshold(): Promise { return this.rollup.read.getActivationThreshold(); } @memoize - getExitDelay() { - return this.rollup.read.getExitDelay(); + async getExitDelay(): Promise { + return Number(await this.rollup.read.getExitDelay()); } @memoize - getManaTarget() { + getManaTarget(): Promise { return this.rollup.read.getManaTarget(); } @memoize - getProvingCostPerMana() { + getProvingCostPerMana(): Promise { return this.rollup.read.getProvingCostPerManaInEth(); } @memoize - getProvingCostPerManaInFeeAsset() { + getProvingCostPerManaInFeeAsset(): Promise { return this.rollup.read.getProvingCostPerManaInFeeAsset(); } @memoize - getManaLimit() { + getManaLimit(): Promise { return this.rollup.read.getManaLimit(); } @memoize - getVersion() { + getVersion(): Promise { return this.rollup.read.getVersion(); } @memoize - async getGenesisArchiveTreeRoot(): Promise<`0x${string}`> { - return await this.rollup.read.archiveAt([0n]); + async getGenesisArchiveTreeRoot(): Promise { + return Fr.fromString(await this.rollup.read.archiveAt([0n])); } /** @@ -292,27 +390,27 @@ export class RollupContract { }; } - getSlasherAddress() { - return this.rollup.read.getSlasher(); + async getSlasherAddress(): Promise { + return EthAddress.fromString(await this.rollup.read.getSlasher()); } /** * Returns a SlasherContract instance for interacting with the slasher contract. */ async getSlasherContract(): Promise { - const slasherAddress = EthAddress.fromString(await this.getSlasherAddress()); + const slasherAddress = await this.getSlasherAddress(); if (slasherAddress.isZero()) { return undefined; } return new SlasherContract(this.client, slasherAddress); } - getOwner() { - return this.rollup.read.owner(); + async getOwner(): Promise { + return EthAddress.fromString(await this.rollup.read.owner()); } - getActiveAttesterCount() { - return this.rollup.read.getActiveAttesterCount(); + async getActiveAttesterCount(): Promise { + return Number(await this.rollup.read.getActiveAttesterCount()); } public async getSlashingProposerAddress() { @@ -323,7 +421,7 @@ export class RollupContract { return await slasher.getProposer(); } - getCheckpointReward() { + getCheckpointReward(): Promise { return this.rollup.read.getCheckpointReward(); } @@ -339,15 +437,19 @@ export class RollupContract { return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot()); } - getL1FeesAt(timestamp: bigint) { - return this.rollup.read.getL1FeesAt([timestamp]); + async getL1FeesAt(timestamp: bigint): Promise { + const result = await this.rollup.read.getL1FeesAt([timestamp]); + return { + baseFee: result.baseFee, + blobFee: result.blobFee, + }; } - getFeeAssetPerEth() { + getFeeAssetPerEth(): Promise { return this.rollup.read.getFeeAssetPerEth(); } - async getCommitteeAt(timestamp: bigint): Promise { + async getCommitteeAt(timestamp: bigint): Promise { const { result } = await this.client .simulateContract({ address: this.address, @@ -362,22 +464,22 @@ export class RollupContract { throw e; }); - return result; + return result ? result.map(addr => EthAddress.fromString(addr)) : undefined; } - getSampleSeedAt(timestamp: bigint) { - return this.rollup.read.getSampleSeedAt([timestamp]); + async getSampleSeedAt(timestamp: bigint): Promise { + return Buffer32.fromBigInt(await this.rollup.read.getSampleSeedAt([timestamp])); } - getCurrentSampleSeed() { - return this.rollup.read.getCurrentSampleSeed(); + async getCurrentSampleSeed(): Promise { + return Buffer32.fromBigInt(await this.rollup.read.getCurrentSampleSeed()); } async getCurrentEpoch(): Promise { return EpochNumber.fromBigInt(await this.rollup.read.getCurrentEpoch()); } - async getCurrentEpochCommittee(): Promise { + async getCurrentEpochCommittee(): Promise { const { result } = await this.client .simulateContract({ address: this.address, @@ -392,10 +494,10 @@ export class RollupContract { throw e; }); - return result; + return result ? result.map(addr => EthAddress.fromString(addr)) : undefined; } - async getCurrentProposer() { + async getCurrentProposer(): Promise { const { result } = await this.client.simulateContract({ address: this.address, abi: RollupAbi, @@ -403,10 +505,10 @@ export class RollupContract { args: [], }); - return result; + return EthAddress.fromString(result); } - async getProposerAt(timestamp: bigint) { + async getProposerAt(timestamp: bigint): Promise { const { result } = await this.client.simulateContract({ address: this.address, abi: RollupAbi, @@ -414,11 +516,26 @@ export class RollupContract { args: [timestamp], }); - return result; + return EthAddress.fromString(result); } - getCheckpoint(checkpointNumber: CheckpointNumber) { - return this.rollup.read.getCheckpoint([BigInt(checkpointNumber)]); + async getCheckpoint(checkpointNumber: CheckpointNumber): Promise { + const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)]); + return { + archive: Fr.fromString(result.archive), + headerHash: Buffer32.fromString(result.headerHash), + blobCommitmentsHash: Buffer32.fromString(result.blobCommitmentsHash), + attestationsHash: Buffer32.fromString(result.attestationsHash), + payloadDigest: Buffer32.fromString(result.payloadDigest), + slotNumber: SlotNumber.fromBigInt(result.slotNumber), + feeHeader: { + excessMana: result.feeHeader.excessMana, + manaUsed: result.feeHeader.manaUsed, + feeAssetPriceNumerator: result.feeHeader.feeAssetPriceNumerator, + congestionCost: result.feeHeader.congestionCost, + proverCost: result.feeHeader.proverCost, + }, + }; } /** Returns the pending checkpoint from the rollup contract */ @@ -444,16 +561,16 @@ export class RollupContract { }; } - getTimestampForSlot(slot: SlotNumber) { + getTimestampForSlot(slot: SlotNumber): Promise { return this.rollup.read.getTimestampForSlot([BigInt(slot)]); } - getEntryQueueLength() { - return this.rollup.read.getEntryQueueLength(); + async getEntryQueueLength(): Promise { + return Number(await this.rollup.read.getEntryQueueLength()); } - getAvailableValidatorFlushes() { - return this.rollup.read.getAvailableValidatorFlushes(); + async getAvailableValidatorFlushes(): Promise { + return Number(await this.rollup.read.getAvailableValidatorFlushes()); } async getNextFlushableEpoch(): Promise { @@ -509,10 +626,11 @@ export class RollupContract { return EpochNumber.fromBigInt(await this.rollup.read.getEpochAtSlot([BigInt(slotNumber)])); } - getEpochProofPublicInputs( + async getEpochProofPublicInputs( args: readonly [bigint, bigint, EpochProofPublicInputArgs, readonly `0x${string}`[], `0x${string}`], - ) { - return this.rollup.read.getEpochProofPublicInputs(args); + ): Promise { + const result = await this.rollup.read.getEpochProofPublicInputs(args); + return result.map(Fr.fromString); } public async validateHeader( @@ -654,7 +772,7 @@ export class RollupContract { return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]); } - getManaBaseFeeAt(timestamp: bigint, inFeeAsset: boolean) { + getManaBaseFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise { return this.rollup.read.getManaBaseFeeAt([timestamp, inFeeAsset]); } @@ -662,77 +780,109 @@ export class RollupContract { return SlotNumber.fromBigInt(await this.rollup.read.getSlotAt([timestamp])); } - async status(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }) { + async status(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise { await checkBlockTag(options?.blockNumber, this.client); - return this.rollup.read.status([BigInt(checkpointNumber)], options); + const result = await this.rollup.read.status([BigInt(checkpointNumber)], options); + return { + provenCheckpointNumber: CheckpointNumber.fromBigInt(result[0]), + provenArchive: Fr.fromString(result[1]), + pendingCheckpointNumber: CheckpointNumber.fromBigInt(result[2]), + pendingArchive: Fr.fromString(result[3]), + archiveOfMyCheckpoint: Fr.fromString(result[4]), + }; } - async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }) { + async canPruneAtTime(timestamp: bigint, options?: { blockNumber?: bigint }): Promise { await checkBlockTag(options?.blockNumber, this.client); return this.rollup.read.canPruneAtTime([timestamp], options); } - archive() { - return this.rollup.read.archive(); + async archive(): Promise { + return Fr.fromString(await this.rollup.read.archive()); } - archiveAt(checkpointNumber: CheckpointNumber) { - return this.rollup.read.archiveAt([BigInt(checkpointNumber)]); + async archiveAt(checkpointNumber: CheckpointNumber): Promise { + return Fr.fromString(await this.rollup.read.archiveAt([BigInt(checkpointNumber)])); } - getSequencerRewards(address: Hex | EthAddress) { + getSequencerRewards(address: Hex | EthAddress): Promise { if (address instanceof EthAddress) { address = address.toString(); } return this.rollup.read.getSequencerRewards([address]); } - getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress) { + getSpecificProverRewardsForEpoch(epoch: bigint, prover: Hex | EthAddress): Promise { if (prover instanceof EthAddress) { prover = prover.toString(); } return this.rollup.read.getSpecificProverRewardsForEpoch([epoch, prover]); } - async getAttesters() { + async getAttesters(): Promise { const attesterSize = await this.getActiveAttesterCount(); const gse = new GSEContract(this.client, await this.getGSE()); const ts = (await this.client.getBlock()).timestamp; - const indices = Array.from({ length: Number(attesterSize) }, (_, i) => BigInt(i)); + const indices = Array.from({ length: attesterSize }, (_, i) => BigInt(i)); const chunks = chunk(indices, 1000); - return (await Promise.all(chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk)))).flat(); + const results = await Promise.all(chunks.map(chunk => gse.getAttestersFromIndicesAtTime(this.address, ts, chunk))); + return results.flat().map(addr => EthAddress.fromString(addr)); } - getAttesterView(address: Hex | EthAddress) { + async getAttesterView(address: Hex | EthAddress): Promise { if (address instanceof EthAddress) { address = address.toString(); } - return this.rollup.read.getAttesterView([address]); + const result = await this.rollup.read.getAttesterView([address]); + return { + status: result.status as AttesterStatus, + effectiveBalance: result.effectiveBalance, + exit: { + withdrawalId: result.exit.withdrawalId, + amount: result.exit.amount, + exitableAt: result.exit.exitableAt, + recipientOrWithdrawer: EthAddress.fromString(result.exit.recipientOrWithdrawer), + isRecipient: result.exit.isRecipient, + exists: result.exit.exists, + }, + config: { + publicKey: { + x: result.config.publicKey.x, + y: result.config.publicKey.y, + }, + }, + }; } - getStatus(address: Hex | EthAddress) { + async getStatus(address: Hex | EthAddress): Promise { if (address instanceof EthAddress) { address = address.toString(); } - return this.rollup.read.getStatus([address]); + return (await this.rollup.read.getStatus([address])) as AttesterStatus; } - getBlobCommitmentsHash(checkpointNumber: CheckpointNumber) { - return this.rollup.read.getBlobCommitmentsHash([BigInt(checkpointNumber)]); + async getBlobCommitmentsHash(checkpointNumber: CheckpointNumber): Promise { + return Buffer32.fromString(await this.rollup.read.getBlobCommitmentsHash([BigInt(checkpointNumber)])); } - getCurrentBlobCommitmentsHash() { - return this.rollup.read.getCurrentBlobCommitmentsHash(); + async getCurrentBlobCommitmentsHash(): Promise { + return Buffer32.fromString(await this.rollup.read.getCurrentBlobCommitmentsHash()); } - getStakingAsset() { - return this.rollup.read.getStakingAsset(); + async getStakingAsset(): Promise { + return EthAddress.fromString(await this.rollup.read.getStakingAsset()); } - getRewardConfig() { - return this.rollup.read.getRewardConfig(); + async getRewardConfig(): Promise { + const result = await this.rollup.read.getRewardConfig(); + return { + rewardDistributor: EthAddress.fromString(result.rewardDistributor), + sequencerBps: BigInt(result.sequencerBps), + booster: EthAddress.fromString(result.booster), + checkpointReward: result.checkpointReward, + }; } setupEpoch(l1TxUtils: L1TxUtils) { diff --git a/yarn-project/ethereum/src/contracts/tally_slashing_proposer.test.ts b/yarn-project/ethereum/src/contracts/tally_slashing_proposer.test.ts index 29c313d97372..25f54eabd054 100644 --- a/yarn-project/ethereum/src/contracts/tally_slashing_proposer.test.ts +++ b/yarn-project/ethereum/src/contracts/tally_slashing_proposer.test.ts @@ -189,7 +189,7 @@ describe('TallySlashingProposer', () => { await rollupCheatCodes.advanceToEpoch(EpochNumber(12)); const votes = bufferToHex(Buffer.alloc(testSlashingRoundSize / testConfig.aztecEpochDuration, 1)); const slot = await rollup.getSlotNumber(); - const proposer = EthAddress.fromString(await rollup.getCurrentProposer()); + const proposer = await rollup.getCurrentProposer(); const proposerIndex = validatorsAddresses.findIndex(addr => addr.equals(proposer)); expect(proposerIndex).toBeGreaterThanOrEqual(0); const proposerKey = validatorsPrivateKeys[proposerIndex]; diff --git a/yarn-project/ethereum/src/queries.ts b/yarn-project/ethereum/src/queries.ts index ed59a9c0ad60..68c3b5c2253c 100644 --- a/yarn-project/ethereum/src/queries.ts +++ b/yarn-project/ethereum/src/queries.ts @@ -97,7 +97,7 @@ export async function getL1ContractsConfig( ejectionThreshold, localEjectionThreshold, slashingQuorum: Number(slashingQuorum), - slashingRoundSizeInEpochs: Number(slashingRoundSize / aztecEpochDuration), + slashingRoundSizeInEpochs: Number(Number(slashingRoundSize) / aztecEpochDuration), slashingLifetimeInRounds: Number(slashingLifetimeInRounds), slashingExecutionDelayInRounds: Number(slashingExecutionDelayInRounds), slashingVetoer, @@ -105,7 +105,7 @@ export async function getL1ContractsConfig( manaTarget, provingCostPerMana: provingCostPerMana, rollupVersion: Number(rollupVersion), - genesisArchiveTreeRoot, + genesisArchiveTreeRoot: genesisArchiveTreeRoot.toString(), exitDelaySeconds: Number(exitDelay), slasherFlavor: slasherProposer?.type ?? 'tally', slashingOffsetInRounds: Number(slashingOffsetInRounds), diff --git a/yarn-project/ethereum/src/test/chain_monitor.ts b/yarn-project/ethereum/src/test/chain_monitor.ts index 10e817b30ac8..4b6c7b1bbca2 100644 --- a/yarn-project/ethereum/src/test/chain_monitor.ts +++ b/yarn-project/ethereum/src/test/chain_monitor.ts @@ -156,7 +156,7 @@ export class ChainMonitor extends EventEmitter { let committee: EthAddress[] | undefined; if (l2Epoch !== this.l2EpochNumber) { this.l2EpochNumber = l2Epoch; - committee = (await this.rollup.getCurrentEpochCommittee())?.map(addr => EthAddress.fromString(addr)); + committee = await this.rollup.getCurrentEpochCommittee(); this.emit('l2-epoch', { l2EpochNumber: l2Epoch, timestamp, committee }); msg += ` starting new epoch ${this.l2EpochNumber} `; } diff --git a/yarn-project/p2p/src/testbench/p2p_client_testbench_worker.ts b/yarn-project/p2p/src/testbench/p2p_client_testbench_worker.ts index 9e58ca2c7b0c..a1bf3ae5d982 100644 --- a/yarn-project/p2p/src/testbench/p2p_client_testbench_worker.ts +++ b/yarn-project/p2p/src/testbench/p2p_client_testbench_worker.ts @@ -6,6 +6,7 @@ import { MockL2BlockSource } from '@aztec/archiver/test'; import type { EpochCacheInterface } from '@aztec/epoch-cache'; import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { createLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; @@ -82,7 +83,7 @@ function mockAttestationPool(): AttestationPool { function mockEpochCache(): EpochCacheInterface { return { - getCommittee: () => Promise.resolve({ committee: [], seed: 1n, epoch: EpochNumber.ZERO }), + getCommittee: () => Promise.resolve({ committee: [], seed: Buffer32.fromBigInt(1n), epoch: EpochNumber.ZERO }), getProposerIndexEncoding: () => '0x' as `0x${string}`, getEpochAndSlotNow: () => ({ epoch: EpochNumber.ZERO, slot: SlotNumber.ZERO, ts: 0n }), computeProposerIndex: () => 0n, diff --git a/yarn-project/prover-node/src/prover-node-publisher.test.ts b/yarn-project/prover-node/src/prover-node-publisher.test.ts index 0d34e0d1a07a..bcd29fb68233 100644 --- a/yarn-project/prover-node/src/prover-node-publisher.test.ts +++ b/yarn-project/prover-node/src/prover-node-publisher.test.ts @@ -1,7 +1,8 @@ import { BatchedBlob } from '@aztec/blob-lib/types'; import type { RollupContract } from '@aztec/ethereum/contracts'; import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils'; -import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { SecretValue } from '@aztec/foundation/config'; import { randomBytes } from '@aztec/foundation/crypto/random'; import { Fr } from '@aztec/foundation/curves/bn254'; @@ -140,12 +141,12 @@ describe('prover-node-publisher', () => { // Return the requested checkpoint rollup.getCheckpoint.mockImplementation((checkpointNumber: CheckpointNumber) => Promise.resolve({ - archive: checkpoints[checkpointNumber - 1].endArchiveRoot.toString(), - attestationsHash: '0x', // unused, - payloadDigest: '0x', // unused, - headerHash: '0x', // unused, - blobCommitmentsHash: '0x', // unused, - slotNumber: 0n, // unused, + archive: checkpoints[checkpointNumber - 1].endArchiveRoot, + attestationsHash: Buffer32.fromString('0x00'), // unused, + payloadDigest: Buffer32.fromString('0x00'), // unused, + headerHash: Buffer32.fromString('0x00'), // unused, + blobCommitmentsHash: Buffer32.fromString('0x00'), // unused, + slotNumber: SlotNumber(0), // unused, feeHeader: { excessMana: 0n, // unused manaUsed: 0n, // unused @@ -172,7 +173,7 @@ describe('prover-node-publisher', () => { // Return our public inputs const totalFields = ourPublicInputs.toFields(); - rollup.getEpochProofPublicInputs.mockResolvedValue(totalFields.map(x => x.toString())); + rollup.getEpochProofPublicInputs.mockResolvedValue(totalFields); const result = await publisher .submitEpochProof({ @@ -209,12 +210,12 @@ describe('prover-node-publisher', () => { // Return the requested checkpoint rollup.getCheckpoint.mockImplementation((checkpointNumber: CheckpointNumber) => Promise.resolve({ - archive: checkpoints[checkpointNumber - 1].endArchiveRoot.toString(), - attestationsHash: '0x', // unused, - payloadDigest: '0x', // unused, - headerHash: '0x', // unused, - blobCommitmentsHash: '0x', // unused, - slotNumber: 0n, // unused, + archive: checkpoints[checkpointNumber - 1].endArchiveRoot, + attestationsHash: Buffer32.fromString('0x00'), // unused, + payloadDigest: Buffer32.fromString('0x00'), // unused, + headerHash: Buffer32.fromString('0x00'), // unused, + blobCommitmentsHash: Buffer32.fromString('0x00'), // unused, + slotNumber: SlotNumber(0), // unused, feeHeader: { excessMana: 0n, // unused manaUsed: 0n, // unused @@ -241,7 +242,7 @@ describe('prover-node-publisher', () => { // Return our public inputs const totalFields = ourPublicInputs.toFields(); - rollup.getEpochProofPublicInputs.mockResolvedValue(totalFields.map(x => x.toString())); + rollup.getEpochProofPublicInputs.mockResolvedValue(totalFields); jest.spyOn(l1Utils, 'getSenderBalance').mockResolvedValue(42n); jest.spyOn(l1Utils, 'getSenderAddress').mockReturnValue(EthAddress.random()); diff --git a/yarn-project/prover-node/src/prover-node-publisher.ts b/yarn-project/prover-node/src/prover-node-publisher.ts index c96d36ec9132..a961f418c3ef 100644 --- a/yarn-project/prover-node/src/prover-node-publisher.ts +++ b/yarn-project/prover-node/src/prover-node-publisher.ts @@ -172,17 +172,17 @@ export class ProverNodePublisher { // Check the archive for the immediate checkpoint before the epoch const checkpointLog = await this.rollupContract.getCheckpoint(CheckpointNumber(fromCheckpoint - 1)); - if (publicInputs.previousArchiveRoot.toString() !== checkpointLog.archive) { + if (!publicInputs.previousArchiveRoot.equals(checkpointLog.archive)) { throw new Error( - `Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${checkpointLog.archive}`, + `Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${checkpointLog.archive.toString()}`, ); } // Check the archive for the last checkpoint in the epoch const endCheckpointLog = await this.rollupContract.getCheckpoint(toCheckpoint); - if (publicInputs.endArchiveRoot.toString() !== endCheckpointLog.archive) { + if (!publicInputs.endArchiveRoot.equals(endCheckpointLog.archive)) { throw new Error( - `End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endCheckpointLog.archive}`, + `End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endCheckpointLog.archive.toString()}`, ); } @@ -200,7 +200,7 @@ export class ProverNodePublisher { ); const argsPublicInputs = [...publicInputs.toFields()]; - if (!areArraysEqual(rollupPublicInputs.map(Fr.fromHexString), argsPublicInputs, (a, b) => a.equals(b))) { + if (!areArraysEqual(rollupPublicInputs, argsPublicInputs, (a, b) => a.equals(b))) { const fmt = (inputs: Fr[] | readonly string[]) => inputs.map(x => x.toString()).join(', '); throw new Error( `Root rollup public inputs mismatch:\nRollup: ${fmt(rollupPublicInputs)}\nComputed:${fmt(argsPublicInputs)}`, diff --git a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts index 45167d4fe5b1..ca763604dc5b 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts @@ -71,7 +71,7 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface { const lastBlock = await this.rollupContract.getPendingCheckpoint(); const earliestTimestamp = await this.rollupContract.getTimestampForSlot( - SlotNumber.fromBigInt(lastBlock.slotNumber + 1n), + SlotNumber.fromBigInt(BigInt(lastBlock.slotNumber) + 1n), ); const nextEthTimestamp = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(this.ethereumSlotDuration)); const timestamp = earliestTimestamp > nextEthTimestamp ? earliestTimestamp : nextEthTimestamp; diff --git a/yarn-project/sequencer-client/src/publisher/sequencer-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/sequencer-publisher.test.ts index 3f071c469844..6c7b587120e0 100644 --- a/yarn-project/sequencer-client/src/publisher/sequencer-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/sequencer-publisher.test.ts @@ -12,6 +12,7 @@ import { type GasPrice, type L1TxUtilsConfig, defaultL1TxUtilsConfig } from '@az import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs'; import { FormattedViemError } from '@aztec/ethereum/utils'; import { BlockNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { sleep } from '@aztec/foundation/sleep'; import { TestDateProvider } from '@aztec/foundation/timer'; @@ -133,7 +134,7 @@ describe('SequencerPublisher', () => { const epochCache = mock(); epochCache.getEpochAndSlotNow.mockReturnValue({ epoch: EpochNumber(1), slot: SlotNumber(2), ts: 3n, now: 3n }); - epochCache.getCommittee.mockResolvedValue({ committee: [], seed: 1n, epoch: EpochNumber(1) }); + epochCache.getCommittee.mockResolvedValue({ committee: [], seed: Buffer32.fromBigInt(1n), epoch: EpochNumber(1) }); publisher = new SequencerPublisher(config, { blobClient, @@ -206,7 +207,7 @@ describe('SequencerPublisher', () => { const { govPayload, voteSig } = mockGovernancePayload(); - rollup.getProposerAt.mockResolvedValueOnce(mockForwarderAddress); + rollup.getProposerAt.mockResolvedValueOnce(EthAddress.fromString(mockForwarderAddress)); expect( await publisher.enqueueGovernanceCastSignal( diff --git a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts index b22acb78dd6d..13e410f30f12 100644 --- a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts +++ b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts @@ -568,7 +568,7 @@ export class CheckpointProposalJob { // Manipulate the attestations if we've been configured to do so if (this.config.injectFakeAttestation || this.config.shuffleAttestationOrdering) { const checkpoint = proposal.payload.header; - return this.manipulateAttestations(checkpoint, epoch, seed, committee, sorted); + return this.manipulateAttestations(checkpoint, epoch, seed.toBigInt(), committee, sorted); } return new CommitteeAttestationsAndSigners(sorted); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index e239752272a5..21938a71ff66 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -3,6 +3,7 @@ import { GENESIS_BLOCK_HEADER_HASH, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from ' import type { EpochCache, EpochCommitteeInfo } from '@aztec/epoch-cache'; import type { RollupContract } from '@aztec/ethereum/contracts'; import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { omit, times, timesParallel } from '@aztec/foundation/collection'; import { Secp256k1Signer } from '@aztec/foundation/crypto/secp256k1-signer'; import { Fr } from '@aztec/foundation/curves/bn254'; @@ -191,7 +192,11 @@ describe('sequencer', () => { ts: 1000n, now: 1000n, })); - epochCache.getCommittee.mockResolvedValue({ committee, seed: 1n, epoch: EpochNumber(1) } as EpochCommitteeInfo); + epochCache.getCommittee.mockResolvedValue({ + committee, + seed: Buffer32.fromBigInt(1n), + epoch: EpochNumber(1), + } as EpochCommitteeInfo); publisher = mockDeep(); publisher.epochCache = epochCache; @@ -807,7 +812,7 @@ describe('sequencer', () => { // Mock committee to include validator2 epochCache.getCommittee.mockResolvedValue({ committee: [validator2], - seed: 123n, + seed: Buffer32.fromBigInt(123n), epoch: EpochNumber(1), }); @@ -852,7 +857,7 @@ describe('sequencer', () => { // Mock committee without any of our validators epochCache.getCommittee.mockResolvedValue({ committee: [EthAddress.random()], - seed: 123n, + seed: Buffer32.fromBigInt(123n), epoch: EpochNumber(1), }); diff --git a/yarn-project/slasher/src/tally_slasher_client.test.ts b/yarn-project/slasher/src/tally_slasher_client.test.ts index 1fa4ab798d38..7a53bf9fcc2f 100644 --- a/yarn-project/slasher/src/tally_slasher_client.test.ts +++ b/yarn-project/slasher/src/tally_slasher_client.test.ts @@ -1,6 +1,7 @@ import type { EpochCache } from '@aztec/epoch-cache'; import { RollupContract, SlasherContract, TallySlashingProposerContract } from '@aztec/ethereum/contracts'; import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { times } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import { type Logger, createLogger } from '@aztec/foundation/log'; @@ -127,7 +128,9 @@ describe('TallySlasherClient', () => { // Create mock EpochCache mockEpochCache = mockDeep(); - mockEpochCache.getCommitteeForEpoch.mockImplementation(epoch => Promise.resolve({ committee, seed: 0n, epoch })); + mockEpochCache.getCommitteeForEpoch.mockImplementation(epoch => + Promise.resolve({ committee, seed: Buffer32.fromBigInt(0n), epoch }), + ); mockEpochCache.getL1Constants.mockReturnValue({ l1StartBlock: 0n, l1GenesisTime: 0n, @@ -256,7 +259,7 @@ describe('TallySlasherClient', () => { mockEpochCache.getCommitteeForEpoch.mockResolvedValueOnce({ committee: undefined, - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: EpochNumber(0), }); diff --git a/yarn-project/slasher/src/watchers/attestations_block_watcher.ts b/yarn-project/slasher/src/watchers/attestations_block_watcher.ts index 6d358655c55b..4a11f1b23505 100644 --- a/yarn-project/slasher/src/watchers/attestations_block_watcher.ts +++ b/yarn-project/slasher/src/watchers/attestations_block_watcher.ts @@ -1,5 +1,6 @@ import { EpochCache } from '@aztec/epoch-cache'; import { SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { merge, pick } from '@aztec/foundation/collection'; import { type Logger, createLogger } from '@aztec/foundation/log'; import { @@ -132,7 +133,12 @@ export class AttestationsBlockWatcher extends (EventEmitter as new () => Watcher const { reason, block } = validationResult; const blockNumber = block.blockNumber; const slot = block.slotNumber; - const proposer = this.epochCache.getProposerFromEpochCommittee(validationResult, slot); + const epochCommitteeInfo = { + committee: validationResult.committee, + seed: Buffer32.fromBigInt(validationResult.seed), + epoch: validationResult.epoch, + }; + const proposer = this.epochCache.getProposerFromEpochCommittee(epochCommitteeInfo, slot); if (!proposer) { this.log.warn(`No proposer found for block ${blockNumber} at slot ${slot}`); diff --git a/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts b/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts index 11f2045c5429..463bfcb4524c 100644 --- a/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts +++ b/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts @@ -1,5 +1,6 @@ import type { EpochCache } from '@aztec/epoch-cache'; import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { sleep } from '@aztec/foundation/sleep'; import { L2Block, type L2BlockSourceEventEmitter, L2BlockSourceEvents } from '@aztec/stdlib/block'; @@ -86,7 +87,7 @@ describe('EpochPruneWatcher', () => { ]; epochCache.getCommitteeForEpoch.mockResolvedValue({ committee: committee.map(EthAddress.fromString), - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: epochNumber, }); @@ -136,7 +137,7 @@ describe('EpochPruneWatcher', () => { ]; epochCache.getCommitteeForEpoch.mockResolvedValue({ committee: committee.map(EthAddress.fromString), - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: EpochNumber(1), }); @@ -192,7 +193,7 @@ describe('EpochPruneWatcher', () => { ]; epochCache.getCommitteeForEpoch.mockResolvedValue({ committee: committee.map(EthAddress.fromString), - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: EpochNumber(1), }); diff --git a/yarn-project/txe/src/state_machine/mock_epoch_cache.ts b/yarn-project/txe/src/state_machine/mock_epoch_cache.ts index 3eb38957c013..7633a9b000e2 100644 --- a/yarn-project/txe/src/state_machine/mock_epoch_cache.ts +++ b/yarn-project/txe/src/state_machine/mock_epoch_cache.ts @@ -1,5 +1,6 @@ import type { EpochAndSlot, EpochCacheInterface, EpochCommitteeInfo, SlotTag } from '@aztec/epoch-cache'; import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; /** @@ -10,7 +11,7 @@ export class MockEpochCache implements EpochCacheInterface { getCommittee(): Promise { return Promise.resolve({ committee: undefined, - seed: 0n, + seed: Buffer32.fromBigInt(0n), epoch: EpochNumber.ZERO, }); }