From 457669e81d654c0b77fcf2c7bf98eb335f0914ff Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:57:29 +0100 Subject: [PATCH] fix: Pad L1 to L2 messages upon retrieval from L1 (#2879) This PR fixes a bug where L1 to L2 message padding is lost upon retrieval from L1. # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [ ] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [ ] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [ ] Every change is related to the PR description. - [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to relevant issues (if any exist). --- yarn-project/archiver/package.json | 1 + .../archiver/src/archiver/archiver.test.ts | 56 +++++++++++++++++++ .../archiver/src/archiver/archiver.ts | 11 ++-- yarn-project/yarn.lock | 1 + 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/yarn-project/archiver/package.json b/yarn-project/archiver/package.json index 48867bed693..c2eef3a26ce 100644 --- a/yarn-project/archiver/package.json +++ b/yarn-project/archiver/package.json @@ -57,6 +57,7 @@ "concurrently": "^8.0.1", "jest": "^29.5.0", "jest-mock-extended": "^3.0.4", + "lodash.times": "^4.3.2", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "^5.0.4" diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 5b19fbc742d..f05129af94f 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,3 +1,4 @@ +import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -6,6 +7,7 @@ import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-art import { ExtendedContractData, L2Block, L2BlockL2Logs, LogType } from '@aztec/types'; import { MockProxy, mock } from 'jest-mock-extended'; +import times from 'lodash.times'; import { Chain, HttpTransport, Log, PublicClient, Transaction, encodeFunctionData, toHex } from 'viem'; import { Archiver } from './archiver.js'; @@ -204,6 +206,60 @@ describe('Archiver', () => { await archiver.stop(); }, 10_000); + + it('pads L1 to L2 messages', async () => { + const NUM_RECEIVED_L1_MESSAGES = 2; + + const archiver = new Archiver( + publicClient, + EthAddress.fromString(rollupAddress), + EthAddress.fromString(inboxAddress), + EthAddress.fromString(registryAddress), + EthAddress.fromString(contractDeploymentEmitterAddress), + 0, + archiverStore, + 1000, + ); + + let latestBlockNum = await archiver.getBlockNumber(); + expect(latestBlockNum).toEqual(0); + + const block = L2Block.random(1, 4, 1, 2, 4, 6); + block.newL1ToL2Messages = times(2, Fr.random); + const rollupTx = makeRollupTx(block); + + publicClient.getBlockNumber.mockResolvedValueOnce(2500n); + // logs should be created in order of how archiver syncs. + publicClient.getLogs + .mockResolvedValueOnce( + makeL1ToL2MessageAddedEvents( + 100n, + block.newL1ToL2Messages.map(x => x.toString(true)), + ), + ) + .mockResolvedValueOnce([]) + .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) + .mockResolvedValue([]); + publicClient.getTransaction.mockResolvedValueOnce(rollupTx); + + await archiver.start(false); + + // Wait until block 1 is processed. If this won't happen the test will fail with timeout. + while ((await archiver.getBlockNumber()) !== 1) { + await sleep(100); + } + + latestBlockNum = await archiver.getBlockNumber(); + expect(latestBlockNum).toEqual(1); + + const expectedL1Messages = block.newL1ToL2Messages + .concat(times(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP - NUM_RECEIVED_L1_MESSAGES, () => Fr.ZERO)) + .map(x => x.value); + const receivedBlock = await archiver.getBlock(1); + expect(receivedBlock?.newL1ToL2Messages.map(x => x.value)).toEqual(expectedL1Messages); + + await archiver.stop(); + }, 10_000); }); /** diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index fcf397b63ba..1c4b8be8816 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,6 +1,7 @@ -import { FunctionSelector } from '@aztec/circuits.js'; +import { FunctionSelector, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { padArrayEnd } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; @@ -281,9 +282,11 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource // store retrieved L2 blocks after removing new logs information. // remove logs to serve "lightweight" block information. Logs can be fetched separately if needed. await this.store.addBlocks( - retrievedBlocks.retrievedData.map(block => - L2Block.fromFields(omit(block, ['newEncryptedLogs', 'newUnencryptedLogs']), block.getBlockHash()), - ), + retrievedBlocks.retrievedData.map(block => { + // Ensure we pad the L1 to L2 message array to the full size before storing. + block.newL1ToL2Messages = padArrayEnd(block.newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); + return L2Block.fromFields(omit(block, ['newEncryptedLogs', 'newUnencryptedLogs']), block.getBlockHash()); + }), ); // set the L1 block for the next search diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index b7422b89efe..da4782e27d4 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -107,6 +107,7 @@ __metadata: jest: ^29.5.0 jest-mock-extended: ^3.0.4 lodash.omit: ^4.5.0 + lodash.times: ^4.3.2 ts-jest: ^29.1.0 ts-node: ^10.9.1 tsc-watch: ^6.0.0