diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index d873da2de83..cacd3560a77 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -269,7 +269,7 @@ describe('Archiver', () => { function makeL2BlockProcessedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { return { blockNumber: l1BlockNum, - args: { blockNum: l2BlockNum }, + args: { blockNumber: l2BlockNum }, transactionHash: `0x${l2BlockNum}`, } as Log; } @@ -349,8 +349,10 @@ function makeL1ToL2MessageCancelledEvents(l1BlockNum: bigint, entryKeys: string[ * @returns A fake tx with calldata that corresponds to calling process in the Rollup contract. */ function makeRollupTx(l2Block: L2Block) { + const header = toHex(l2Block.header.toBuffer()); + const archive = toHex(l2Block.archive.toBuffer()); + const body = toHex(l2Block.bodyToBuffer()); const proof = `0x`; - const block = toHex(l2Block.toBufferWithLogs()); - const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', args: [proof, block] }); + const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', args: [header, archive, body, proof] }); return { input } as Transaction; } diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index ebdd62a3e98..0f0df679f3b 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -76,12 +76,12 @@ export async function processBlockLogs( ): Promise { const retrievedBlocks: L2Block[] = []; for (const log of logs) { - const blockNum = log.args.blockNum; + const blockNum = log.args.blockNumber; if (blockNum !== expectedL2BlockNumber) { throw new Error('Block number mismatch. Expected: ' + expectedL2BlockNumber + ' but got: ' + blockNum + '.'); } // TODO: Fetch blocks from calldata in parallel - const newBlock = await getBlockFromCallData(publicClient, log.transactionHash!, log.args.blockNum); + const newBlock = await getBlockFromCallData(publicClient, log.transactionHash!, log.args.blockNumber); newBlock.setL1BlockNumber(log.blockNumber!); retrievedBlocks.push(newBlock); expectedL2BlockNumber++; @@ -112,8 +112,14 @@ async function getBlockFromCallData( if (functionName !== 'process') { throw new Error(`Unexpected method called ${functionName}`); } - const [, l2BlockHex] = args! as [Hex, Hex]; - const block = L2Block.fromBufferWithLogs(Buffer.from(hexToBytes(l2BlockHex))); + // TODO(benesjan): This is brittle and should be handled inside the L2 Block. + const [headerHex, archiveHex, bodyHex] = args! as [Hex, Hex, Hex, Hex]; + const blockBuffer = Buffer.concat([ + Buffer.from(hexToBytes(headerHex)), + Buffer.from(hexToBytes(archiveHex)), + Buffer.from(hexToBytes(bodyHex)), + ]); + const block = L2Block.fromBufferWithLogs(blockBuffer); if (BigInt(block.number) !== l2BlockNum) { throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${block.number}`); } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 8d539e90785..e0ada8a4fca 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -263,19 +263,7 @@ export class L2Block { */ toBuffer() { return serializeToBuffer( - this.header.globalVariables, - // TODO(#3868) - AppendOnlyTreeSnapshot.empty(), // this.startNoteHashTreeSnapshot, - AppendOnlyTreeSnapshot.empty(), // this.startNullifierTreeSnapshot, - AppendOnlyTreeSnapshot.empty(), // this.startContractTreeSnapshot, - AppendOnlyTreeSnapshot.empty(), // this.startPublicDataTreeSnapshot, - AppendOnlyTreeSnapshot.empty(), // this.startL1ToL2MessageTreeSnapshot, - this.header.lastArchive, - this.header.state.partial.noteHashTree, - this.header.state.partial.nullifierTree, - this.header.state.partial.contractTree, - this.header.state.partial.publicDataTree, - this.header.state.l1ToL2MessageTree, + this.header, this.archive, this.newCommitments.length, this.newCommitments, @@ -308,13 +296,6 @@ export class L2Block { return serializeToBuffer(this.toBuffer(), this.newEncryptedLogs, this.newUnencryptedLogs); } - headerAndArchiveToBuffer() { - return serializeToBuffer( - this.header, - this.archive, - ); - } - bodyToBuffer(): Buffer { if (this.newEncryptedLogs === undefined || this.newUnencryptedLogs === undefined) { throw new Error( @@ -335,7 +316,7 @@ export class L2Block { this.newContracts, this.newContractData, this.newL1ToL2Messages.length, - this.newL1ToL2Messages, + this.newL1ToL2Messages, this.newEncryptedLogs, this.newUnencryptedLogs ); } @@ -357,20 +338,8 @@ export class L2Block { */ static fromBuffer(buf: Buffer | BufferReader, blockHash?: Buffer) { const reader = BufferReader.asReader(buf); - const globalVariables = reader.readObject(GlobalVariables); - // TODO(#3938): update the encoding here - reader.readObject(AppendOnlyTreeSnapshot); // startNoteHashTreeSnapshot - reader.readObject(AppendOnlyTreeSnapshot); // startNullifierTreeSnapshot - reader.readObject(AppendOnlyTreeSnapshot); // startContractTreeSnapshot - reader.readObject(AppendOnlyTreeSnapshot); // startPublicDataTreeSnapshot - reader.readObject(AppendOnlyTreeSnapshot); // startL1ToL2MessageTreeSnapshot - const startArchiveSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endNoteHashTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endNullifierTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endContractTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endPublicDataTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endL1ToL2MessageTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endArchiveSnapshot = reader.readObject(AppendOnlyTreeSnapshot); + const header = reader.readObject(Header); + const archive = reader.readObject(AppendOnlyTreeSnapshot); const newCommitments = reader.readVector(Fr); const newNullifiers = reader.readVector(Fr); const newPublicDataWrites = reader.readVector(PublicDataWrite); @@ -380,19 +349,9 @@ export class L2Block { // TODO(sean): could an optimization of this be that it is encoded such that zeros are assumed const newL1ToL2Messages = reader.readVector(Fr); - const partial = new PartialStateReference( - endNoteHashTreeSnapshot, - endNullifierTreeSnapshot, - endContractTreeSnapshot, - endPublicDataTreeSnapshot, - ); - const state = new StateReference(endL1ToL2MessageTreeSnapshot, partial); - // TODO(#3938): populate bodyHash - const header = new Header(startArchiveSnapshot, [Fr.ZERO, Fr.ZERO], state, globalVariables); - return L2Block.fromFields( { - archive: endArchiveSnapshot, + archive, header, newCommitments, newNullifiers, @@ -565,6 +524,7 @@ export class L2Block { * and inside the circuit, it is part of the public inputs. * @returns The calldata hash. */ + // TODO(benesjan): Update to getBodyHash getCalldataHash() { if (this.newEncryptedLogs === undefined) { throw new Error('Encrypted logs has to be attached before calling "getCalldataHash"'); diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index a179716361c..879279a2097 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -280,7 +280,7 @@ describe('L1Publisher integration', () => { }; it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { - const stateInRollup_ = await rollup.read.rollupStateHash(); + const stateInRollup_ = await rollup.read.archive(); expect(hexStringToBuffer(stateInRollup_.toString())).toEqual(Buffer.alloc(32, 0)); const blockNumber = await publicClient.getBlockNumber(); @@ -362,7 +362,7 @@ describe('L1Publisher integration', () => { fromBlock: blockNumber + 1n, }); expect(logs).toHaveLength(i + 1); - expect(logs[i].args.blockNum).toEqual(BigInt(i + 1)); + expect(logs[i].args.blockNumber).toEqual(BigInt(i + 1)); const ethTx = await publicClient.getTransaction({ hash: logs[i].transactionHash!, @@ -371,14 +371,19 @@ describe('L1Publisher integration', () => { const expectedData = encodeFunctionData({ abi: RollupAbi, functionName: 'process', - args: [`0x${l2Proof.toString('hex')}`, `0x${block.toBufferWithLogs().toString('hex')}`], + args: [ + `0x${block.header.toBuffer().toString('hex')}`, + `0x${block.archive.toBuffer().toString('hex')}`, + `0x${block.bodyToBuffer().toString('hex')}`, + `0x${l2Proof.toString('hex')}`, + ], }); expect(ethTx.input).toEqual(expectedData); const decoderArgs = [`0x${block.toBufferWithLogs().toString('hex')}`] as const; const decodedHashes = await decoderHelper.read.computeDiffRootAndMessagesHash(decoderArgs); const decodedRes = await decoderHelper.read.decode(decoderArgs); - const stateInRollup = await rollup.read.rollupStateHash(); + const stateInRollup = await rollup.read.archive(); expect(block.number).toEqual(Number(decodedRes[0])); expect(block.getStartStateHash()).toEqual(hexStringToBuffer(decodedRes[1].toString())); @@ -403,7 +408,7 @@ describe('L1Publisher integration', () => { }, 360_000); it(`Build ${numberOfConsecutiveBlocks} blocks of 4 empty txs building on each other`, async () => { - const stateInRollup_ = await rollup.read.rollupStateHash(); + const stateInRollup_ = await rollup.read.archive(); expect(hexStringToBuffer(stateInRollup_.toString())).toEqual(Buffer.alloc(32, 0)); const blockNumber = await publicClient.getBlockNumber(); @@ -438,7 +443,7 @@ describe('L1Publisher integration', () => { fromBlock: blockNumber + 1n, }); expect(logs).toHaveLength(i + 1); - expect(logs[i].args.blockNum).toEqual(BigInt(i + 1)); + expect(logs[i].args.blockNumber).toEqual(BigInt(i + 1)); const ethTx = await publicClient.getTransaction({ hash: logs[i].transactionHash!, @@ -447,14 +452,19 @@ describe('L1Publisher integration', () => { const expectedData = encodeFunctionData({ abi: RollupAbi, functionName: 'process', - args: [`0x${l2Proof.toString('hex')}`, `0x${block.toBufferWithLogs().toString('hex')}`], + args: [ + `0x${block.header.toBuffer().toString('hex')}`, + `0x${block.archive.toBuffer().toString('hex')}`, + `0x${block.bodyToBuffer().toString('hex')}`, + `0x${l2Proof.toString('hex')}`, + ], }); expect(ethTx.input).toEqual(expectedData); const decoderArgs = [`0x${block.toBufferWithLogs().toString('hex')}`] as const; const decodedHashes = await decoderHelper.read.computeDiffRootAndMessagesHash(decoderArgs); const decodedRes = await decoderHelper.read.decode(decoderArgs); - const stateInRollup = await rollup.read.rollupStateHash(); + const stateInRollup = await rollup.read.archive(); expect(block.number).toEqual(Number(decodedRes[0])); expect(block.getStartStateHash()).toEqual(hexStringToBuffer(decodedRes[1].toString())); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 5a390b36fa6..a0e03bb5afc 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -250,11 +250,7 @@ describe('sequencer/solo_block_builder', () => { newUnencryptedLogs, }); - const callDataHash = l2Block.getCalldataHash(); - const high = Fr.fromBuffer(callDataHash.slice(0, 16)); - const low = Fr.fromBuffer(callDataHash.slice(16, 32)); - - rootRollupOutput.header.bodyHash = [high, low]; + rootRollupOutput.header.bodyHash = l2Block.getCalldataHash(); return txs; }; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index ee8d709fee0..fd74a090816 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -144,11 +144,12 @@ export class SoloBlockBuilder implements BlockBuilder { newUnencryptedLogs, }); + // TODO: update naming here if (!l2Block.getCalldataHash().equals(circuitsOutput.header.bodyHash)) { throw new Error( - `Calldata hash mismatch, ${l2Block.getCalldataHash().toString('hex')} == ${circuitsOutput - .sha256CalldataHash() - .toString('hex')} `, + `Calldata hash mismatch, ${l2Block + .getCalldataHash() + .toString('hex')} == ${circuitsOutput.header.bodyHash.toString('hex')} `, ); } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index db6b3cdfa24..efa87c38542 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -82,17 +82,17 @@ export interface L1PublisherTxSender { } /** - * Encoded block data and proof ready to be pushed to the L1 contract. + * Encoded block and proof ready to be pushed to the L1 contract. */ export type L1ProcessArgs = { - /** - * Root rollup proof for an L1 block. - */ + /** The L2 block header. */ + header: Buffer; + /** A snapshot (root and next available leaf index) of the archive tree after the L2 block is applied. */ + archive: Buffer; + /** L2 block body. */ + body: Buffer; + /** Root rollup proof of the L2 block. */ proof: Buffer; - /** - * Serialized L2Block data. - */ - inputs: Buffer; }; /** @@ -129,9 +129,12 @@ export class L1Publisher implements L2BlockReceiver { * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise. */ public async publishL2Block(block: L2Block): Promise { - const proof = Buffer.alloc(0); - - const txData = { proof, inputs: block.toBufferWithLogs() }; + const txData = { + header: block.header.toBuffer(), + archive: block.archive.toBuffer(), + body: block.bodyToBuffer(), + proof: Buffer.alloc(0), + }; const startStateHash = block.getStartStateHash(); while (!this.interrupted) { @@ -243,6 +246,7 @@ export class L1Publisher implements L2BlockReceiver { * @param startStateHash - The start state hash of the block we wish to publish. * @returns Boolean indicating if the hashes are equal. */ + // TODO(benesjan): rename this private async checkStartStateHash(startStateHash: Buffer): Promise { const fromChain = await this.txSender.getCurrentStateHash(); const areSame = startStateHash.equals(fromChain); diff --git a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts index 89a3037ec32..e301b6d0b63 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -76,7 +76,7 @@ export class ViemTxSender implements L1PublisherTxSender { } async getCurrentStateHash(): Promise { - const stateHash = await this.rollupContract.read.rollupStateHash(); + const stateHash = await this.rollupContract.read.archive(); return Buffer.from(stateHash.replace('0x', ''), 'hex'); } @@ -122,7 +122,12 @@ export class ViemTxSender implements L1PublisherTxSender { * @returns The hash of the mined tx. */ async sendProcessTx(encodedData: ProcessTxArgs): Promise { - const args = [`0x${encodedData.proof.toString('hex')}`, `0x${encodedData.inputs.toString('hex')}`] as const; + const args = [ + `0x${encodedData.header.toString('hex')}`, + `0x${encodedData.archive.toString('hex')}`, + `0x${encodedData.body.toString('hex')}`, + `0x${encodedData.proof.toString('hex')}`, + ] as const; const gas = await this.rollupContract.estimateGas.process(args, { account: this.account,