diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 6bf50ce7aee..89dd1a0a433 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -296,7 +296,7 @@ function makeL1ToL2MessageCancelledEvents(l1BlockNum: bigint, entryKeys: string[ */ function makeRollupTx(l2Block: L2Block) { const proof = `0x`; - const block = toHex(l2Block.encode()); + const block = toHex(l2Block.toBufferWithLogs()); const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', args: [proof, block] }); 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 30c6bbcea3a..ebbbd926748 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -104,7 +104,7 @@ async function getBlockFromCallData( }); if (functionName !== 'process') throw new Error(`Unexpected method called ${functionName}`); const [, l2BlockHex] = args! as [Hex, Hex]; - const block = L2Block.decode(Buffer.from(hexToBytes(l2BlockHex))); + const block = L2Block.fromBufferWithLogs(Buffer.from(hexToBytes(l2BlockHex))); if (BigInt(block.number) !== l2BlockNum) { throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${block.number}`); } diff --git a/yarn-project/aztec-sandbox/docker-compose.yml b/yarn-project/aztec-sandbox/docker-compose.yml index 608c7db3d03..5e66423bb29 100644 --- a/yarn-project/aztec-sandbox/docker-compose.yml +++ b/yarn-project/aztec-sandbox/docker-compose.yml @@ -29,9 +29,9 @@ services: image: otterscan/otterscan:develop # platform: linux/amd64 ports: - - "5100:80" + - '5100:80' container_name: otterscan environment: - # otterscan env var is hardcoded to support erigon client - # but it also works for anvil - - ERIGON_URL=http://127.0.0.1:${SANDBOX_ANVIL_PORT:-8545} \ No newline at end of file + # otterscan env var is hardcoded to support erigon client + # but it also works for anvil + - ERIGON_URL=http://127.0.0.1:${SANDBOX_ANVIL_PORT:-8545} diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 18cf976c69b..d3ada644a9a 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -133,7 +133,7 @@ export const setupL1Contracts = async ( /** * Sets up Private eXecution Environment (PXE). * @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated. - * @param aztecNode - The instance of an aztec node, if one is required + * @param aztecNode - An instance of Aztec Node. * @param firstPrivKey - The private key of the first account to be created. * @param logger - The logger to be used. * @param useLogSuffix - Whether to add a randomly generated suffix to the PXE debug logs. 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 adc9c01d7ae..5875d3af99a 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 @@ -315,11 +315,11 @@ describe('L1Publisher integration', () => { const expectedData = encodeFunctionData({ abi: RollupAbi, functionName: 'process', - args: [`0x${l2Proof.toString('hex')}`, `0x${block.encode().toString('hex')}`], + args: [`0x${l2Proof.toString('hex')}`, `0x${block.toBufferWithLogs().toString('hex')}`], }); expect(ethTx.input).toEqual(expectedData); - const decoderArgs = [`0x${block.encode().toString('hex')}`] as const; + 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(); @@ -387,11 +387,11 @@ describe('L1Publisher integration', () => { const expectedData = encodeFunctionData({ abi: RollupAbi, functionName: 'process', - args: [`0x${l2Proof.toString('hex')}`, `0x${block.encode().toString('hex')}`], + args: [`0x${l2Proof.toString('hex')}`, `0x${block.toBufferWithLogs().toString('hex')}`], }); expect(ethTx.input).toEqual(expectedData); - const decoderArgs = [`0x${block.encode().toString('hex')}`] as const; + 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(); diff --git a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts index f504121cd28..c632d4dde5b 100644 --- a/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts +++ b/yarn-project/foundation/src/json-rpc/client/json_rpc_client.ts @@ -57,9 +57,9 @@ export async function defaultFetch( } if (!resp.ok) { if (noRetry) { - throw new NoRetryError(responseJson.error.message); + throw new NoRetryError('(JSON-RPC PROPAGATED) ' + responseJson.error.message); } else { - throw new Error(responseJson.error.message); + throw new Error('(JSON-RPC PROPAGATED) ' + responseJson.error.message); } } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts index df3c48e550c..7ffe7a97a5f 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts @@ -16,7 +16,7 @@ describe('L1Publisher', () => { beforeEach(() => { l2Block = L2Block.random(42); - l2Inputs = l2Block.encode(); + l2Inputs = l2Block.toBufferWithLogs(); l2Proof = Buffer.alloc(0); txSender = mock(); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 4c608cdd352..1294f698555 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -124,7 +124,7 @@ export class L1Publisher implements L2BlockReceiver { */ public async processL2Block(l2BlockData: L2Block): Promise { const proof = Buffer.alloc(0); - const txData = { proof, inputs: l2BlockData.encode() }; + const txData = { proof, inputs: l2BlockData.toBufferWithLogs() }; while (!this.interrupted) { if (!(await this.checkFeeDistributorBalance())) { diff --git a/yarn-project/types/src/l2_block.test.ts b/yarn-project/types/src/l2_block.test.ts index 959849fed67..fb5c9a76e57 100644 --- a/yarn-project/types/src/l2_block.test.ts +++ b/yarn-project/types/src/l2_block.test.ts @@ -2,31 +2,26 @@ import { TxL2Logs } from './index.js'; import { L2Block } from './l2_block.js'; describe('L2Block', () => { - it('can encode a L2 block data object to buffer and back', () => { + it('can serialize an L2 block with logs to a buffer and back', () => { const block = L2Block.random(42); - const buffer = block.encode(); - const recovered = L2Block.decode(buffer); + const buffer = block.toBufferWithLogs(); + const recovered = L2Block.fromBufferWithLogs(buffer); expect(recovered).toEqual(block); }); - it('can encode a L2 block to string and back', () => { + it('can serialize an L2 block without logs to a buffer and back', () => { const block = L2Block.random(42); + block.newEncryptedLogs = undefined; + block.newUnencryptedLogs = undefined; + const serialised = block.toString(); const recovered = L2Block.fromString(serialised); expect(recovered).toEqual(block); }); - it('can serialise an L2 block to JSON and back', () => { - const block = L2Block.random(42); - const serialised = block.toJSON(); - const recovered = L2Block.fromJSON(serialised); - - expect(recovered).toEqual(block); - }); - // TS equivalent of `testComputeKernelLogsIterationWithoutLogs` in `Decoder.t.sol` it('correctly computes kernel logs hash when there are no logs', () => { // The following 2 values are copied from `testComputeKernelLogsIterationWithoutLogs` in `Decoder.t.sol` diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index b4f9ee005fc..166dec34f37 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -341,14 +341,12 @@ export class L2Block { } /** - * Encode the L2 block data into a buffer that can be pushed to the rollup contract. - * @returns The encoded L2 block data. + * Serializes a block without logs to a buffer. + * @remarks This is used when the block is being served via JSON-RPC because the logs are expected to be served + * separately. + * @returns A serialized L2 block without logs. */ - encode(): Buffer { - if (this.newEncryptedLogs === undefined || this.newUnencryptedLogs === undefined) { - throw new Error('newEncryptedLogs and newUnencryptedLogs must be defined when encoding L2BlockData'); - } - + toBuffer() { return serializeToBuffer( this.globalVariables, this.startPrivateDataTreeSnapshot, @@ -376,65 +374,41 @@ export class L2Block { this.newContractData, this.newL1ToL2Messages.length, this.newL1ToL2Messages, - this.newEncryptedLogs, - this.newUnencryptedLogs, ); } /** - * Alias for encode. - * @returns The encoded L2 block data. + * Serializes a block with logs to a buffer. + * @remarks This is used when the block is being submitted on L1. + * @returns A serialized L2 block with logs. */ - toBuffer() { - return this.encode(); - } + toBufferWithLogs(): Buffer { + if (this.newEncryptedLogs === undefined || this.newUnencryptedLogs === undefined) { + throw new Error( + `newEncryptedLogs and newUnencryptedLogs must be defined when encoding L2BlockData (block ${this.number})`, + ); + } - /** - * Encodes the block as a hex string - * @returns The encoded L2 block data as a hex string. - */ - toString() { - return this.toBuffer().toString(STRING_ENCODING); + return serializeToBuffer(this.toBuffer(), this.newEncryptedLogs, this.newUnencryptedLogs); } /** - * Encodes the block as a JSON object. - * @returns The L2 block encoded as a JSON object. + * Serializes a block without logs to a string. + * @remarks This is used when the block is being served via JSON-RPC because the logs are expected to be served + * separately. + * @returns A serialized L2 block without logs. */ - toJSON() { - return { - globalVariables: this.globalVariables.toJSON(), - startPrivateDataTreeSnapshot: this.startPrivateDataTreeSnapshot.toString(), - startNullifierTreeSnapshot: this.startNullifierTreeSnapshot.toString(), - startContractTreeSnapshot: this.startContractTreeSnapshot.toString(), - startPublicDataTreeRoot: this.startPublicDataTreeRoot.toString(), - startL1ToL2MessagesTreeSnapshot: this.startL1ToL2MessagesTreeSnapshot.toString(), - startHistoricBlocksTreeSnapshot: this.startHistoricBlocksTreeSnapshot.toString(), - endPrivateDataTreeSnapshot: this.endPrivateDataTreeSnapshot.toString(), - endNullifierTreeSnapshot: this.endNullifierTreeSnapshot.toString(), - endContractTreeSnapshot: this.endContractTreeSnapshot.toString(), - endPublicDataTreeRoot: this.endPublicDataTreeRoot.toString(), - endL1ToL2MessagesTreeSnapshot: this.endL1ToL2MessagesTreeSnapshot.toString(), - endHistoricBlocksTreeSnapshot: this.endHistoricBlocksTreeSnapshot.toString(), - newCommitments: this.newCommitments.map(c => c.toString()), - newNullifiers: this.newNullifiers.map(n => n.toString()), - newPublicDataWrites: this.newPublicDataWrites.map(p => p.toString()), - newL2ToL1Msgs: this.newL2ToL1Msgs.map(m => m.toString()), - newContracts: this.newContracts.map(c => c.toString()), - newContractData: this.newContractData.map(c => c.toString()), - newL1ToL2Messages: this.newL1ToL2Messages.map(m => m.toString()), - newEncryptedLogs: this.newEncryptedLogs?.toJSON() ?? null, - newUnencryptedLogs: this.newUnencryptedLogs?.toJSON() ?? null, - }; + toString(): string { + return this.toBuffer().toString(STRING_ENCODING); } /** - * Decode the L2 block data from a buffer. - * @param encoded - The encoded L2 block data. - * @returns The decoded L2 block data. + * Deserializes L2 block without logs from a buffer. + * @param buf - A serialized L2 block. + * @returns Deserialized L2 block. */ - static decode(encoded: Buffer | BufferReader) { - const reader = BufferReader.asReader(encoded); + static fromBuffer(buf: Buffer | BufferReader) { + const reader = BufferReader.asReader(buf); const globalVariables = reader.readObject(GlobalVariables); const number = Number(globalVariables.blockNumber.value); const startPrivateDataTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); @@ -457,8 +431,6 @@ export class L2Block { const newContractData = reader.readArray(newContracts.length, ContractData); // TODO(sean): could an optimisation of this be that it is encoded such that zeros are assumed const newL1ToL2Messages = reader.readVector(Fr); - const newEncryptedLogs = reader.readObject(L2BlockL2Logs); - const newUnencryptedLogs = reader.readObject(L2BlockL2Logs); return L2Block.fromFields({ number, @@ -482,70 +454,33 @@ export class L2Block { newContracts, newContractData, newL1ToL2Messages, - newEncryptedLogs, - newUnencryptedLogs, }); } /** - * Decode the L2 block from a string - * @param str - The serialised L2 block - * @returns An L2 block + * Deserializes L2 block with logs from a buffer. + * @param buf - A serialized L2 block. + * @returns Deserialized L2 block. */ - static fromString(str: string): L2Block { - return L2Block.decode(Buffer.from(str, STRING_ENCODING)); - } + static fromBufferWithLogs(buf: Buffer | BufferReader) { + const reader = BufferReader.asReader(buf); + const block = L2Block.fromBuffer(reader); + const newEncryptedLogs = reader.readObject(L2BlockL2Logs); + const newUnencryptedLogs = reader.readObject(L2BlockL2Logs); - static fromJSON(_obj: any): L2Block { - const globalVariables = GlobalVariables.fromJSON(_obj.globalVariables); - const number = Number(globalVariables.blockNumber.value); - const startPrivateDataTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.startPrivateDataTreeSnapshot); - const startNullifierTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.startNullifierTreeSnapshot); - const startContractTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.startContractTreeSnapshot); - const startPublicDataTreeRoot = Fr.fromString(_obj.startPublicDataTreeRoot); - const startL1ToL2MessagesTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.startL1ToL2MessagesTreeSnapshot); - const startHistoricBlocksTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.startHistoricBlocksTreeSnapshot); - const endPrivateDataTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.endPrivateDataTreeSnapshot); - const endNullifierTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.endNullifierTreeSnapshot); - const endContractTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.endContractTreeSnapshot); - const endPublicDataTreeRoot = Fr.fromString(_obj.endPublicDataTreeRoot); - const endL1ToL2MessagesTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.endL1ToL2MessagesTreeSnapshot); - const endHistoricBlocksTreeSnapshot = AppendOnlyTreeSnapshot.fromString(_obj.endHistoricBlocksTreeSnapshot); - const newCommitments = _obj.newCommitments.map((c: string) => Fr.fromString(c)); - const newNullifiers = _obj.newNullifiers.map((n: string) => Fr.fromString(n)); - const newPublicDataWrites = _obj.newPublicDataWrites.map((p: any) => PublicDataWrite.fromString(p)); - const newL2ToL1Msgs = _obj.newL2ToL1Msgs.map((m: string) => Fr.fromString(m)); - const newContracts = _obj.newContracts.map((c: string) => Fr.fromString(c)); - const newContractData = _obj.newContractData.map((c: any) => ContractData.fromString(c)); - const newL1ToL2Messages = _obj.newL1ToL2Messages.map((m: string) => Fr.fromString(m)); - const newEncryptedLogs = _obj.newEncryptedLogs ? L2BlockL2Logs.fromJSON(_obj.newEncryptedLogs) : undefined; - const newUnencryptedLogs = _obj.newUnencryptedLogs ? L2BlockL2Logs.fromJSON(_obj.newUnencryptedLogs) : undefined; + block.attachLogs(newEncryptedLogs, LogType.ENCRYPTED); + block.attachLogs(newUnencryptedLogs, LogType.UNENCRYPTED); - return L2Block.fromFields({ - number, - globalVariables, - startPrivateDataTreeSnapshot, - startNullifierTreeSnapshot, - startContractTreeSnapshot, - startPublicDataTreeRoot, - startL1ToL2MessagesTreeSnapshot, - startHistoricBlocksTreeSnapshot, - endPrivateDataTreeSnapshot, - endNullifierTreeSnapshot, - endContractTreeSnapshot, - endPublicDataTreeRoot, - endL1ToL2MessagesTreeSnapshot, - endHistoricBlocksTreeSnapshot, - newCommitments, - newNullifiers, - newPublicDataWrites, - newL2ToL1Msgs, - newContracts, - newContractData, - newL1ToL2Messages, - newEncryptedLogs, - newUnencryptedLogs, - }); + return block; + } + + /** + * Deserializes L2 block without logs from a buffer. + * @param str - A serialized L2 block. + * @returns Deserialized L2 block. + */ + static fromString(str: string): L2Block { + return L2Block.fromBuffer(Buffer.from(str, STRING_ENCODING)); } /** @@ -584,7 +519,7 @@ export class L2Block { */ public getBlockHash(): Buffer { if (!this.blockHash) { - this.blockHash = keccak(this.encode()); + this.blockHash = keccak(this.toBufferWithLogs()); } return this.blockHash; }