diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 91ae9d578c2..3d15de3fbbb 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -1,4 +1,4 @@ -import { Body, type InBlock, L2Block, type TxEffect, type TxHash, TxReceipt } from '@aztec/circuit-types'; +import { Body, type InBlock, L2Block, L2BlockHash, type TxEffect, type TxHash, TxReceipt } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, type AztecAddress, Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { type AztecKVStore, type AztecMap, type AztecSingleton, type Range } from '@aztec/kv-store'; @@ -211,7 +211,7 @@ export class BlockStore { TxReceipt.statusFromRevertCode(tx.revertCode), '', tx.transactionFee.toBigInt(), - block.data.hash().toBuffer(), + L2BlockHash.fromField(block.data.hash()), block.data.number, ); } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts index 7f34e559ccc..df606d16fab 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts @@ -9,6 +9,7 @@ import { type InBlock, type InboxLeaf, type L2Block, + L2BlockHash, type L2BlockL2Logs, type LogFilter, LogId, @@ -450,7 +451,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { TxReceipt.statusFromRevertCode(txEffect.revertCode), '', txEffect.transactionFee.toBigInt(), - block.data.hash().toBuffer(), + L2BlockHash.fromField(block.data.hash()), block.data.number, ), ); diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index ae7f86f8c20..24112863fc1 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -1,3 +1,4 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { createDebugLogger } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; @@ -25,7 +26,7 @@ async function main() { const config = getArchiverConfigFromEnv(); const { l1RpcUrl: rpcUrl, l1Contracts } = config; - log.info(`Starting archiver in main(): ${JSON.stringify(config)}`); + log.info(`Starting archiver in main(): ${jsonStringify(config)}`); const publicClient = createPublicClient({ chain: localhost, transport: http(rpcUrl), diff --git a/yarn-project/archiver/src/test/mock_l2_block_source.ts b/yarn-project/archiver/src/test/mock_l2_block_source.ts index 2ab843cb42a..cbd2e3363d3 100644 --- a/yarn-project/archiver/src/test/mock_l2_block_source.ts +++ b/yarn-project/archiver/src/test/mock_l2_block_source.ts @@ -1,4 +1,12 @@ -import { L2Block, type L2BlockSource, type L2Tips, type TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; +import { + L2Block, + L2BlockHash, + type L2BlockSource, + type L2Tips, + type TxHash, + TxReceipt, + TxStatus, +} from '@aztec/circuit-types'; import { EthAddress, type Header } from '@aztec/circuits.js'; import { DefaultL1ContractsConfig } from '@aztec/ethereum'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -144,7 +152,7 @@ export class MockL2BlockSource implements L2BlockSource { TxStatus.SUCCESS, '', txEffect.transactionFee.toBigInt(), - block.hash().toBuffer(), + L2BlockHash.fromField(block.hash()), block.number, ), ); diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 29bbf20e274..666bd426440 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -143,12 +143,14 @@ describe('aztec node', () => { maxBlockNumber: new MaxBlockNumber(true, new Fr(1)), getSize: () => 1, toBuffer: () => Fr.ZERO.toBuffer(), + toString: () => Fr.ZERO.toString(), }; validMaxBlockNumberMetadata.data.rollupValidationRequests = { maxBlockNumber: new MaxBlockNumber(true, new Fr(5)), getSize: () => 1, toBuffer: () => Fr.ZERO.toBuffer(), + toString: () => Fr.ZERO.toString(), }; lastBlockNumber = 3; diff --git a/yarn-project/aztec.js/src/rpc_clients/node/index.ts b/yarn-project/aztec.js/src/rpc_clients/node/index.ts index 9cf3195f334..0db9d0edf35 100644 --- a/yarn-project/aztec.js/src/rpc_clients/node/index.ts +++ b/yarn-project/aztec.js/src/rpc_clients/node/index.ts @@ -1,8 +1,10 @@ import { type PXE } from '@aztec/circuit-types'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { type DebugLogger } from '@aztec/foundation/log'; import { NoRetryError, makeBackoff, retry } from '@aztec/foundation/retry'; -import axios, { type AxiosError, type AxiosResponse } from 'axios'; +import { Axios, type AxiosError } from 'axios'; +import { inspect } from 'util'; import { createPXEClient } from '../pxe_client.js'; @@ -15,34 +17,19 @@ import { createPXEClient } from '../pxe_client.js'; * @returns The response data. */ async function axiosFetch(host: string, rpcMethod: string, body: any, useApiEndpoints: boolean) { - let resp: AxiosResponse; - if (useApiEndpoints) { - resp = await axios - .post(`${host}/${rpcMethod}`, body, { - headers: { 'content-type': 'application/json' }, - }) - .catch((error: AxiosError) => { - if (error.response) { - return error.response; - } - throw error; - }); - } else { - resp = await axios - .post( - host, - { ...body, method: rpcMethod }, - { - headers: { 'content-type': 'application/json' }, - }, - ) - .catch((error: AxiosError) => { - if (error.response) { - return error.response; - } - throw error; - }); - } + const request = new Axios({ + headers: { 'content-type': 'application/json' }, + transformRequest: [(data: any) => jsonStringify(data)], + transformResponse: [(data: any) => JSON.parse(data)], + }); + const [url, content] = useApiEndpoints ? [`${host}/${rpcMethod}`, body] : [host, { ...body, method: rpcMethod }]; + const resp = await request.post(url, content).catch((error: AxiosError) => { + if (error.response) { + return error.response; + } + const errorMessage = `Error fetching from host ${host} with method ${rpcMethod}: ${inspect(error)}`; + throw new Error(errorMessage); + }); const isOK = resp.status >= 200 && resp.status < 300; if (isOK) { diff --git a/yarn-project/aztec/src/examples/util.ts b/yarn-project/aztec/src/examples/util.ts index 0d38e5beeef..2ba7c3e6e93 100644 --- a/yarn-project/aztec/src/examples/util.ts +++ b/yarn-project/aztec/src/examples/util.ts @@ -1,4 +1,5 @@ import { EthAddress } from '@aztec/aztec.js'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import type { Abi, Narrow } from 'abitype'; import { type Account, type Chain, type Hex, type HttpTransport, type PublicClient, type WalletClient } from 'viem'; @@ -28,7 +29,7 @@ export async function deployL1Contract( const receipt = await publicClient.waitForTransactionReceipt({ hash }); const contractAddress = receipt.contractAddress; if (!contractAddress) { - throw new Error(`No contract address found in receipt: ${JSON.stringify(receipt)}`); + throw new Error(`No contract address found in receipt: ${jsonStringify(receipt)}`); } return EthAddress.fromString(receipt.contractAddress!); diff --git a/yarn-project/bot/src/factory.ts b/yarn-project/bot/src/factory.ts index b05e840fdb2..2a72653005a 100644 --- a/yarn-project/bot/src/factory.ts +++ b/yarn-project/bot/src/factory.ts @@ -70,7 +70,7 @@ export class BotFactory { this.log.info(`Initializing account at ${account.getAddress().toString()}`); const sentTx = account.deploy(); const txHash = await sentTx.getTxHash(); - this.log.info(`Sent tx with hash ${txHash.to0xString()}`); + this.log.info(`Sent tx with hash ${txHash.toString()}`); if (this.config.flushSetupTransactions) { this.log.verbose('Flushing transactions'); await this.node!.flushTxs(); @@ -117,7 +117,7 @@ export class BotFactory { this.log.info(`Deploying token contract at ${address.toString()}`); const sentTx = deploy.send(deployOpts); const txHash = await sentTx.getTxHash(); - this.log.info(`Sent tx with hash ${txHash.to0xString()}`); + this.log.info(`Sent tx with hash ${txHash.toString()}`); if (this.config.flushSetupTransactions) { this.log.verbose('Flushing transactions'); await this.node!.flushTxs(); @@ -164,7 +164,7 @@ export class BotFactory { } const sentTx = new BatchCall(token.wallet, calls).send(); const txHash = await sentTx.getTxHash(); - this.log.info(`Sent tx with hash ${txHash.to0xString()}`); + this.log.info(`Sent tx with hash ${txHash.toString()}`); if (this.config.flushSetupTransactions) { this.log.verbose('Flushing transactions'); await this.node!.flushTxs(); diff --git a/yarn-project/circuit-types/src/auth_witness.ts b/yarn-project/circuit-types/src/auth_witness.ts index f661817edbd..ea135a2d5dd 100644 --- a/yarn-project/circuit-types/src/auth_witness.ts +++ b/yarn-project/circuit-types/src/auth_witness.ts @@ -2,6 +2,7 @@ import { Vector } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { hexSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; /** * An authentication witness. Used to authorize an action by a user. @@ -37,12 +38,11 @@ export class AuthWitness { } toString() { - return '0x' + this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(str: string) { - const hex = str.replace(/^0x/, ''); - return AuthWitness.fromBuffer(Buffer.from(hex, 'hex')); + return AuthWitness.fromBuffer(hexToBuffer(str)); } static random() { diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index 48617fa2016..7c5d131a5c8 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -1,3 +1,4 @@ +import { type ZodFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { computeUnbalancedMerkleRoot } from '@aztec/foundation/trees'; @@ -21,7 +22,7 @@ export class Body { }); } - static get schema() { + static get schema(): ZodFor { return z .object({ txEffects: z.array(TxEffect.schema), @@ -29,10 +30,6 @@ export class Body { .transform(({ txEffects }) => new Body(txEffects)); } - toJSON() { - return { txEffects: this.txEffects }; - } - /** * Serializes a block body * @returns A serialized L2 block body. diff --git a/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts b/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts index bfc6097ab09..ec46c4d99e9 100644 --- a/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts +++ b/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts @@ -54,20 +54,4 @@ export class NullifierMembershipWitness { public toFields(): Fr[] { return [new Fr(this.index), ...this.leafPreimage.toFields(), ...this.siblingPath.toFields()]; } - - public toJSON() { - return { - index: '0x' + this.index.toString(16), - leafPreimage: this.leafPreimage.toJSON(), - siblingPath: this.siblingPath.toString(), - }; - } - - static fromJSON(json: any): NullifierMembershipWitness { - return new NullifierMembershipWitness( - BigInt(json.index), - NullifierLeafPreimage.fromJSON(json.leafPreimage), - SiblingPath.fromString(json.siblingPath), - ); - } } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index bf5f8bffe33..169ff874fd6 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -1,7 +1,8 @@ -import { AppendOnlyTreeSnapshot, Header, STRING_ENCODING } from '@aztec/circuits.js'; +import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js'; import { sha256, sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { z } from 'zod'; @@ -31,14 +32,6 @@ export class L2Block { .transform(({ archive, header, body }) => new L2Block(archive, header, body)); } - toJSON() { - return { - archive: this.archive, - header: this.header, - body: this.body, - }; - } - /** * Deserializes a block from a buffer * @returns A deserialized L2 block. @@ -66,7 +59,7 @@ export class L2Block { * @returns Deserialized L2 block. */ static fromString(str: string): L2Block { - return L2Block.fromBuffer(Buffer.from(str, STRING_ENCODING)); + return L2Block.fromBuffer(hexToBuffer(str)); } /** @@ -74,7 +67,7 @@ export class L2Block { * @returns A serialized L2 block as a string. */ toString(): string { - return this.toBuffer().toString(STRING_ENCODING); + return bufferToHex(this.toBuffer()); } /** diff --git a/yarn-project/circuit-types/src/l2_block_downloader/l2_block_stream.test.ts b/yarn-project/circuit-types/src/l2_block_downloader/l2_block_stream.test.ts index 756c598eb1e..bb8eaafc83a 100644 --- a/yarn-project/circuit-types/src/l2_block_downloader/l2_block_stream.test.ts +++ b/yarn-project/circuit-types/src/l2_block_downloader/l2_block_stream.test.ts @@ -42,7 +42,7 @@ describe('L2BlockStream', () => { const makeBlock = (number: number) => ({ number } as L2Block); - const makeHeader = (number: number) => mock
({ hash: () => new Fr(number) }); + const makeHeader = (number: number) => mock
({ hash: () => new Fr(number) } as Header); const setRemoteTips = (latest_: number, proven?: number, finalized?: number) => { proven = proven ?? 0; diff --git a/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts b/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts index f59b98fa6a6..da67376b042 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts +++ b/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts @@ -25,23 +25,10 @@ export class EncryptedL2Log { static get schema() { return z - .object({ data: schemas.BufferHex, maskedContractAddress: schemas.Fr }) + .object({ data: schemas.Buffer, maskedContractAddress: schemas.Fr }) .transform(({ data, maskedContractAddress }) => new EncryptedL2Log(data, maskedContractAddress)); } - /** Returns a JSON-friendly representation of the log. */ - public toJSON(): object { - return { - data: this.data.toString('hex'), - maskedContractAddress: this.maskedContractAddress.toString(), - }; - } - - /** Converts a plain JSON object into an instance. */ - public static fromJSON(obj: any) { - return new EncryptedL2Log(Buffer.from(obj.data, 'hex'), Fr.fromString(obj.maskedContractAddress)); - } - /** * Deserializes log from a buffer. * @param buffer - The buffer containing the log. diff --git a/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts b/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts index 23f5a2a99b1..62d4d7ff62d 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts +++ b/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts @@ -25,20 +25,8 @@ export class EncryptedL2NoteLog { return this.data; } - /** Returns a JSON-friendly representation of the log. */ - public toJSON(): object { - return { data: this.data.toString('hex') }; - } - static get schema() { - return z - .object({ data: schemas.HexString }) - .transform(({ data }) => new EncryptedL2NoteLog(Buffer.from(data, 'hex'))); - } - - /** Converts a plain JSON object into an instance. */ - public static fromJSON(obj: any) { - return new EncryptedL2NoteLog(Buffer.from(obj.data, 'hex')); + return z.object({ data: schemas.Buffer }).transform(({ data }) => new EncryptedL2NoteLog(data)); } /** diff --git a/yarn-project/circuit-types/src/logs/event_metadata.ts b/yarn-project/circuit-types/src/logs/event_metadata.ts index b63d8b8bba5..e5b4a89f221 100644 --- a/yarn-project/circuit-types/src/logs/event_metadata.ts +++ b/yarn-project/circuit-types/src/logs/event_metadata.ts @@ -1,4 +1,4 @@ -import { type AbiType, AbiTypeSchema, EventSelector, decodeFromAbi } from '@aztec/foundation/abi'; +import { type AbiType, AbiTypeSchema, type EventSelector, decodeFromAbi } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; @@ -49,37 +49,13 @@ export class EventMetadata { }; } - /** - * Serializes the metadata to a JSON-friendly format - */ - public toJSON() { - return { - type: 'event_metadata', // TODO(palla/schemas): Remove this type property - eventSelector: this.eventSelector, - abiType: this.abiType, - fieldNames: this.fieldNames, - }; - } - static get schema() { return z .object({ eventSelector: schemas.EventSelector, abiType: AbiTypeSchema, fieldNames: z.array(z.string()), - type: z.literal('event_metadata').optional(), }) .transform(obj => new EventMetadata(obj)); } - - /** - * Creates an EventMetadata instance from a JSON representation - */ - public static fromJSON(json: any): EventMetadata { - return new EventMetadata({ - eventSelector: EventSelector.fromString(json.eventSelector), - abiType: json.abiType, - fieldNames: json.fieldNames, - }); - } } diff --git a/yarn-project/circuit-types/src/logs/extended_unencrypted_l2_log.ts b/yarn-project/circuit-types/src/logs/extended_unencrypted_l2_log.ts index b571879aacd..9bdab9deeb4 100644 --- a/yarn-project/circuit-types/src/logs/extended_unencrypted_l2_log.ts +++ b/yarn-project/circuit-types/src/logs/extended_unencrypted_l2_log.ts @@ -1,4 +1,5 @@ import { BufferReader } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import isEqual from 'lodash.isequal'; @@ -22,10 +23,6 @@ export class ExtendedUnencryptedL2Log { return new ExtendedUnencryptedL2Log(LogId.random(), UnencryptedL2Log.random()); } - toJSON() { - return { id: this.id, log: this.log }; - } - static get schema() { return z .object({ @@ -52,7 +49,7 @@ export class ExtendedUnencryptedL2Log { * @returns A string containing the serialized log. */ public toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -92,7 +89,6 @@ export class ExtendedUnencryptedL2Log { * @returns An `ExtendedUnencryptedL2Log` object. */ public static fromString(data: string): ExtendedUnencryptedL2Log { - const buffer = Buffer.from(data, 'hex'); - return ExtendedUnencryptedL2Log.fromBuffer(buffer); + return ExtendedUnencryptedL2Log.fromBuffer(hexToBuffer(data)); } } diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts index 5effe039a0c..d0f49d57c7c 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts @@ -1,3 +1,5 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + import { EncryptedFunctionL2Logs, EncryptedNoteFunctionL2Logs, UnencryptedFunctionL2Logs } from './function_l2_logs.js'; function shouldBehaveLikeFunctionL2Logs( @@ -19,8 +21,8 @@ function shouldBehaveLikeFunctionL2Logs( it('can encode L2Logs to JSON and back', () => { const l2Logs = FunctionL2Logs.random(3); - const buffer = JSON.stringify(l2Logs.toJSON()); - const recovered = FunctionL2Logs.fromJSON(JSON.parse(buffer)); + const buffer = jsonStringify(l2Logs); + const recovered = FunctionL2Logs.schema.parse(JSON.parse(buffer)); expect(recovered).toEqual(l2Logs); }); diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.ts index e3127e63cd6..2171fb2c17e 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.ts @@ -62,14 +62,6 @@ export abstract class FunctionL2Logs l.hash())); return sha256Trunc(preimage); } - - /** - * Convert a FunctionL2Logs class object to a plain JSON object. - * @returns A plain object with FunctionL2Logs properties. - */ - public toJSON() { - return { logs: this.logs }; - } } export class EncryptedNoteFunctionL2Logs extends FunctionL2Logs { @@ -118,16 +110,6 @@ export class EncryptedNoteFunctionL2Logs extends FunctionL2Logs { @@ -176,16 +158,6 @@ export class EncryptedFunctionL2Logs extends FunctionL2Logs { } return new EncryptedFunctionL2Logs(logs); } - - /** - * Convert a plain JSON object to a FunctionL2Logs class object. - * @param obj - A plain FunctionL2Logs JSON object. - * @returns A FunctionL2Logs class object. - */ - public static fromJSON(obj: any) { - const logs = obj.logs.map(EncryptedL2Log.fromJSON); - return new EncryptedFunctionL2Logs(logs); - } } export class UnencryptedFunctionL2Logs extends FunctionL2Logs { @@ -234,14 +206,4 @@ export class UnencryptedFunctionL2Logs extends FunctionL2Logs } return new UnencryptedFunctionL2Logs(logs); } - - /** - * Convert a plain JSON object to a FunctionL2Logs class object. - * @param obj - A plain FunctionL2Logs JSON object. - * @returns A FunctionL2Logs class object. - */ - public static fromJSON(obj: any) { - const logs = obj.logs.map(UnencryptedL2Log.fromJSON); - return new UnencryptedFunctionL2Logs(logs); - } } diff --git a/yarn-project/circuit-types/src/logs/get_logs_response.ts b/yarn-project/circuit-types/src/logs/get_logs_response.ts index 6f1d156be0b..62b2ff6d833 100644 --- a/yarn-project/circuit-types/src/logs/get_logs_response.ts +++ b/yarn-project/circuit-types/src/logs/get_logs_response.ts @@ -52,7 +52,7 @@ export class TxScopedL2Log { dataStartIndexForTx: z.number(), blockNumber: z.number(), isFromPublic: z.boolean(), - logData: schemas.BufferB64, + logData: schemas.Buffer, }) .transform( ({ txHash, dataStartIndexForTx, blockNumber, isFromPublic, logData }) => diff --git a/yarn-project/circuit-types/src/logs/l1_payload/payload.test.ts b/yarn-project/circuit-types/src/logs/l1_payload/payload.test.ts index a4fa27d833a..6dc3a358683 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/payload.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/payload.test.ts @@ -1,13 +1,23 @@ import { Fr } from '@aztec/foundation/fields'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; + +import times from 'lodash.times'; import { Event, Note } from './payload.js'; describe('note', () => { + let note: Note; + + beforeEach(() => { + note = new Note(times(5, Fr.random)); + }); + it('convert to and from buffer', () => { - const fields = Array.from({ length: 5 }).map(() => Fr.random()); - const note = new Note(fields); - const buf = note.toBuffer(); - expect(Note.fromBuffer(buf)).toEqual(note); + expect(Note.fromBuffer(note.toBuffer())).toEqual(note); + }); + + it('converts to and from json', () => { + expect(jsonParseWithSchema(jsonStringify(note), Note.schema)).toEqual(note); }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_payload/payload.ts b/yarn-project/circuit-types/src/logs/l1_payload/payload.ts index cc460a2a3cd..4bcad7408fc 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/payload.ts @@ -1,8 +1,9 @@ import { Vector } from '@aztec/circuits.js'; import { randomInt } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { schemas } from '@aztec/foundation/schemas'; import { BufferReader } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; /** * The Note class represents a Note emitted from a Noir contract as a vector of Fr (finite field) elements. @@ -11,11 +12,11 @@ import { BufferReader } from '@aztec/foundation/serialize'; */ export class Payload extends Vector { toJSON() { - return this.toString(); + return this.toBuffer(); } static get schema() { - return hexSchemaFor(Payload); + return schemas.Buffer.transform(Payload.fromBuffer); } /** @@ -49,7 +50,7 @@ export class Payload extends Vector { * @returns A hex string with the vector length as first element. */ override toString() { - return '0x' + this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -58,8 +59,7 @@ export class Payload extends Vector { * @returns A Note instance. */ static fromString(str: string) { - const hex = str.replace(/^0x/, ''); - return Payload.fromBuffer(Buffer.from(hex, 'hex')); + return Payload.fromBuffer(hexToBuffer(str)); } get length() { @@ -71,6 +71,24 @@ export class Payload extends Vector { } } -export class Event extends Payload {} +export class Event extends Payload { + static override get schema() { + return schemas.Buffer.transform(Event.fromBuffer); + } + + static override fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new Event(reader.readVector(Fr)); + } +} -export class Note extends Payload {} +export class Note extends Payload { + static override get schema() { + return schemas.Buffer.transform(Note.fromBuffer); + } + + static override fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new Note(reader.readVector(Fr)); + } +} diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts index 41ea8c0eee8..e16b963525b 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts @@ -45,17 +45,6 @@ function shouldBehaveLikeL2BlockL2Logs( } }); - it('serializes to and from JSON via fromJSON', () => { - const l2Logs = - L2BlockL2Logs.name == 'ContractClass2BlockL2Logs' - ? L2BlockL2Logs.random(3, 1, 1) - : L2BlockL2Logs.random(3, 4, 2); - const json = jsonStringify(l2Logs); - const recovered = L2BlockL2Logs.fromJSON(JSON.parse(json)); - expect(recovered).toEqual(l2Logs); - expect(recovered).toBeInstanceOf(L2BlockL2Logs); - }); - it('serializes to and from JSON via schema', () => { const l2Logs = L2BlockL2Logs.name == 'ContractClass2BlockL2Logs' diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts index 2698fc2fc12..82bf2d4a899 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts @@ -1,5 +1,6 @@ import { type ZodFor } from '@aztec/foundation/schemas'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import isEqual from 'lodash.isequal'; import { z } from 'zod'; @@ -70,7 +71,7 @@ export abstract class L2BlockL2Logs EncryptedNoteTxL2Logs.fromJSON(log)); - return new EncryptedNoteL2BlockL2Logs(txLogs); - } - /** * Deserializes logs from a buffer. * @param buffer - The buffer containing the serialized logs. @@ -144,8 +135,7 @@ export class EncryptedNoteL2BlockL2Logs extends L2BlockL2Logs { return 'Encrypted'; } - /** - * Convert a plain JSON object to a L2BlockL2Logs class object. - * @param obj - A plain L2BlockL2Logs JSON object. - * @returns A L2BlockL2Logs class object. - */ - public static fromJSON(obj: any) { - const txLogs = obj.txLogs.map((log: any) => EncryptedTxL2Logs.fromJSON(log)); - return new EncryptedL2BlockL2Logs(txLogs); - } - /** * Deserializes logs from a buffer. * @param buffer - The buffer containing the serialized logs. @@ -225,8 +205,7 @@ export class EncryptedL2BlockL2Logs extends L2BlockL2Logs { * @returns A new `L2BlockL2Logs` object. */ public static fromString(data: string): EncryptedL2BlockL2Logs { - const buffer = Buffer.from(data, 'hex'); - return EncryptedL2BlockL2Logs.fromBuffer(buffer); + return EncryptedL2BlockL2Logs.fromBuffer(hexToBuffer(data)); } /** @@ -275,16 +254,6 @@ export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { return 'Unencrypted'; } - /** - * Convert a plain JSON object to a L2BlockL2Logs class object. - * @param obj - A plain L2BlockL2Logs JSON object. - * @returns A L2BlockL2Logs class object. - */ - public static fromJSON(obj: any) { - const txLogs = obj.txLogs.map((log: any) => UnencryptedTxL2Logs.fromJSON(log)); - return new UnencryptedL2BlockL2Logs(txLogs); - } - /** * Deserializes logs from a buffer. * @param buffer - The buffer containing the serialized logs. @@ -306,8 +275,7 @@ export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { * @returns A new `L2BlockL2Logs` object. */ public static fromString(data: string): UnencryptedL2BlockL2Logs { - const buffer = Buffer.from(data, 'hex'); - return UnencryptedL2BlockL2Logs.fromBuffer(buffer); + return UnencryptedL2BlockL2Logs.fromBuffer(hexToBuffer(data)); } /** @@ -358,16 +326,6 @@ export class ContractClass2BlockL2Logs extends L2BlockL2Logs { return 'ContractClass'; } - /** - * Convert a plain JSON object to a L2BlockL2Logs class object. - * @param obj - A plain L2BlockL2Logs JSON object. - * @returns A L2BlockL2Logs class object. - */ - public static fromJSON(obj: any) { - const txLogs = obj.txLogs.map((log: any) => ContractClassTxL2Logs.fromJSON(log)); - return new ContractClass2BlockL2Logs(txLogs); - } - /** * Deserializes logs from a buffer. * @param buffer - The buffer containing the serialized logs. @@ -389,8 +347,7 @@ export class ContractClass2BlockL2Logs extends L2BlockL2Logs { * @returns A new `L2BlockL2Logs` object. */ public static fromString(data: string): ContractClass2BlockL2Logs { - const buffer = Buffer.from(data, 'hex'); - return ContractClass2BlockL2Logs.fromBuffer(buffer); + return ContractClass2BlockL2Logs.fromBuffer(hexToBuffer(data)); } /** diff --git a/yarn-project/circuit-types/src/logs/log_id.ts b/yarn-project/circuit-types/src/logs/log_id.ts index 731763b1f07..fe718fb3821 100644 --- a/yarn-project/circuit-types/src/logs/log_id.ts +++ b/yarn-project/circuit-types/src/logs/log_id.ts @@ -50,14 +50,6 @@ export class LogId { .transform(({ blockNumber, txIndex, logIndex }) => new LogId(blockNumber, txIndex, logIndex)); } - toJSON() { - return { - blockNumber: this.blockNumber, - txIndex: this.txIndex, - logIndex: this.logIndex, - }; - } - /** * Serializes log id to a buffer. * @returns A buffer containing the serialized log id. diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts index 5fd7831ebe5..6bec9823692 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts @@ -22,8 +22,8 @@ function shouldBehaveLikeTxL2Logs( it('can encode TxL2Logs to JSON and back', () => { const l2Logs = TxL2Logs.name == 'ContractClassTxL2Logs' ? TxL2Logs.random(1, 1) : TxL2Logs.random(4, 2); - const buffer = jsonStringify(l2Logs.toJSON()); - const recovered = TxL2Logs.fromJSON(JSON.parse(buffer)); + const buffer = jsonStringify(l2Logs); + const recovered = TxL2Logs.schema.parse(JSON.parse(buffer)); expect(recovered).toEqual(l2Logs); }); diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts index afa1f715752..b27b2346f02 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts @@ -76,16 +76,6 @@ export abstract class TxL2Logs log.toJSON()), - }; - } - /** * Unrolls logs from this tx. * @returns Unrolled logs. @@ -209,16 +199,6 @@ export class UnencryptedTxL2Logs extends TxL2Logs { return new UnencryptedTxL2Logs(functionLogs); } - /** - * Convert a plain JSON object to a TxL2Logs class object. - * @param obj - A plain TxL2Logs JSON object. - * @returns A TxL2Logs class object. - */ - public static fromJSON(obj: any) { - const functionLogs = obj.functionLogs.map((log: any) => UnencryptedFunctionL2Logs.fromJSON(log)); - return new UnencryptedTxL2Logs(functionLogs); - } - /** * Computes unencrypted logs hash as is done in the kernel and decoder contract. * @param logs - Logs to be hashed. @@ -303,16 +283,6 @@ export class EncryptedNoteTxL2Logs extends TxL2Logs { return new EncryptedNoteTxL2Logs(functionLogs); } - /** - * Convert a plain JSON object to a TxL2Logs class object. - * @param obj - A plain TxL2Logs JSON object. - * @returns A TxL2Logs class object. - */ - public static fromJSON(obj: any) { - const functionLogs = obj.functionLogs.map((log: any) => EncryptedNoteFunctionL2Logs.fromJSON(log)); - return new EncryptedNoteTxL2Logs(functionLogs); - } - /** * Computes encrypted logs hash as is done in the kernel and decoder contract. * @param logs - Logs to be hashed. @@ -396,16 +366,6 @@ export class EncryptedTxL2Logs extends TxL2Logs { return new EncryptedTxL2Logs(functionLogs); } - /** - * Convert a plain JSON object to a TxL2Logs class object. - * @param obj - A plain TxL2Logs JSON object. - * @returns A TxL2Logs class object. - */ - public static fromJSON(obj: any) { - const functionLogs = obj.functionLogs.map((log: any) => EncryptedFunctionL2Logs.fromJSON(log)); - return new EncryptedTxL2Logs(functionLogs); - } - /** * Computes encrypted logs hash as is done in the kernel and decoder contract. * @param logs - Logs to be hashed. @@ -490,16 +450,6 @@ export class ContractClassTxL2Logs extends TxL2Logs { return new ContractClassTxL2Logs(functionLogs); } - /** - * Convert a plain JSON object to a TxL2Logs class object. - * @param obj - A plain TxL2Logs JSON object. - * @returns A TxL2Logs class object. - */ - public static fromJSON(obj: any) { - const functionLogs = obj.functionLogs.map((log: any) => UnencryptedFunctionL2Logs.fromJSON(log)); - return new ContractClassTxL2Logs(functionLogs); - } - /** * @param logs - Logs to be hashed. * @returns The hash of the logs. diff --git a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.test.ts b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.test.ts index 60f89766d9d..7917be9f8a6 100644 --- a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.test.ts +++ b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.test.ts @@ -1,3 +1,5 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + import { UnencryptedL2Log } from './unencrypted_l2_log.js'; describe('UnencryptedL2Log', () => { @@ -9,4 +11,13 @@ describe('UnencryptedL2Log', () => { expect(recovered).toEqual(l2Logs); }); + + it('can encode to JSON and back', () => { + const l2Logs = UnencryptedL2Log.random(); + + const buffer = jsonStringify(l2Logs); + const recovered = UnencryptedL2Log.schema.parse(JSON.parse(buffer)); + + expect(recovered).toEqual(l2Logs); + }); }); diff --git a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts index b43778409a9..942dad32db2 100644 --- a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts +++ b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts @@ -48,23 +48,10 @@ export class UnencryptedL2Log { static get schema() { return z - .object({ contractAddress: schemas.AztecAddress, data: schemas.BufferHex }) + .object({ contractAddress: schemas.AztecAddress, data: schemas.Buffer }) .transform(({ contractAddress, data }) => new UnencryptedL2Log(contractAddress, data)); } - /** Returns a JSON-friendly representation of the log. */ - public toJSON(): object { - return { - contractAddress: this.contractAddress.toString(), - data: this.data.toString('hex'), - }; - } - - /** Converts a plain JSON object into an instance. */ - public static fromJSON(obj: any) { - return new UnencryptedL2Log(AztecAddress.fromString(obj.contractAddress), Buffer.from(obj.data, 'hex')); - } - /** * Deserializes log from a buffer. * @param buffer - The buffer or buffer reader containing the log. diff --git a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts index e68a73a83e8..3dc438940e2 100644 --- a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts @@ -4,6 +4,7 @@ import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex } from '@aztec/foundation/string'; import { type AztecNode } from '../interfaces/aztec-node.js'; import { MerkleTreeId } from '../merkle_tree_id.js'; @@ -55,7 +56,7 @@ export class L1ToL2Message { } toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(data: string): L1ToL2Message { diff --git a/yarn-project/circuit-types/src/notes/extended_note.test.ts b/yarn-project/circuit-types/src/notes/extended_note.test.ts index 25a2280b527..a5035cc5406 100644 --- a/yarn-project/circuit-types/src/notes/extended_note.test.ts +++ b/yarn-project/circuit-types/src/notes/extended_note.test.ts @@ -1,18 +1,40 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + import { randomExtendedNote, randomUniqueNote } from '../mocks.js'; import { ExtendedNote, UniqueNote } from './extended_note.js'; -describe('Extended Note', () => { +describe('ExtendedNote', () => { + let note: ExtendedNote; + + beforeEach(() => { + note = randomExtendedNote(); + }); + it('convert to and from buffer', () => { - const extendedNote = randomExtendedNote(); - const buf = extendedNote.toBuffer(); - expect(ExtendedNote.fromBuffer(buf)).toEqual(extendedNote); + const buf = note.toBuffer(); + expect(ExtendedNote.fromBuffer(buf)).toEqual(note); + }); + + it('convert to and from JSON', () => { + const json = jsonStringify(note); + expect(ExtendedNote.schema.parse(JSON.parse(json))).toEqual(note); }); }); -describe('Unique Note', () => { +describe('UniqueNote', () => { + let note: UniqueNote; + + beforeEach(() => { + note = randomUniqueNote(); + }); + it('convert to and from buffer', () => { - const uniqueNote = randomUniqueNote(); - const buf = uniqueNote.toBuffer(); - expect(UniqueNote.fromBuffer(buf)).toEqual(uniqueNote); + const buf = note.toBuffer(); + expect(UniqueNote.fromBuffer(buf)).toEqual(note); + }); + + it('convert to and from JSON', () => { + const json = jsonStringify(note); + expect(UniqueNote.schema.parse(JSON.parse(json))).toEqual(note); }); }); diff --git a/yarn-project/circuit-types/src/notes/extended_note.ts b/yarn-project/circuit-types/src/notes/extended_note.ts index a3c3506cdbb..cac982b01b8 100644 --- a/yarn-project/circuit-types/src/notes/extended_note.ts +++ b/yarn-project/circuit-types/src/notes/extended_note.ts @@ -1,7 +1,10 @@ import { AztecAddress, Fr } from '@aztec/circuits.js'; import { NoteSelector } from '@aztec/foundation/abi'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { schemas } from '@aztec/foundation/schemas'; import { BufferReader } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; + +import { z } from 'zod'; import { Note } from '../logs/l1_payload/payload.js'; import { TxHash } from '../tx/tx_hash.js'; @@ -49,21 +52,27 @@ export class ExtendedNote { return new this(note, owner, contractAddress, storageSlot, noteTypeId, txHash); } - toJSON() { - return this.toString(); - } - static get schema() { - return hexSchemaFor(ExtendedNote); + return z + .object({ + note: Note.schema, + owner: schemas.AztecAddress, + contractAddress: schemas.AztecAddress, + storageSlot: schemas.Fr, + noteTypeId: schemas.NoteSelector, + txHash: TxHash.schema, + }) + .transform(({ note, owner, contractAddress, storageSlot, noteTypeId, txHash }) => { + return new ExtendedNote(note, owner, contractAddress, storageSlot, noteTypeId, txHash); + }); } toString() { - return '0x' + this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(str: string) { - const hex = str.replace(/^0x/, ''); - return ExtendedNote.fromBuffer(Buffer.from(hex, 'hex')); + return ExtendedNote.fromBuffer(hexToBuffer(str)); } static random() { @@ -99,7 +108,19 @@ export class UniqueNote extends ExtendedNote { } static override get schema() { - return hexSchemaFor(UniqueNote); + return z + .object({ + note: Note.schema, + owner: schemas.AztecAddress, + contractAddress: schemas.AztecAddress, + storageSlot: schemas.Fr, + noteTypeId: schemas.NoteSelector, + txHash: TxHash.schema, + nonce: schemas.Fr, + }) + .transform(({ note, owner, contractAddress, storageSlot, noteTypeId, txHash, nonce }) => { + return new UniqueNote(note, owner, contractAddress, storageSlot, noteTypeId, txHash, nonce); + }); } override toBuffer(): Buffer { @@ -141,7 +162,6 @@ export class UniqueNote extends ExtendedNote { } static override fromString(str: string) { - const hex = str.replace(/^0x/, ''); - return UniqueNote.fromBuffer(Buffer.from(hex, 'hex')); + return UniqueNote.fromBuffer(hexToBuffer(str)); } } diff --git a/yarn-project/circuit-types/src/p2p/consensus_payload.ts b/yarn-project/circuit-types/src/p2p/consensus_payload.ts index a5ce2fbed50..3c4d5e946b0 100644 --- a/yarn-project/circuit-types/src/p2p/consensus_payload.ts +++ b/yarn-project/circuit-types/src/p2p/consensus_payload.ts @@ -1,6 +1,7 @@ import { Header } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { encodeAbiParameters, parseAbiParameters } from 'viem'; @@ -26,19 +27,19 @@ export class ConsensusPayload implements Signable { getPayloadToSign(domainSeperator: SignatureDomainSeperator): Buffer { const abi = parseAbiParameters('uint8, (bytes32, bytes32, (uint256, uint256), bytes, bytes32[])'); - const txArray = this.txHashes.map(tx => tx.to0xString()); + const txArray = this.txHashes.map(tx => tx.toString()); const encodedData = encodeAbiParameters(abi, [ domainSeperator, [ this.archive.toString(), this.header.hash().toString(), [0n, 0n] /* @todo See #9963 */, - `0x${this.header.toString()}`, + this.header.toString(), txArray, ], ] as const); - return Buffer.from(encodedData.slice(2), 'hex'); + return hexToBuffer(encodedData); } toBuffer(): Buffer { diff --git a/yarn-project/circuit-types/src/private_execution_result.test.ts b/yarn-project/circuit-types/src/private_execution_result.test.ts index f67092467df..1b3a97f766e 100644 --- a/yarn-project/circuit-types/src/private_execution_result.test.ts +++ b/yarn-project/circuit-types/src/private_execution_result.test.ts @@ -1,5 +1,5 @@ import { Fr, PrivateCircuitPublicInputs } from '@aztec/circuits.js'; -import { jsonStringify } from '@aztec/foundation/json-rpc'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; import { PrivateExecutionResult, @@ -36,8 +36,11 @@ describe('execution_result', () => { }); describe('serialization', () => { - const instance = PrivateExecutionResult.random(); - expect(PrivateExecutionResult.schema.parse(JSON.parse(jsonStringify(instance)))).toEqual(instance); + it('serializes and deserializes correctly', () => { + const instance = PrivateExecutionResult.random(); + jsonParseWithSchema; + expect(jsonParseWithSchema(jsonStringify(instance), PrivateExecutionResult.schema)).toEqual(instance); + }); }); describe('collectNoteHashLeafIndexMap', () => { diff --git a/yarn-project/circuit-types/src/private_execution_result.ts b/yarn-project/circuit-types/src/private_execution_result.ts index 588c4c44ab2..893ecc0ad4f 100644 --- a/yarn-project/circuit-types/src/private_execution_result.ts +++ b/yarn-project/circuit-types/src/private_execution_result.ts @@ -3,7 +3,7 @@ import { NoteSelector } from '@aztec/foundation/abi'; import { times } from '@aztec/foundation/collection'; import { randomBytes, randomInt } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { type ZodFor, hexSchemaFor, mapSchema, schemas } from '@aztec/foundation/schemas'; +import { type ZodFor, mapSchema, schemas } from '@aztec/foundation/schemas'; import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; @@ -46,22 +46,6 @@ export class NoteAndSlot { return new NoteAndSlot(fields.note, fields.storageSlot, fields.noteTypeId); } - toJSON() { - return { - note: this.note.toBuffer().toString('hex'), - storageSlot: this.storageSlot.toBuffer().toString('hex'), - noteTypeId: this.noteTypeId.toString(), - }; - } - - public static fromJSON(json: any): NoteAndSlot { - return new NoteAndSlot( - Note.fromBuffer(Buffer.from(json.note, 'hex')), - Fr.fromString(json.storageSlot), - NoteSelector.fromString(json.noteTypeId), - ); - } - static random() { return new NoteAndSlot(Note.random(), Fr.random(), NoteSelector.random()); } @@ -115,18 +99,6 @@ export class CountedNoteLog extends CountedLog { .transform(({ log, counter, noteHashCounter }) => new CountedNoteLog(log, counter, noteHashCounter)); } - toJSON() { - return { - log: this.log.toJSON(), - counter: this.counter, - noteHashCounter: this.noteHashCounter, - }; - } - - static fromJSON(json: any) { - return new CountedNoteLog(EncryptedL2NoteLog.fromJSON(json.log), json.counter, json.noteHashCounter); - } - static random() { return new CountedNoteLog(EncryptedL2NoteLog.random(), randomInt(10), randomInt(10)); } @@ -138,7 +110,7 @@ export class CountedPublicExecutionRequest { static get schema() { return z .object({ - request: hexSchemaFor(PublicExecutionRequest), // TODO(palla/schema) Use PublicExecutionRequest.schema, + request: PublicExecutionRequest.schema, counter: schemas.Integer, }) .transform(CountedPublicExecutionRequest.from); @@ -152,20 +124,6 @@ export class CountedPublicExecutionRequest { return this.request.isEmpty() && !this.counter; } - toJSON() { - return { - request: this.request.toBuffer().toString('hex'), - counter: this.counter, - }; - } - - static fromJSON(json: any) { - return new CountedPublicExecutionRequest( - PublicExecutionRequest.fromBuffer(Buffer.from(json.request, 'hex')), - json.counter, - ); - } - static random() { return new CountedPublicExecutionRequest(PublicExecutionRequest.random(), 0); } @@ -220,8 +178,8 @@ export class PrivateExecutionResult { static get schema(): ZodFor { return z .object({ - acir: schemas.BufferHex, - vk: schemas.BufferHex, + acir: schemas.Buffer, + vk: schemas.Buffer, partialWitness: mapSchema(z.coerce.number(), z.string()), publicInputs: PrivateCircuitPublicInputs.schema, noteHashLeafIndexMap: mapSchema(schemas.BigInt, schemas.BigInt), @@ -230,7 +188,7 @@ export class PrivateExecutionResult { returnValues: z.array(schemas.Fr), nestedExecutions: z.array(z.lazy(() => PrivateExecutionResult.schema)), enqueuedPublicFunctionCalls: z.array(CountedPublicExecutionRequest.schema), - publicTeardownFunctionCall: hexSchemaFor(PublicExecutionRequest), // TODO(palla/schema) Use PublicExecutionRequest.schema + publicTeardownFunctionCall: PublicExecutionRequest.schema, noteEncryptedLogs: z.array(CountedNoteLog.schema), encryptedLogs: z.array(CountedLog.schemaFor(EncryptedL2Log)), contractClassLogs: z.array(CountedLog.schemaFor(UnencryptedL2Log)), @@ -257,34 +215,6 @@ export class PrivateExecutionResult { ); } - toJSON(): any { - return { - acir: this.acir.toString('hex'), - vk: this.vk.toString('hex'), - partialWitness: Array.from(this.partialWitness.entries()), - publicInputs: this.publicInputs.toJSON(), - noteHashLeafIndexMap: Array.from(this.noteHashLeafIndexMap.entries()).map(([key, value]) => [ - key.toString(), - value.toString(), - ]), - newNotes: this.newNotes.map(note => note.toJSON()), - noteHashNullifierCounterMap: Array.from(this.noteHashNullifierCounterMap.entries()), - returnValues: this.returnValues.map(fr => fr.toBuffer().toString('hex')), - nestedExecutions: this.nestedExecutions.map(exec => exec.toJSON()), - enqueuedPublicFunctionCalls: this.enqueuedPublicFunctionCalls.map(call => call.toJSON()), - publicTeardownFunctionCall: this.publicTeardownFunctionCall.toBuffer().toString('hex'), - noteEncryptedLogs: this.noteEncryptedLogs.map(log => log.toJSON()), - encryptedLogs: this.encryptedLogs.map(countedLog => ({ - log: countedLog.log.toJSON(), - counter: countedLog.counter, - })), - contractClassLogs: this.contractClassLogs.map(countedLog => ({ - log: countedLog.log.toJSON(), - counter: countedLog.counter, - })), - }; - } - static random(nested = 1): PrivateExecutionResult { return new PrivateExecutionResult( randomBytes(4), @@ -303,45 +233,6 @@ export class PrivateExecutionResult { [new CountedLog(UnencryptedL2Log.random(), randomInt(10))], ); } - - static fromJSON(json: any): PrivateExecutionResult { - return new PrivateExecutionResult( - Buffer.from(json.acir, 'hex'), - Buffer.from(json.vk, 'hex'), - Array.isArray(json.partialWitness) - ? new Map(json.partialWitness.map(([key, value]: any[]) => [Number(key), value as string])) - : new Map(), - PrivateCircuitPublicInputs.fromJSON(json.publicInputs), - Array.isArray(json.noteHashLeafIndexMap) - ? new Map(json.noteHashLeafIndexMap.map(([key, value]: any[]) => [BigInt(key), BigInt(value)])) - : new Map(), - Array.isArray(json.newNotes) ? json.newNotes.map((note: any) => NoteAndSlot.fromJSON(note)) : [], - Array.isArray(json.noteHashNullifierCounterMap) - ? new Map(json.noteHashNullifierCounterMap.map(([key, value]: any[]) => [Number(key), Number(value)])) - : new Map(), - json.returnValues.map((fr: any) => new Fr(Buffer.from(fr, 'hex'))), - Array.isArray(json.nestedExecutions) - ? json.nestedExecutions.map((exec: any) => PrivateExecutionResult.fromJSON(exec)) - : [], - Array.isArray(json.enqueuedPublicFunctionCalls) - ? json.enqueuedPublicFunctionCalls.map((call: any) => CountedPublicExecutionRequest.fromJSON(call)) - : [], - PublicExecutionRequest.fromBuffer(Buffer.from(json.publicTeardownFunctionCall, 'hex')), - Array.isArray(json.noteEncryptedLogs) - ? json.noteEncryptedLogs.map((json: any) => CountedNoteLog.fromJSON(json)) - : [], - Array.isArray(json.encryptedLogs) - ? json.encryptedLogs.map( - (json: any) => new CountedLog(EncryptedL2Log.fromJSON(json.log), json.counter), - ) - : [], - Array.isArray(json.contractClassLogs) - ? json.contractClassLogs.map( - (json: any) => new CountedLog(UnencryptedL2Log.fromJSON(json.log), json.counter), - ) - : [], - ); - } } export function collectNoteHashLeafIndexMap( diff --git a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.test.ts b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.test.ts index 78f68edee04..fe29fcb941d 100644 --- a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.test.ts +++ b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.test.ts @@ -1,5 +1,6 @@ import { EthAddress } from '@aztec/circuits.js'; import { Signature } from '@aztec/foundation/eth-signature'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; import { EpochProofQuote } from './epoch_proof_quote.js'; import { EpochProofQuotePayload } from './epoch_proof_quote_payload.js'; @@ -30,7 +31,7 @@ describe('epoch proof quote', () => { }); it('should serialize and deserialize from JSON', () => { - const deserialised = EpochProofQuote.fromJSON(quote.toJSON()); + const deserialised = jsonParseWithSchema(jsonStringify(quote), EpochProofQuote.schema); checkEquivalence(quote, deserialised); }); }); diff --git a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.ts b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.ts index d6f7222cf8b..454d01aa585 100644 --- a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.ts +++ b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote.ts @@ -1,7 +1,6 @@ import { Buffer32 } from '@aztec/foundation/buffer'; import { type Secp256k1Signer, keccak256 } from '@aztec/foundation/crypto'; import { Signature } from '@aztec/foundation/eth-signature'; -import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; @@ -44,26 +43,15 @@ export class EpochProofQuote extends Gossipable { return new EpochProofQuote(reader.readObject(EpochProofQuotePayload), reader.readObject(Signature)); } - toJSON() { - return { - payload: this.payload.toJSON(), - signature: this.signature.to0xString(), - }; - } - static get schema() { return z .object({ payload: EpochProofQuotePayload.schema, - signature: schemas.Signature, + signature: Signature.schema, }) .transform(({ payload, signature }) => new EpochProofQuote(payload, signature)); } - static fromJSON(obj: any) { - return EpochProofQuote.schema.parse(obj); - } - // TODO: https://github.com/AztecProtocol/aztec-packages/issues/8911 /** * Creates a new quote with a signature. diff --git a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote_payload.ts b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote_payload.ts index 7f1e87eee87..60c06e39501 100644 --- a/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote_payload.ts +++ b/yarn-project/circuit-types/src/prover_coordination/epoch_proof_quote_payload.ts @@ -3,6 +3,7 @@ import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; +import omit from 'lodash.omit'; import { inspect } from 'util'; import { z } from 'zod'; @@ -82,31 +83,21 @@ export class EpochProofQuotePayload { } toJSON() { - return { - epochToProve: this.epochToProve.toString(), - validUntilSlot: this.validUntilSlot.toString(), - bondAmount: this.bondAmount.toString(), - prover: this.prover.toString(), - basisPointFee: this.basisPointFee, - }; + return omit(this, 'asBuffer', 'size'); } static get schema() { return z .object({ - epochToProve: z.coerce.bigint(), - validUntilSlot: z.coerce.bigint(), - bondAmount: z.coerce.bigint(), + epochToProve: schemas.BigInt, + validUntilSlot: schemas.BigInt, + bondAmount: schemas.BigInt, prover: schemas.EthAddress, - basisPointFee: z.number(), + basisPointFee: schemas.Integer, }) .transform(EpochProofQuotePayload.from); } - static fromJSON(obj: any): EpochProofQuotePayload { - return EpochProofQuotePayload.schema.parse(obj); - } - toViemArgs(): { epochToProve: bigint; validUntilSlot: bigint; diff --git a/yarn-project/circuit-types/src/public_data_witness.ts b/yarn-project/circuit-types/src/public_data_witness.ts index cdc33705231..41e43418b9a 100644 --- a/yarn-project/circuit-types/src/public_data_witness.ts +++ b/yarn-project/circuit-types/src/public_data_witness.ts @@ -2,6 +2,7 @@ import { Fr, PUBLIC_DATA_TREE_HEIGHT, PublicDataTreeLeafPreimage } from '@aztec/ import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { z } from 'zod'; @@ -63,7 +64,7 @@ export class PublicDataWitness { * Returns a string representation of the TxEffect object. */ toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static random() { @@ -95,6 +96,6 @@ export class PublicDataWitness { * @returns An instance of PublicDataWitness. */ static fromString(str: string) { - return PublicDataWitness.fromBuffer(Buffer.from(str, 'hex')); + return PublicDataWitness.fromBuffer(hexToBuffer(str)); } } diff --git a/yarn-project/circuit-types/src/public_execution_request.ts b/yarn-project/circuit-types/src/public_execution_request.ts index 7cf834cb1c8..6371bac3b09 100644 --- a/yarn-project/circuit-types/src/public_execution_request.ts +++ b/yarn-project/circuit-types/src/public_execution_request.ts @@ -40,13 +40,6 @@ export class PublicExecutionRequest { .transform(PublicExecutionRequest.from); } - toJSON() { - return { - callContext: this.callContext, - args: this.args, - }; - } - static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new PublicExecutionRequest(CallContext.fromBuffer(reader), reader.readVector(Fr)); diff --git a/yarn-project/circuit-types/src/sibling_path/sibling_path.test.ts b/yarn-project/circuit-types/src/sibling_path/sibling_path.test.ts new file mode 100644 index 00000000000..d48e32e820b --- /dev/null +++ b/yarn-project/circuit-types/src/sibling_path/sibling_path.test.ts @@ -0,0 +1,19 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + +import { SiblingPath } from './sibling_path.js'; + +describe('SiblingPath', () => { + it('serializes to JSON', () => { + const path = SiblingPath.random(10); + const json = jsonStringify(path); + expect(SiblingPath.schema.parse(JSON.parse(json))).toEqual(path); + }); + + it('validates length', () => { + const path = SiblingPath.random(10); + const json = jsonStringify(path); + expect(() => SiblingPath.schemaFor(12).parse(JSON.parse(json))).toThrow( + expect.objectContaining({ name: 'ZodError' }), + ); + }); +}); diff --git a/yarn-project/circuit-types/src/sibling_path/sibling_path.ts b/yarn-project/circuit-types/src/sibling_path/sibling_path.ts index a18d02ce951..96738dab368 100644 --- a/yarn-project/circuit-types/src/sibling_path/sibling_path.ts +++ b/yarn-project/circuit-types/src/sibling_path/sibling_path.ts @@ -1,12 +1,13 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchema, hexSchemaFor } from '@aztec/foundation/schemas'; +import { schemas } from '@aztec/foundation/schemas'; import { type Tuple, assertLength, deserializeArrayFromVector, serializeArrayOfBufferableToVector, } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type Hasher } from '@aztec/types/interfaces'; /** @@ -37,17 +38,18 @@ export class SiblingPath { } static get schema() { - return hexSchemaFor(SiblingPath); + return schemas.Buffer.transform(b => SiblingPath.fromBuffer(b)); } static schemaFor(size: N) { - return hexSchema - .transform(str => SiblingPath.fromString(str) as SiblingPath) - .refine(path => path.pathSize === size, 'Unexpected size'); + return schemas.Buffer.transform(b => SiblingPath.fromBuffer(b) as SiblingPath).refine( + path => path.pathSize === size, + path => ({ message: `Expected sibling path size ${size} but got ${path.pathSize}` }), + ); } toJSON() { - return this.toString(); + return this.toBuffer(); } /** @@ -137,7 +139,7 @@ export class SiblingPath { * @returns A hex string representation of the sibling path. */ public toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -146,7 +148,7 @@ export class SiblingPath { * @returns A SiblingPath object. */ public static fromString(repr: string): SiblingPath { - return SiblingPath.fromBuffer(Buffer.from(repr, 'hex')); + return SiblingPath.fromBuffer(hexToBuffer(repr)); } /** diff --git a/yarn-project/circuit-types/src/simulation_error.ts b/yarn-project/circuit-types/src/simulation_error.ts index 70cd960217a..3e84bbdb60e 100644 --- a/yarn-project/circuit-types/src/simulation_error.ts +++ b/yarn-project/circuit-types/src/simulation_error.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Fr, FunctionSelector } from '@aztec/circuits.js'; +import { AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js'; import { type OpcodeLocation } from '@aztec/foundation/abi'; import { schemas } from '@aztec/foundation/schemas'; @@ -220,15 +220,6 @@ export class SimulationError extends Error { }; } - static fromJSON(obj: ReturnType) { - return new SimulationError( - obj.originalMessage, - obj.functionErrorStack, - obj.revertData.map(serializedFr => Fr.fromString(serializedFr)), - obj.noirErrorStack, - ); - } - static get schema() { return z .object({ diff --git a/yarn-project/circuit-types/src/tx/block_hash.ts b/yarn-project/circuit-types/src/tx/block_hash.ts new file mode 100644 index 00000000000..010b2e6ca16 --- /dev/null +++ b/yarn-project/circuit-types/src/tx/block_hash.ts @@ -0,0 +1,29 @@ +import { Fr } from '@aztec/circuits.js'; +import { Buffer32 } from '@aztec/foundation/buffer'; +import { schemas } from '@aztec/foundation/schemas'; + +/** Hash of an L2 block. */ +export class L2BlockHash extends Buffer32 { + constructor( + /** The buffer containing the hash. */ + hash: Buffer, + ) { + super(hash); + } + + static override random() { + return new L2BlockHash(Fr.random().toBuffer()); + } + + static get schema() { + return schemas.BufferHex.transform(value => new L2BlockHash(value)); + } + + static zero() { + return new L2BlockHash(Buffer32.ZERO.toBuffer()); + } + + static override fromField(hash: Fr) { + return new L2BlockHash(hash.toBuffer()); + } +} diff --git a/yarn-project/circuit-types/src/tx/index.ts b/yarn-project/circuit-types/src/tx/index.ts index bc94339f36b..30cae14ee88 100644 --- a/yarn-project/circuit-types/src/tx/index.ts +++ b/yarn-project/circuit-types/src/tx/index.ts @@ -7,3 +7,4 @@ export * from './tx_hash.js'; export * from './tx_receipt.js'; export * from './validator/tx_validator.js'; export * from './validator/empty_validator.js'; +export * from './block_hash.js'; diff --git a/yarn-project/circuit-types/src/tx/public_simulation_output.test.ts b/yarn-project/circuit-types/src/tx/public_simulation_output.test.ts new file mode 100644 index 00000000000..8582164a408 --- /dev/null +++ b/yarn-project/circuit-types/src/tx/public_simulation_output.test.ts @@ -0,0 +1,11 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + +import { PublicSimulationOutput } from './public_simulation_output.js'; + +describe('PublicSimulationOutput', () => { + it('serializes to JSON', () => { + const output = PublicSimulationOutput.random(); + const json = jsonStringify(output); + expect(PublicSimulationOutput.schema.parse(JSON.parse(json))).toEqual(output); + }); +}); diff --git a/yarn-project/circuit-types/src/tx/public_simulation_output.ts b/yarn-project/circuit-types/src/tx/public_simulation_output.ts index a6748c071aa..98ca5e8fc60 100644 --- a/yarn-project/circuit-types/src/tx/public_simulation_output.ts +++ b/yarn-project/circuit-types/src/tx/public_simulation_output.ts @@ -1,5 +1,4 @@ import { CombinedConstantData, Fr, Gas } from '@aztec/circuits.js'; -import { mapValues } from '@aztec/foundation/collection'; import { type ZodFor, schemas } from '@aztec/foundation/schemas'; import times from 'lodash.times'; @@ -31,20 +30,6 @@ export class NestedProcessReturnValues { .transform(({ values, nested }) => new NestedProcessReturnValues(values, nested)); } - toJSON(): any { - return { - values: this.values?.map(fr => fr.toString()), - nested: this.nested.map(n => n.toJSON()), - }; - } - - static fromJSON(json: any): NestedProcessReturnValues { - return new NestedProcessReturnValues( - json.values?.map(Fr.fromString), - json.nested?.map((n: any) => NestedProcessReturnValues.fromJSON(n)), - ); - } - static empty() { return new NestedProcessReturnValues([]); } @@ -90,28 +75,6 @@ export class PublicSimulationOutput { ); } - toJSON() { - return { - revertReason: this.revertReason, - constants: this.constants.toBuffer().toString('hex'), - txEffect: this.txEffect.toBuffer().toString('hex'), - publicReturnValues: this.publicReturnValues.map(returns => returns?.toJSON()), - gasUsed: mapValues(this.gasUsed, gas => gas?.toJSON()), - }; - } - - static fromJSON(json: any): PublicSimulationOutput { - return new PublicSimulationOutput( - json.revertReason, - CombinedConstantData.fromBuffer(Buffer.from(json.constants, 'hex')), - TxEffect.fromBuffer(Buffer.from(json.txEffect, 'hex')), - Array.isArray(json.publicReturnValues) - ? json.publicReturnValues.map((returns: any) => NestedProcessReturnValues.fromJSON(returns)) - : [], - mapValues(json.gasUsed, gas => Gas.fromJSON(gas)), - ); - } - static random() { return new PublicSimulationOutput( SimulationError.random(), diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.test.ts b/yarn-project/circuit-types/src/tx/simulated_tx.test.ts index 035bab4f517..a12a51e3452 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.test.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.test.ts @@ -1,18 +1,33 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + import { mockSimulatedTx } from '../mocks.js'; -import { TxSimulationResult } from './simulated_tx.js'; +import { TxProvingResult, TxSimulationResult } from './simulated_tx.js'; describe('simulated_tx', () => { - let simulatedTx: TxSimulationResult; - beforeEach(() => { - simulatedTx = mockSimulatedTx(); - }); - describe('json', () => { + describe('TxSimulationResult', () => { + let simulatedTx: TxSimulationResult; + beforeEach(() => { + simulatedTx = mockSimulatedTx(); + }); + it('convert to and from json', () => { - expect(TxSimulationResult.fromJSON(JSON.parse(JSON.stringify(simulatedTx.toJSON())))).toEqual(simulatedTx); + expect(TxSimulationResult.schema.parse(JSON.parse(jsonStringify(simulatedTx)))).toEqual(simulatedTx); }); + it('convert undefined effects to and from json', () => { simulatedTx.publicOutput = undefined; - expect(TxSimulationResult.fromJSON(JSON.parse(JSON.stringify(simulatedTx.toJSON())))).toEqual(simulatedTx); + expect(TxSimulationResult.schema.parse(JSON.parse(jsonStringify(simulatedTx)))).toEqual(simulatedTx); + }); + }); + + describe('TxProvingResult', () => { + let tx: TxProvingResult; + beforeEach(() => { + tx = TxProvingResult.random(); + }); + + it('convert to and from json', () => { + expect(TxProvingResult.schema.parse(JSON.parse(jsonStringify(tx)))).toEqual(tx); }); }); }); diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index 62c6270908c..f53e55e2923 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -55,19 +55,6 @@ export class PrivateSimulationResult { ); return tx; } - - public toJSON() { - return { - privateExecutionResult: this.privateExecutionResult.toJSON(), - publicInputs: this.publicInputs.toBuffer().toString('hex'), - }; - } - - public static fromJSON(obj: any) { - const privateExecutionResult = PrivateExecutionResult.fromJSON(obj.privateExecutionResult); - const publicInputs = PrivateKernelTailCircuitPublicInputs.fromBuffer(Buffer.from(obj.publicInputs, 'hex')); - return new PrivateSimulationResult(privateExecutionResult, publicInputs); - } } export class TxSimulationResult extends PrivateSimulationResult { @@ -126,21 +113,12 @@ export class TxSimulationResult extends PrivateSimulationResult { ); } - public override toJSON() { - return { - privateExecutionResult: this.privateExecutionResult.toJSON(), - publicInputs: this.publicInputs.toBuffer().toString('hex'), - publicOutput: this.publicOutput ? this.publicOutput.toJSON() : undefined, - profileResult: this.profileResult, - }; - } - - public static override fromJSON(obj: any) { - const privateExecutionResult = PrivateExecutionResult.fromJSON(obj.privateExecutionResult); - const publicInputs = PrivateKernelTailCircuitPublicInputs.fromBuffer(Buffer.from(obj.publicInputs, 'hex')); - const publicOuput = obj.publicOutput ? PublicSimulationOutput.fromJSON(obj.publicOutput) : undefined; - const profileResult = obj.profileResult; - return new TxSimulationResult(privateExecutionResult, publicInputs, publicOuput, profileResult); + static random() { + return new TxSimulationResult( + PrivateExecutionResult.random(), + PrivateKernelTailCircuitPublicInputs.empty(), + PublicSimulationOutput.random(), + ); } } @@ -186,19 +164,12 @@ export class TxProvingResult { return new TxProvingResult(fields.privateExecutionResult, fields.publicInputs, fields.clientIvcProof); } - public toJSON() { - return { - privateExecutionResult: this.privateExecutionResult, - publicInputs: this.publicInputs, - clientIvcProof: this.clientIvcProof, - }; - } - - public static fromJSON(obj: any) { - const privateExecutionResult = PrivateExecutionResult.fromJSON(obj.privateExecutionResult); - const publicInputs = PrivateKernelTailCircuitPublicInputs.fromBuffer(Buffer.from(obj.publicInputs, 'hex')); - const clientIvcProof = ClientIvcProof.fromBuffer(Buffer.from(obj.clientIvcProof, 'hex')); - return new TxProvingResult(privateExecutionResult, publicInputs, clientIvcProof); + static random() { + return new TxProvingResult( + PrivateExecutionResult.random(), + PrivateKernelTailCircuitPublicInputs.empty(), + ClientIvcProof.empty(), + ); } } diff --git a/yarn-project/circuit-types/src/tx/tx.test.ts b/yarn-project/circuit-types/src/tx/tx.test.ts index 3cfe2c1a4eb..0710303b16b 100644 --- a/yarn-project/circuit-types/src/tx/tx.test.ts +++ b/yarn-project/circuit-types/src/tx/tx.test.ts @@ -1,3 +1,5 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + import { mockTx } from '../mocks.js'; import { Tx } from './tx.js'; @@ -7,4 +9,10 @@ describe('Tx', () => { const buf = tx.toBuffer(); expect(Tx.fromBuffer(buf)).toEqual(tx); }); + + it('convert to and from json', () => { + const tx = mockTx(); + const json = jsonStringify(tx); + expect(Tx.schema.parse(JSON.parse(json))).toEqual(tx); + }); }); diff --git a/yarn-project/circuit-types/src/tx/tx.ts b/yarn-project/circuit-types/src/tx/tx.ts index e290ad2a46f..d049697cec3 100644 --- a/yarn-project/circuit-types/src/tx/tx.ts +++ b/yarn-project/circuit-types/src/tx/tx.ts @@ -7,8 +7,8 @@ import { } from '@aztec/circuits.js'; import { type Buffer32 } from '@aztec/foundation/buffer'; import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection'; -import { hexSchema } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; @@ -154,65 +154,30 @@ export class Tx extends Gossipable { } static get schema() { - // TODO(palla/schemas): Use the nested objects schemas as opposed to the toBuffers return z .object({ - data: hexSchema, // PrivateKernelTailCircuitPublicInputs.schema, - clientIvcProof: hexSchema, // ClientIvcProof.schema, - noteEncryptedLogs: hexSchema, // EncryptedNoteTxL2Logs.schema, - encryptedLogs: hexSchema, // EncryptedTxL2Logs.schema, - unencryptedLogs: hexSchema, // UnencryptedTxL2Logs.schema, - contractClassLogs: hexSchema, // ContractClassTxL2Logs.schema, - enqueuedPublicFunctionCalls: z.array(hexSchema), // z.array(PublicExecutionRequest.schema), - publicTeardownFunctionCall: hexSchema, // PublicExecutionRequest.schema, + data: PrivateKernelTailCircuitPublicInputs.schema, + clientIvcProof: ClientIvcProof.schema, + noteEncryptedLogs: EncryptedNoteTxL2Logs.schema, + encryptedLogs: EncryptedTxL2Logs.schema, + unencryptedLogs: UnencryptedTxL2Logs.schema, + contractClassLogs: ContractClassTxL2Logs.schema, + enqueuedPublicFunctionCalls: z.array(PublicExecutionRequest.schema), + publicTeardownFunctionCall: PublicExecutionRequest.schema, }) - .transform(Tx.fromJSON); + .transform(Tx.from); } - /** - * Convert a Tx class object to a plain JSON object. - * @returns A plain object with Tx properties. - */ - public toJSON() { - return { - data: this.data.toBuffer().toString('hex'), - noteEncryptedLogs: this.noteEncryptedLogs.toBuffer().toString('hex'), - encryptedLogs: this.encryptedLogs.toBuffer().toString('hex'), - unencryptedLogs: this.unencryptedLogs.toBuffer().toString('hex'), - contractClassLogs: this.contractClassLogs.toBuffer().toString('hex'), - clientIvcProof: this.clientIvcProof.toBuffer().toString('hex'), - enqueuedPublicFunctionCalls: this.enqueuedPublicFunctionCalls.map(f => f.toBuffer().toString('hex')) ?? [], - publicTeardownFunctionCall: this.publicTeardownFunctionCall.toBuffer().toString('hex'), - }; - } - - /** - * Convert a plain JSON object to a Tx class object. - * @param obj - A plain Tx JSON object. - * @returns A Tx class object. - */ - public static fromJSON(obj: any) { - const publicInputs = PrivateKernelTailCircuitPublicInputs.fromBuffer(Buffer.from(obj.data, 'hex')); - const noteEncryptedLogs = EncryptedNoteTxL2Logs.fromBuffer(Buffer.from(obj.noteEncryptedLogs, 'hex')); - const encryptedLogs = EncryptedTxL2Logs.fromBuffer(Buffer.from(obj.encryptedLogs, 'hex')); - const unencryptedLogs = UnencryptedTxL2Logs.fromBuffer(Buffer.from(obj.unencryptedLogs, 'hex')); - const contractClassLogs = ContractClassTxL2Logs.fromBuffer(Buffer.from(obj.contractClassLogs, 'hex')); - const clientIvcProof = ClientIvcProof.fromBuffer(Buffer.from(obj.clientIvcProof, 'hex')); - const enqueuedPublicFunctionCalls = obj.enqueuedPublicFunctionCalls - ? obj.enqueuedPublicFunctionCalls.map((x: string) => PublicExecutionRequest.fromBuffer(Buffer.from(x, 'hex'))) - : []; - const publicTeardownFunctionCall = PublicExecutionRequest.fromBuffer( - Buffer.from(obj.publicTeardownFunctionCall, 'hex'), - ); + static from(fields: FieldsOf) { return new Tx( - publicInputs, - clientIvcProof, - noteEncryptedLogs, - encryptedLogs, - unencryptedLogs, - contractClassLogs, - enqueuedPublicFunctionCalls, - publicTeardownFunctionCall, + fields.data, + fields.clientIvcProof, + fields.noteEncryptedLogs, + fields.encryptedLogs, + fields.unencryptedLogs, + fields.contractClassLogs, + fields.enqueuedPublicFunctionCalls, + fields.publicTeardownFunctionCall, ); } diff --git a/yarn-project/circuit-types/src/tx/tx_receipt.test.ts b/yarn-project/circuit-types/src/tx/tx_receipt.test.ts index 2eac60ece2e..b55ec33b7a8 100644 --- a/yarn-project/circuit-types/src/tx/tx_receipt.test.ts +++ b/yarn-project/circuit-types/src/tx/tx_receipt.test.ts @@ -1,3 +1,6 @@ +import { jsonStringify } from '@aztec/foundation/json-rpc'; + +import { L2BlockHash } from './block_hash.js'; import { TxHash } from './tx_hash.js'; import { TxReceipt, TxStatus } from './tx_receipt.js'; @@ -8,16 +11,16 @@ describe('TxReceipt', () => { TxStatus.SUCCESS, 'error', BigInt(1), - Buffer.from('blockHash'), + L2BlockHash.random(), undefined, ); - expect(TxReceipt.fromJSON(receipt.toJSON())).toEqual(receipt); + expect(TxReceipt.schema.parse(JSON.parse(jsonStringify(receipt)))).toEqual(receipt); }); it('serializes and deserializes from json with undefined fields', () => { const receipt = new TxReceipt(TxHash.random(), TxStatus.DROPPED, 'error', undefined, undefined, undefined); - expect(TxReceipt.fromJSON(receipt.toJSON())).toEqual(receipt); + expect(TxReceipt.schema.parse(JSON.parse(jsonStringify(receipt)))).toEqual(receipt); }); }); diff --git a/yarn-project/circuit-types/src/tx/tx_receipt.ts b/yarn-project/circuit-types/src/tx/tx_receipt.ts index 280dae346b7..50b6c840086 100644 --- a/yarn-project/circuit-types/src/tx/tx_receipt.ts +++ b/yarn-project/circuit-types/src/tx/tx_receipt.ts @@ -5,6 +5,7 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; +import { L2BlockHash } from './block_hash.js'; import { TxHash } from './tx_hash.js'; /** @@ -36,7 +37,7 @@ export class TxReceipt { /** The transaction fee paid for the transaction. */ public transactionFee?: bigint, /** The hash of the block containing the transaction. */ - public blockHash?: Buffer, + public blockHash?: L2BlockHash, /** The block number in which the transaction was included. */ public blockNumber?: number, /** Information useful for testing/debugging, set when test flag is set to true in `waitOpts`. */ @@ -47,29 +48,13 @@ export class TxReceipt { return new TxReceipt(TxHash.zero(), TxStatus.DROPPED, ''); } - /** - * Convert a Tx class object to a plain JSON object. - * @returns A plain object with Tx properties. - */ - public toJSON() { - return { - txHash: this.txHash.toString(), - status: this.status.toString(), - error: this.error, - blockHash: this.blockHash?.toString('hex'), - blockNumber: this.blockNumber, - transactionFee: this.transactionFee?.toString(), - ...(this.debugInfo && { debugInfo: this.debugInfo }), - }; - } - static get schema() { return z .object({ txHash: TxHash.schema, status: z.nativeEnum(TxStatus), error: z.string(), - blockHash: schemas.BufferHex.optional(), + blockHash: L2BlockHash.schema.optional(), blockNumber: z.number().optional(), transactionFee: schemas.BigInt.optional(), debugInfo: DebugInfoSchema.optional(), @@ -89,21 +74,6 @@ export class TxReceipt { ); } - /** - * Convert a plain JSON object to a Tx class object. - * @param obj - A plain Tx JSON object. - * @returns A Tx class object. - */ - public static fromJSON(obj: any) { - const txHash = TxHash.fromString(obj.txHash); - const status = obj.status as TxStatus; - const error = obj.error; - const transactionFee = obj.transactionFee ? BigInt(obj.transactionFee) : undefined; - const blockHash = obj.blockHash ? Buffer.from(obj.blockHash, 'hex') : undefined; - const blockNumber = obj.blockNumber ? Number(obj.blockNumber) : undefined; - return new TxReceipt(txHash, status, error, transactionFee, blockHash, blockNumber); - } - public static statusFromRevertCode(revertCode: RevertCode) { if (revertCode.equals(RevertCode.OK)) { return TxStatus.SUCCESS; diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index 8a06a7fb09b..3a00f06c9a2 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -7,17 +7,22 @@ import { PublicDataWrite, RevertCode, } from '@aztec/circuits.js'; -import { makeTuple } from '@aztec/foundation/array'; +import { type FieldsOf, makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; import { sha256Trunc } from '@aztec/foundation/crypto'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; +import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeArrayOfBufferableToVector, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; +import { z } from 'zod'; import { ContractClassTxL2Logs, EncryptedNoteTxL2Logs, EncryptedTxL2Logs, UnencryptedTxL2Logs } from './logs/index.js'; import { TxHash } from './tx/tx_hash.js'; +export { RevertCodeEnum } from '@aztec/circuits.js'; + export class TxEffect { constructor( /** @@ -264,21 +269,51 @@ export class TxEffect { } /** Returns a hex representation of the TxEffect object. */ - toString(): string { - return this.toBuffer().toString('hex'); + toString() { + return bufferToHex(this.toBuffer()); } - toJSON() { - return this.toString(); + static from(fields: Omit, 'txHash'>) { + return new TxEffect( + fields.revertCode, + fields.transactionFee, + fields.noteHashes, + fields.nullifiers, + fields.l2ToL1Msgs, + fields.publicDataWrites, + fields.noteEncryptedLogsLength, + fields.encryptedLogsLength, + fields.unencryptedLogsLength, + fields.contractClassLogsLength, + fields.noteEncryptedLogs, + fields.encryptedLogs, + fields.unencryptedLogs, + fields.contractClassLogs, + ); } static get schema() { - return hexSchemaFor(TxEffect); + return z + .object({ + revertCode: RevertCode.schema, + transactionFee: schemas.Fr, + noteHashes: z.array(schemas.Fr), + nullifiers: z.array(schemas.Fr), + l2ToL1Msgs: z.array(schemas.Fr), + publicDataWrites: z.array(PublicDataWrite.schema), + noteEncryptedLogsLength: schemas.Fr, + encryptedLogsLength: schemas.Fr, + unencryptedLogsLength: schemas.Fr, + contractClassLogsLength: schemas.Fr, + noteEncryptedLogs: EncryptedNoteTxL2Logs.schema, + encryptedLogs: EncryptedTxL2Logs.schema, + unencryptedLogs: UnencryptedTxL2Logs.schema, + contractClassLogs: ContractClassTxL2Logs.schema, + }) + .transform(TxEffect.from); } [inspect.custom]() { - // print out the non-empty fields - return `TxEffect { revertCode: ${this.revertCode}, transactionFee: ${this.transactionFee}, @@ -290,10 +325,10 @@ export class TxEffect { encryptedLogsLength: ${this.encryptedLogsLength}, unencryptedLogsLength: ${this.unencryptedLogsLength}, contractClassLogsLength: ${this.contractClassLogsLength}, - noteEncryptedLogs: ${JSON.stringify(this.noteEncryptedLogs.toJSON())}, - encryptedLogs: ${JSON.stringify(this.encryptedLogs.toJSON())}, - unencryptedLogs: ${JSON.stringify(this.unencryptedLogs.toJSON())} - contractClassLogs: ${JSON.stringify(this.contractClassLogs.toJSON())} + noteEncryptedLogs: ${jsonStringify(this.noteEncryptedLogs)}, + encryptedLogs: ${jsonStringify(this.encryptedLogs)}, + unencryptedLogs: ${jsonStringify(this.unencryptedLogs)} + contractClassLogs: ${jsonStringify(this.contractClassLogs)} }`; } @@ -303,7 +338,7 @@ export class TxEffect { * @returns An instance of TxEffect. */ static fromString(str: string) { - return TxEffect.fromBuffer(Buffer.from(str, 'hex')); + return TxEffect.fromBuffer(hexToBuffer(str)); } get txHash(): TxHash { diff --git a/yarn-project/circuit-types/src/tx_execution_request.test.ts b/yarn-project/circuit-types/src/tx_execution_request.test.ts index 2cb04307dfa..d1de9f1c4db 100644 --- a/yarn-project/circuit-types/src/tx_execution_request.test.ts +++ b/yarn-project/circuit-types/src/tx_execution_request.test.ts @@ -1,6 +1,5 @@ -import { jsonStringify } from '@aztec/foundation/json-rpc'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; -import { jsonParseWithSchema } from '../../foundation/src/json-rpc/convert.js'; import { TxExecutionRequest } from './tx_execution_request.js'; describe('TxExecutionRequest', () => { diff --git a/yarn-project/circuit-types/src/tx_execution_request.ts b/yarn-project/circuit-types/src/tx_execution_request.ts index 9588de8c160..2a99636da2e 100644 --- a/yarn-project/circuit-types/src/tx_execution_request.ts +++ b/yarn-project/circuit-types/src/tx_execution_request.ts @@ -1,6 +1,7 @@ import { AztecAddress, Fr, FunctionData, FunctionSelector, TxContext, TxRequest, Vector } from '@aztec/circuits.js'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; @@ -101,7 +102,7 @@ export class TxExecutionRequest { * @returns The string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -127,7 +128,7 @@ export class TxExecutionRequest { * @returns The deserialized TxRequest object. */ static fromString(str: string): TxExecutionRequest { - return TxExecutionRequest.fromBuffer(Buffer.from(str, 'hex')); + return TxExecutionRequest.fromBuffer(hexToBuffer(str)); } static random() { diff --git a/yarn-project/circuits.js/src/contract/interfaces/contract_class.ts b/yarn-project/circuits.js/src/contract/interfaces/contract_class.ts index 82d0a4960a2..002c3ac4f75 100644 --- a/yarn-project/circuits.js/src/contract/interfaces/contract_class.ts +++ b/yarn-project/circuits.js/src/contract/interfaces/contract_class.ts @@ -45,7 +45,7 @@ export interface ExecutablePrivateFunction extends PrivateFunction { } const ExecutablePrivateFunctionSchema = PrivateFunctionSchema.and( - z.object({ bytecode: schemas.BufferB64 }), + z.object({ bytecode: schemas.Buffer }), ) satisfies ZodFor; /** Public function definition within a contract class. */ @@ -58,7 +58,7 @@ export interface PublicFunction { export const PublicFunctionSchema = z.object({ selector: schemas.FunctionSelector, - bytecode: schemas.BufferB64, + bytecode: schemas.Buffer, }) satisfies ZodFor; /** Unconstrained function definition. */ @@ -72,7 +72,7 @@ export interface UnconstrainedFunction { const UnconstrainedFunctionSchema = z.object({ /** lala */ selector: schemas.FunctionSelector, - bytecode: schemas.BufferB64, + bytecode: schemas.Buffer, }) satisfies ZodFor; /** Sibling paths and sibling commitments for proving membership of a private function within a contract class. */ @@ -124,7 +124,7 @@ export const ContractClassSchema = z.object({ artifactHash: schemas.Fr, privateFunctions: z.array(PrivateFunctionSchema), publicFunctions: z.array(PublicFunctionSchema), - packedBytecode: schemas.BufferB64, + packedBytecode: schemas.Buffer, }) satisfies ZodFor; /** Commitments to fields of a contract class. */ diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap index a4fdeb08c29..5cc25a3728b 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`revert_code should serialize properly 1`] = ` +exports[`revert_code should serialize RevertCode<0> properly 1`] = ` { "data": [ 0, @@ -40,7 +40,7 @@ exports[`revert_code should serialize properly 1`] = ` } `; -exports[`revert_code should serialize properly 2`] = ` +exports[`revert_code should serialize RevertCode<0> properly 2`] = ` { "data": [ 0, @@ -49,14 +49,9 @@ exports[`revert_code should serialize properly 2`] = ` } `; -exports[`revert_code should serialize properly 3`] = ` -{ - "type": "Fr", - "value": "0x0000000000000000000000000000000000000000000000000000000000000000", -} -`; +exports[`revert_code should serialize RevertCode<0> properly 3`] = `"0x0000000000000000000000000000000000000000000000000000000000000000"`; -exports[`revert_code should serialize properly 4`] = ` +exports[`revert_code should serialize RevertCode<1> properly 1`] = ` { "data": [ 0, @@ -96,7 +91,7 @@ exports[`revert_code should serialize properly 4`] = ` } `; -exports[`revert_code should serialize properly 5`] = ` +exports[`revert_code should serialize RevertCode<1> properly 2`] = ` { "data": [ 1, @@ -105,14 +100,9 @@ exports[`revert_code should serialize properly 5`] = ` } `; -exports[`revert_code should serialize properly 6`] = ` -{ - "type": "Fr", - "value": "0x0000000000000000000000000000000000000000000000000000000000000001", -} -`; +exports[`revert_code should serialize RevertCode<1> properly 3`] = `"0x0000000000000000000000000000000000000000000000000000000000000001"`; -exports[`revert_code should serialize properly 7`] = ` +exports[`revert_code should serialize RevertCode<2> properly 1`] = ` { "data": [ 0, @@ -152,7 +142,7 @@ exports[`revert_code should serialize properly 7`] = ` } `; -exports[`revert_code should serialize properly 8`] = ` +exports[`revert_code should serialize RevertCode<2> properly 2`] = ` { "data": [ 2, @@ -161,14 +151,9 @@ exports[`revert_code should serialize properly 8`] = ` } `; -exports[`revert_code should serialize properly 9`] = ` -{ - "type": "Fr", - "value": "0x0000000000000000000000000000000000000000000000000000000000000002", -} -`; +exports[`revert_code should serialize RevertCode<2> properly 3`] = `"0x0000000000000000000000000000000000000000000000000000000000000002"`; -exports[`revert_code should serialize properly 10`] = ` +exports[`revert_code should serialize RevertCode<3> properly 1`] = ` { "data": [ 0, @@ -208,7 +193,7 @@ exports[`revert_code should serialize properly 10`] = ` } `; -exports[`revert_code should serialize properly 11`] = ` +exports[`revert_code should serialize RevertCode<3> properly 2`] = ` { "data": [ 3, @@ -217,9 +202,4 @@ exports[`revert_code should serialize properly 11`] = ` } `; -exports[`revert_code should serialize properly 12`] = ` -{ - "type": "Fr", - "value": "0x0000000000000000000000000000000000000000000000000000000000000003", -} -`; +exports[`revert_code should serialize RevertCode<3> properly 3`] = `"0x0000000000000000000000000000000000000000000000000000000000000003"`; diff --git a/yarn-project/circuits.js/src/structs/avm/avm.ts b/yarn-project/circuits.js/src/structs/avm/avm.ts index b4020f36511..30c37a7b132 100644 --- a/yarn-project/circuits.js/src/structs/avm/avm.ts +++ b/yarn-project/circuits.js/src/structs/avm/avm.ts @@ -1,8 +1,9 @@ import { PublicDataTreeLeafPreimage } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { type ContractClassIdPreimage } from '../../contract/contract_class_id.js'; @@ -34,7 +35,7 @@ export class AvmEnqueuedCallHint { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -79,7 +80,7 @@ export class AvmEnqueuedCallHint { * @returns The deserialized instance. */ static fromString(str: string): AvmEnqueuedCallHint { - return AvmEnqueuedCallHint.fromBuffer(Buffer.from(str, 'hex')); + return AvmEnqueuedCallHint.fromBuffer(hexToBuffer(str)); } } @@ -100,7 +101,7 @@ export class AvmKeyValueHint { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -145,7 +146,7 @@ export class AvmKeyValueHint { * @returns The deserialized instance. */ static fromString(str: string): AvmKeyValueHint { - return AvmKeyValueHint.fromBuffer(Buffer.from(str, 'hex')); + return AvmKeyValueHint.fromBuffer(hexToBuffer(str)); } } @@ -182,7 +183,7 @@ export class AvmExternalCallHint { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -245,7 +246,7 @@ export class AvmExternalCallHint { * @returns The deserialized instance. */ static fromString(str: string): AvmExternalCallHint { - return AvmExternalCallHint.fromBuffer(Buffer.from(str, 'hex')); + return AvmExternalCallHint.fromBuffer(hexToBuffer(str)); } } @@ -272,7 +273,7 @@ export class AvmContractInstanceHint { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -341,7 +342,7 @@ export class AvmContractInstanceHint { * @returns The deserialized instance. */ static fromString(str: string): AvmContractInstanceHint { - return AvmContractInstanceHint.fromBuffer(Buffer.from(str, 'hex')); + return AvmContractInstanceHint.fromBuffer(hexToBuffer(str)); } } @@ -369,7 +370,7 @@ export class AvmContractBytecodeHints { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -434,7 +435,7 @@ export class AvmContractBytecodeHints { * @returns The deserialized instance. */ static fromString(str: string): AvmContractBytecodeHints { - return AvmContractBytecodeHints.fromBuffer(Buffer.from(str, 'hex')); + return AvmContractBytecodeHints.fromBuffer(hexToBuffer(str)); } } @@ -914,7 +915,7 @@ export class AvmExecutionHints { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -1026,7 +1027,7 @@ export class AvmExecutionHints { * @returns The deserialized instance. */ static fromString(str: string): AvmCircuitInputs { - return AvmCircuitInputs.fromBuffer(Buffer.from(str, 'hex')); + return AvmCircuitInputs.fromBuffer(hexToBuffer(str)); } } @@ -1061,7 +1062,7 @@ export class AvmCircuitInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static empty(): AvmCircuitInputs { @@ -1114,16 +1115,16 @@ export class AvmCircuitInputs { * @returns The deserialized instance. */ static fromString(str: string): AvmCircuitInputs { - return AvmCircuitInputs.fromBuffer(Buffer.from(str, 'hex')); + return AvmCircuitInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(AvmCircuitInputs); + return bufferSchemaFor(AvmCircuitInputs); } } diff --git a/yarn-project/circuits.js/src/structs/avm/avm_accumulated_data.ts b/yarn-project/circuits.js/src/structs/avm/avm_accumulated_data.ts index 2e01efc6ee2..c68d93b13e4 100644 --- a/yarn-project/circuits.js/src/structs/avm/avm_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/avm/avm_accumulated_data.ts @@ -2,6 +2,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; @@ -83,11 +84,11 @@ export class AvmAccumulatedData { } static fromString(str: string) { - return this.fromBuffer(Buffer.from(str, 'hex')); + return this.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts index 0ff41750b69..8877b4b8003 100644 --- a/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; @@ -80,11 +81,11 @@ export class AvmCircuitPublicInputs { } static fromString(str: string) { - return AvmCircuitPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return AvmCircuitPublicInputs.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromFields(fields: Fr[] | FieldReader) { diff --git a/yarn-project/circuits.js/src/structs/client_ivc_proof.ts b/yarn-project/circuits.js/src/structs/client_ivc_proof.ts index 737870e5080..a35b8f6c84f 100644 --- a/yarn-project/circuits.js/src/structs/client_ivc_proof.ts +++ b/yarn-project/circuits.js/src/structs/client_ivc_proof.ts @@ -1,4 +1,4 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import * as fs from 'fs/promises'; @@ -67,12 +67,11 @@ export class ClientIvcProof { } static get schema() { - // TODO(palla/schemas): Consider using a b64 schema instead - return hexSchemaFor(ClientIvcProof); + return bufferSchemaFor(ClientIvcProof); } toJSON() { - return '0x' + this.toBuffer().toString('hex'); + return this.toBuffer(); } static fromBuffer(buffer: Buffer | BufferReader): ClientIvcProof { diff --git a/yarn-project/circuits.js/src/structs/complete_address.ts b/yarn-project/circuits.js/src/structs/complete_address.ts index 04d083ae50c..5fbd1132e40 100644 --- a/yarn-project/circuits.js/src/structs/complete_address.ts +++ b/yarn-project/circuits.js/src/structs/complete_address.ts @@ -2,6 +2,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { hexSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex } from '@aztec/foundation/string'; import { computePartialAddress } from '../contract/contract_address.js'; import { computeAddress, computePreaddress, deriveKeys } from '../keys/index.js'; @@ -141,6 +142,6 @@ export class CompleteAddress { * @returns A hexadecimal string representation of the CompleteAddress. */ toString(): string { - return `0x${this.toBuffer().toString('hex')}`; + return bufferToHex(this.toBuffer()); } } diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index 578a6831ff5..8e2e9680ba2 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex } from '@aztec/foundation/string'; import { z } from 'zod'; @@ -34,24 +35,15 @@ export class ContentCommitment { return z .object({ numTxs: schemas.Fr, - txsEffectsHash: schemas.BufferHex, - inHash: schemas.BufferHex, - outHash: schemas.BufferHex, + txsEffectsHash: schemas.Buffer, + inHash: schemas.Buffer, + outHash: schemas.Buffer, }) .transform( ({ numTxs, txsEffectsHash, inHash, outHash }) => new ContentCommitment(numTxs, txsEffectsHash, inHash, outHash), ); } - toJSON() { - return { - numTxs: this.numTxs, - txsEffectsHash: this.txsEffectsHash.toString('hex'), - inHash: this.inHash.toString('hex'), - outHash: this.outHash.toString('hex'), - }; - } - getSize() { return this.toBuffer().length; } @@ -113,7 +105,7 @@ export class ContentCommitment { } public toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(str: string): ContentCommitment { diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 02f58a2deaa..afc63a96d21 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -1,7 +1,10 @@ import { type FunctionAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; +import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { z } from 'zod'; + import { FUNCTION_DATA_LENGTH } from '../constants.gen.js'; import { type ContractFunctionDao } from '../types/contract_function_dao.js'; @@ -21,6 +24,15 @@ export class FunctionData { ); } + static get schema() { + return z + .object({ + selector: schemas.FunctionSelector, + isPrivate: z.boolean(), + }) + .transform(({ selector, isPrivate }) => new FunctionData(selector, isPrivate)); + } + /** * Serialize this as a buffer. * @returns The buffer. @@ -88,15 +100,4 @@ export class FunctionData { return new FunctionData(selector, isPrivate); } - - public toJSON() { - return { - selector: this.selector.toString(), - isPrivate: this.isPrivate, - }; - } - - public static fromJSON(json: any) { - return new FunctionData(FunctionSelector.fromString(json.selector), json.isPrivate); - } } diff --git a/yarn-project/circuits.js/src/structs/gas.ts b/yarn-project/circuits.js/src/structs/gas.ts index 4dc6f24f087..7952b2cbbbd 100644 --- a/yarn-project/circuits.js/src/structs/gas.ts +++ b/yarn-project/circuits.js/src/structs/gas.ts @@ -93,12 +93,4 @@ export class Gas { const reader = FieldReader.asReader(fields); return new Gas(reader.readU32(), reader.readU32()); } - - toJSON() { - return { daGas: this.daGas, l2Gas: this.l2Gas }; - } - - static fromJSON(json: any) { - return new Gas(json.daGas, json.l2Gas); - } } diff --git a/yarn-project/circuits.js/src/structs/gas_fees.ts b/yarn-project/circuits.js/src/structs/gas_fees.ts index 6cab097c0ce..dcaabb12da8 100644 --- a/yarn-project/circuits.js/src/structs/gas_fees.ts +++ b/yarn-project/circuits.js/src/structs/gas_fees.ts @@ -83,17 +83,6 @@ export class GasFees { return serializeToFields(this.feePerDaGas, this.feePerL2Gas); } - static fromJSON(obj: any) { - return new GasFees(Fr.fromString(obj.feePerDaGas), Fr.fromString(obj.feePerL2Gas)); - } - - toJSON() { - return { - feePerDaGas: this.feePerDaGas.toString(), - feePerL2Gas: this.feePerL2Gas.toString(), - }; - } - [inspect.custom]() { return `GasFees { feePerDaGas=${this.feePerDaGas} feePerL2Gas=${this.feePerL2Gas} }`; } diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index f49badfe8ff..914dc7b5fb6 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -1,6 +1,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; @@ -84,19 +85,6 @@ export class GlobalVariables { ); } - static fromJSON(obj: any): GlobalVariables { - return new GlobalVariables( - Fr.fromString(obj.chainId), - Fr.fromString(obj.version), - Fr.fromString(obj.blockNumber), - Fr.fromString(obj.slotNumber), - Fr.fromString(obj.timestamp), - EthAddress.fromString(obj.coinbase), - AztecAddress.fromString(obj.feeRecipient), - GasFees.fromJSON(obj.gasFees), - ); - } - static fromFields(fields: Fr[] | FieldReader): GlobalVariables { const reader = FieldReader.asReader(fields); @@ -140,19 +128,6 @@ export class GlobalVariables { return fields; } - toJSON() { - return { - chainId: this.chainId.toString(), - version: this.version.toString(), - blockNumber: this.blockNumber.toString(), - slotNumber: this.slotNumber.toString(), - timestamp: this.timestamp.toString(), - coinbase: this.coinbase.toString(), - feeRecipient: this.feeRecipient.toString(), - gasFees: this.gasFees.toJSON(), - }; - } - /** * A trimmed version of the JSON representation of the global variables, * tailored for human consumption. @@ -163,7 +138,7 @@ export class GlobalVariables { slotNumber: this.slotNumber.toNumber(), timestamp: this.timestamp.toString(), coinbase: this.coinbase.toString(), - gasFees: this.gasFees.toJSON(), + gasFees: jsonStringify(this.gasFees), }; } diff --git a/yarn-project/circuits.js/src/structs/header.ts b/yarn-project/circuits.js/src/structs/header.ts index f31f85a2ef9..654d202eb51 100644 --- a/yarn-project/circuits.js/src/structs/header.ts +++ b/yarn-project/circuits.js/src/structs/header.ts @@ -2,6 +2,7 @@ import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { inspect } from 'util'; @@ -40,16 +41,6 @@ export class Header { .transform(Header.from); } - toJSON() { - return { - lastArchive: this.lastArchive, - contentCommitment: this.contentCommitment, - state: this.state, - globalVariables: this.globalVariables, - totalFees: this.totalFees, - }; - } - static getFields(fields: FieldsOf
) { // Note: The order here must match the order in the HeaderLib solidity library. return [ @@ -139,13 +130,12 @@ export class Header { * Serializes this instance into a string. * @returns Encoded string. */ - public toString(): string { - return this.toBuffer().toString('hex'); + public toString() { + return bufferToHex(this.toBuffer()); } static fromString(str: string): Header { - const buffer = Buffer.from(str.replace(/^0x/i, ''), 'hex'); - return Header.fromBuffer(buffer); + return Header.fromBuffer(hexToBuffer(str)); } hash(): Fr { diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 16ba5e3b7b7..b245c70f7b6 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -1,8 +1,9 @@ import { type FieldsOf, makeTuple } from '@aztec/foundation/array'; import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; @@ -116,11 +117,11 @@ export class CombinedAccumulatedData { } static get schema() { - return hexSchemaFor(CombinedAccumulatedData); + return bufferSchemaFor(CombinedAccumulatedData); } toJSON() { - return this.toString(); + return this.toBuffer(); } toBuffer() { @@ -128,7 +129,7 @@ export class CombinedAccumulatedData { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -160,7 +161,7 @@ export class CombinedAccumulatedData { * @returns Deserialized object. */ static fromString(str: string) { - return CombinedAccumulatedData.fromBuffer(Buffer.from(str, 'hex')); + return CombinedAccumulatedData.fromBuffer(hexToBuffer(str)); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts index 2ec58bdd269..e5abfe011f1 100644 --- a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { Gas } from '../gas.js'; import { PartialStateReference } from '../partial_state_reference.js'; @@ -89,20 +90,20 @@ export class KernelCircuitPublicInputs { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(str: string) { - return KernelCircuitPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return KernelCircuitPublicInputs.fromBuffer(hexToBuffer(str)); } /** Returns a hex representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(KernelCircuitPublicInputs); + return bufferSchemaFor(KernelCircuitPublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts index 86b7a03ac7f..a314fdde586 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts @@ -1,5 +1,6 @@ import { makeTuple } from '@aztec/foundation/array'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { MAX_CONTRACT_CLASS_LOGS_PER_TX, @@ -75,7 +76,7 @@ export class PrivateAccumulatedData { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -103,7 +104,7 @@ export class PrivateAccumulatedData { * @returns Deserialized object. */ static fromString(str: string) { - return PrivateAccumulatedData.fromBuffer(Buffer.from(str, 'hex')); + return PrivateAccumulatedData.fromBuffer(hexToBuffer(str)); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_circuit_public_inputs.ts index 1db065b1464..1839ce2c98d 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_circuit_public_inputs.ts @@ -1,6 +1,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { PrivateValidationRequests } from '../private_validation_requests.js'; @@ -40,11 +40,11 @@ export class PrivateKernelCircuitPublicInputs { ) {} static get schema() { - return hexSchemaFor(PrivateKernelCircuitPublicInputs); + return bufferSchemaFor(PrivateKernelCircuitPublicInputs); } toJSON() { - return '0x' + this.toBuffer().toString('hex'); + return this.toBuffer(); } toBuffer() { diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_empty_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_empty_inputs.ts index 0a97d999581..9fe7957baa0 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_empty_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_empty_inputs.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { RECURSIVE_PROOF_LENGTH } from '../../constants.gen.js'; @@ -22,7 +23,7 @@ export class PrivateKernelEmptyInputData { } toString(): string { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromBuffer(buf: Buffer) { @@ -37,7 +38,7 @@ export class PrivateKernelEmptyInputData { } static fromString(str: string): PrivateKernelEmptyInputData { - return PrivateKernelEmptyInputData.fromBuffer(Buffer.from(str, 'hex')); + return PrivateKernelEmptyInputData.fromBuffer(hexToBuffer(str)); } static from(fields: FieldsOf) { @@ -50,14 +51,14 @@ export class PrivateKernelEmptyInputData { ); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(PrivateKernelEmptyInputData); + return bufferSchemaFor(PrivateKernelEmptyInputData); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index 7ce5ae26c0d..d21a7590db9 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -1,6 +1,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { countAccumulatedItems, mergeAccumulatedData } from '../../utils/index.js'; @@ -131,11 +131,11 @@ export class PrivateKernelTailCircuitPublicInputs { } static get schema() { - return hexSchemaFor(PrivateKernelTailCircuitPublicInputs); + return bufferSchemaFor(PrivateKernelTailCircuitPublicInputs); } toJSON() { - return '0x' + this.toBuffer().toString('hex'); + return this.toBuffer(); } getSize() { diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts index 7a93e0cee96..ed837be8084 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts @@ -1,5 +1,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { Gas } from '../gas.js'; import { PublicCallRequest } from '../public_call_request.js'; @@ -56,10 +57,10 @@ export class PrivateToPublicKernelCircuitPublicInputs { } static fromString(str: string) { - return PrivateToPublicKernelCircuitPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return PrivateToPublicKernelCircuitPublicInputs.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } } diff --git a/yarn-project/circuits.js/src/structs/parity/base_parity_inputs.ts b/yarn-project/circuits.js/src/structs/parity/base_parity_inputs.ts index 44a6804c840..a02b44025a3 100644 --- a/yarn-project/circuits.js/src/structs/parity/base_parity_inputs.ts +++ b/yarn-project/circuits.js/src/structs/parity/base_parity_inputs.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_MSGS_PER_BASE_PARITY } from '../../constants.gen.js'; @@ -30,7 +31,7 @@ export class BaseParityInputs { /** Serializes the inputs to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -48,16 +49,16 @@ export class BaseParityInputs { * @returns - The deserialized inputs. */ static fromString(str: string) { - return BaseParityInputs.fromBuffer(Buffer.from(str, 'hex')); + return BaseParityInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(BaseParityInputs); + return bufferSchemaFor(BaseParityInputs); } } diff --git a/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts b/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts index d0cd63e2565..1f2f3551c02 100644 --- a/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; export class ParityPublicInputs { @@ -30,12 +31,12 @@ export class ParityPublicInputs { * @returns The inputs serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** @@ -72,10 +73,10 @@ export class ParityPublicInputs { * @returns A new ParityPublicInputs instance. */ static fromString(str: string) { - return ParityPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return ParityPublicInputs.fromBuffer(hexToBuffer(str)); } static get schema() { - return hexSchemaFor(ParityPublicInputs); + return bufferSchemaFor(ParityPublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/parity/root_parity_input.ts b/yarn-project/circuits.js/src/structs/parity/root_parity_input.ts index aa26e28386e..e9b159b4387 100644 --- a/yarn-project/circuits.js/src/structs/parity/root_parity_input.ts +++ b/yarn-project/circuits.js/src/structs/parity/root_parity_input.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { VK_TREE_HEIGHT } from '../../constants.gen.js'; @@ -25,7 +26,7 @@ export class RootParityInput { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static from( @@ -55,16 +56,16 @@ export class RootParityInput { str: string, expectedSize?: PROOF_LENGTH, ): RootParityInput { - return RootParityInput.fromBuffer(Buffer.from(str, 'hex'), expectedSize); + return RootParityInput.fromBuffer(hexToBuffer(str), expectedSize); } /** Returns a hex representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string with expected size. */ static schemaFor(expectedSize?: N) { - return schemas.HexString.transform(str => RootParityInput.fromString(str, expectedSize)); + return schemas.Buffer.transform(buf => RootParityInput.fromBuffer(buf, expectedSize)); } } diff --git a/yarn-project/circuits.js/src/structs/parity/root_parity_inputs.ts b/yarn-project/circuits.js/src/structs/parity/root_parity_inputs.ts index aa74c1092f2..2b09078c755 100644 --- a/yarn-project/circuits.js/src/structs/parity/root_parity_inputs.ts +++ b/yarn-project/circuits.js/src/structs/parity/root_parity_inputs.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { NUM_BASE_PARITY_PER_ROOT_PARITY, RECURSIVE_PROOF_LENGTH } from '../../constants.gen.js'; import { RootParityInput } from './root_parity_input.js'; @@ -26,7 +27,7 @@ export class RootParityInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -50,16 +51,16 @@ export class RootParityInputs { * @returns A new RootParityInputs instance. */ static fromString(str: string) { - return RootParityInputs.fromBuffer(Buffer.from(str, 'hex')); + return RootParityInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(RootParityInputs); + return bufferSchemaFor(RootParityInputs); } } diff --git a/yarn-project/circuits.js/src/structs/partial_state_reference.ts b/yarn-project/circuits.js/src/structs/partial_state_reference.ts index fe484113835..7e212e71262 100644 --- a/yarn-project/circuits.js/src/structs/partial_state_reference.ts +++ b/yarn-project/circuits.js/src/structs/partial_state_reference.ts @@ -19,14 +19,6 @@ export class PartialStateReference { public readonly publicDataTree: AppendOnlyTreeSnapshot, ) {} - toJSON() { - return { - noteHashTree: this.noteHashTree, - nullifierTree: this.nullifierTree, - publicDataTree: this.publicDataTree, - }; - } - static get schema() { return z .object({ diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index dfb3fa6d00f..cded605058d 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -1,6 +1,6 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, @@ -323,18 +323,10 @@ export class PrivateCircuitPublicInputs { } public toJSON() { - return this.toBuffer().toString('hex'); - } - - public static fromJSON(value: any) { - return PrivateCircuitPublicInputs.fromBuffer(Buffer.from(value, 'hex')); - } - - public static fromString(str: string) { - return PrivateCircuitPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return this.toBuffer(); } static get schema() { - return hexSchemaFor(PrivateCircuitPublicInputs); + return bufferSchemaFor(PrivateCircuitPublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/private_validation_requests.ts b/yarn-project/circuits.js/src/structs/private_validation_requests.ts index f026fbfacaf..3b8da4dc030 100644 --- a/yarn-project/circuits.js/src/structs/private_validation_requests.ts +++ b/yarn-project/circuits.js/src/structs/private_validation_requests.ts @@ -2,6 +2,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { arraySerializedSizeOfNonEmpty } from '@aztec/foundation/collection'; import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; @@ -69,7 +70,7 @@ export class PrivateValidationRequests { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromFields(fields: Fr[] | FieldReader) { @@ -105,7 +106,7 @@ export class PrivateValidationRequests { * @returns Deserialized object. */ static fromString(str: string) { - return PrivateValidationRequests.fromBuffer(Buffer.from(str, 'hex')); + return PrivateValidationRequests.fromBuffer(hexToBuffer(str)); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/proof.ts b/yarn-project/circuits.js/src/structs/proof.ts index 57b57606df4..ec6af85223c 100644 --- a/yarn-project/circuits.js/src/structs/proof.ts +++ b/yarn-project/circuits.js/src/structs/proof.ts @@ -1,5 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { AGGREGATION_OBJECT_LENGTH } from '../constants.gen.js'; @@ -61,7 +62,7 @@ export class Proof { * @returns The hex string representation of the proof data. */ public toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } public withoutPublicInputs(): Buffer { @@ -89,7 +90,7 @@ export class Proof { * @returns - A new Proof instance. */ static fromString(str: string) { - return Proof.fromBuffer(Buffer.from(str, 'hex')); + return Proof.fromBuffer(hexToBuffer(str)); } /** Returns whether this proof is actually empty. */ diff --git a/yarn-project/circuits.js/src/structs/public_data_write.ts b/yarn-project/circuits.js/src/structs/public_data_write.ts index 7f4c2e49ca4..001d14a7878 100644 --- a/yarn-project/circuits.js/src/structs/public_data_write.ts +++ b/yarn-project/circuits.js/src/structs/public_data_write.ts @@ -1,7 +1,7 @@ -import { STRING_ENCODING } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; @@ -55,11 +55,11 @@ export class PublicDataWrite { } static fromString(str: string) { - return PublicDataWrite.fromBuffer(Buffer.from(str, STRING_ENCODING)); + return PublicDataWrite.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString(STRING_ENCODING); + return bufferToHex(this.toBuffer()); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/recursive_proof.ts b/yarn-project/circuits.js/src/structs/recursive_proof.ts index ce5a3b0dcae..d1329ee857a 100644 --- a/yarn-project/circuits.js/src/structs/recursive_proof.ts +++ b/yarn-project/circuits.js/src/structs/recursive_proof.ts @@ -2,6 +2,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { Proof, makeEmptyProof } from './proof.js'; @@ -73,7 +74,7 @@ export class RecursiveProof { * @returns The hex string representation of the proof data. */ public toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -82,17 +83,17 @@ export class RecursiveProof { * @returns - A new Proof instance. */ static fromString(str: string, expectedSize?: N): RecursiveProof { - return RecursiveProof.fromBuffer(Buffer.from(str, 'hex'), expectedSize); + return RecursiveProof.fromBuffer(hexToBuffer(str), expectedSize); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string with expected size. */ static schemaFor(expectedSize?: N) { - return schemas.HexString.transform(str => RecursiveProof.fromString(str, expectedSize)); + return schemas.Buffer.transform(b => RecursiveProof.fromBuffer(b, expectedSize)); } } diff --git a/yarn-project/circuits.js/src/structs/revert_code.test.ts b/yarn-project/circuits.js/src/structs/revert_code.test.ts index e2188f7a93a..1fafefb47c4 100644 --- a/yarn-project/circuits.js/src/structs/revert_code.test.ts +++ b/yarn-project/circuits.js/src/structs/revert_code.test.ts @@ -1,10 +1,11 @@ import { Fr } from '@aztec/foundation/fields'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { RevertCode } from './revert_code.js'; describe('revert_code', () => { it.each([RevertCode.OK, RevertCode.APP_LOGIC_REVERTED, RevertCode.TEARDOWN_REVERTED, RevertCode.BOTH_REVERTED])( - 'should serialize properly', + 'should serialize %s properly', revertCode => { expect(revertCode.getSerializedLength()).toBe(1); @@ -20,6 +21,9 @@ describe('revert_code', () => { expect(field).toMatchSnapshot(); expect(RevertCode.fromField(field)).toEqual(revertCode); expect(RevertCode.fromFields([field])).toEqual(revertCode); + + const json = jsonStringify(revertCode); + expect(RevertCode.schema.parse(JSON.parse(json))).toEqual(revertCode); }, ); diff --git a/yarn-project/circuits.js/src/structs/revert_code.ts b/yarn-project/circuits.js/src/structs/revert_code.ts index 55ac00d331c..7e4357f05ae 100644 --- a/yarn-project/circuits.js/src/structs/revert_code.ts +++ b/yarn-project/circuits.js/src/structs/revert_code.ts @@ -2,8 +2,9 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader } from '@aztec/foundation/serialize'; import { inspect } from 'util'; +import { z } from 'zod'; -enum RevertCodeEnum { +export enum RevertCodeEnum { OK = 0, APP_LOGIC_REVERTED = 1, TEARDOWN_REVERTED = 2, @@ -55,6 +56,14 @@ export class RevertCode { } } + public toJSON() { + return this.code; + } + + static get schema() { + return z.nativeEnum(RevertCodeEnum).transform(value => new RevertCode(value)); + } + /** * Having different serialization methods allows for * decoupling the serialization for producing the content commitment hash diff --git a/yarn-project/circuits.js/src/structs/rollup/append_only_tree_snapshot.ts b/yarn-project/circuits.js/src/structs/rollup/append_only_tree_snapshot.ts index b4c71e37be1..5a97560f2e9 100644 --- a/yarn-project/circuits.js/src/structs/rollup/append_only_tree_snapshot.ts +++ b/yarn-project/circuits.js/src/structs/rollup/append_only_tree_snapshot.ts @@ -1,11 +1,12 @@ import { Fr } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; import { z } from 'zod'; -import { STRING_ENCODING, type UInt32 } from '../shared.js'; +import { type UInt32 } from '../shared.js'; /** * Snapshot of an append only tree. @@ -39,10 +40,6 @@ export class AppendOnlyTreeSnapshot { .transform(({ root, nextAvailableLeafIndex }) => new AppendOnlyTreeSnapshot(root, nextAvailableLeafIndex)); } - toJSON() { - return { root: this.root, nextAvailableLeafIndex: this.nextAvailableLeafIndex }; - } - getSize() { return this.root.size + 4; } @@ -56,7 +53,7 @@ export class AppendOnlyTreeSnapshot { } toString(): string { - return this.toBuffer().toString(STRING_ENCODING); + return bufferToHex(this.toBuffer()); } static fromBuffer(buffer: Buffer | BufferReader): AppendOnlyTreeSnapshot { @@ -65,7 +62,7 @@ export class AppendOnlyTreeSnapshot { } static fromString(str: string): AppendOnlyTreeSnapshot { - return AppendOnlyTreeSnapshot.fromBuffer(Buffer.from(str, STRING_ENCODING)); + return AppendOnlyTreeSnapshot.fromBuffer(hexToBuffer(str)); } static fromFields(fields: Fr[] | FieldReader): AppendOnlyTreeSnapshot { diff --git a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts index 981d1f0faa6..c42337e1c0f 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { PartialStateReference } from '../partial_state_reference.js'; import { RollupTypes } from '../shared.js'; @@ -108,7 +109,7 @@ export class BaseOrMergeRollupPublicInputs { * @returns - The hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -117,16 +118,16 @@ export class BaseOrMergeRollupPublicInputs { * @returns A new BaseOrMergeRollupPublicInputs instance. */ static fromString(str: string) { - return BaseOrMergeRollupPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return BaseOrMergeRollupPublicInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(BaseOrMergeRollupPublicInputs); + return bufferSchemaFor(BaseOrMergeRollupPublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/base_rollup_hints.ts b/yarn-project/circuits.js/src/structs/rollup/base_rollup_hints.ts index d9176c82f6d..80f627b4fab 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_rollup_hints.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_rollup_hints.ts @@ -1,4 +1,5 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { ARCHIVE_HEIGHT } from '../../constants.gen.js'; @@ -56,7 +57,7 @@ export class PrivateBaseRollupHints { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromBuffer(buffer: Buffer | BufferReader): PrivateBaseRollupHints { @@ -71,7 +72,7 @@ export class PrivateBaseRollupHints { } static fromString(str: string) { - return PrivateBaseRollupHints.fromBuffer(Buffer.from(str, 'hex')); + return PrivateBaseRollupHints.fromBuffer(hexToBuffer(str)); } static empty() { @@ -130,7 +131,7 @@ export class PublicBaseRollupHints { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromBuffer(buffer: Buffer | BufferReader): PublicBaseRollupHints { @@ -145,7 +146,7 @@ export class PublicBaseRollupHints { } static fromString(str: string) { - return PublicBaseRollupHints.fromBuffer(Buffer.from(str, 'hex')); + return PublicBaseRollupHints.fromBuffer(hexToBuffer(str)); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/rollup/block_merge_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/block_merge_rollup.ts index 6732a4ffadf..e134ad16ba0 100644 --- a/yarn-project/circuits.js/src/structs/rollup/block_merge_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/block_merge_rollup.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { PreviousRollupBlockData } from './previous_rollup_block_data.js'; @@ -27,7 +28,7 @@ export class BlockMergeRollupInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -49,16 +50,16 @@ export class BlockMergeRollupInputs { * @returns A new BlockMergeRollupInputs instance. */ static fromString(str: string) { - return BlockMergeRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return BlockMergeRollupInputs.fromBuffer(hexToBuffer(str)); } /** Returns a hex representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(BlockMergeRollupInputs); + return bufferSchemaFor(BlockMergeRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/block_root_or_block_merge_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/block_root_or_block_merge_public_inputs.ts index 639f335b760..00eeb3666a7 100644 --- a/yarn-project/circuits.js/src/structs/rollup/block_root_or_block_merge_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/block_root_or_block_merge_public_inputs.ts @@ -1,7 +1,8 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { AZTEC_MAX_EPOCH_DURATION } from '../../constants.gen.js'; @@ -107,7 +108,7 @@ export class BlockRootOrBlockMergePublicInputs { * @returns - The hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -116,17 +117,17 @@ export class BlockRootOrBlockMergePublicInputs { * @returns A new BaseOrMergeRollupPublicInputs instance. */ static fromString(str: string) { - return BlockRootOrBlockMergePublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return BlockRootOrBlockMergePublicInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(BlockRootOrBlockMergePublicInputs); + return bufferSchemaFor(BlockRootOrBlockMergePublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/block_root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/block_root_rollup.ts index 3a63c40ddb3..18c1c289cb2 100644 --- a/yarn-project/circuits.js/src/structs/rollup/block_root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/block_root_rollup.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { @@ -69,7 +70,7 @@ export class BlockRootRollupInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -126,16 +127,16 @@ export class BlockRootRollupInputs { * @returns A new RootRollupInputs instance. */ static fromString(str: string) { - return BlockRootRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return BlockRootRollupInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(BlockRootRollupInputs); + return bufferSchemaFor(BlockRootRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/empty_block_root_rollup_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/empty_block_root_rollup_inputs.ts index ba42802e1ae..f4355e835a7 100644 --- a/yarn-project/circuits.js/src/structs/rollup/empty_block_root_rollup_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/empty_block_root_rollup_inputs.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { GlobalVariables } from '../global_variables.js'; @@ -33,7 +34,7 @@ export class EmptyBlockRootRollupInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -84,16 +85,16 @@ export class EmptyBlockRootRollupInputs { * @returns A new RootRollupInputs instance. */ static fromString(str: string) { - return EmptyBlockRootRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return EmptyBlockRootRollupInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } - /** Creates an instance from a hex string. */ + /** Creates an instance from a buffer string. */ static get schema() { - return hexSchemaFor(EmptyBlockRootRollupInputs); + return bufferSchemaFor(EmptyBlockRootRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/merge_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/merge_rollup.ts index 2950f2f1614..2b38a5f6188 100644 --- a/yarn-project/circuits.js/src/structs/rollup/merge_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/merge_rollup.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { PreviousRollupData } from './previous_rollup_data.js'; @@ -27,7 +28,7 @@ export class MergeRollupInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -46,16 +47,16 @@ export class MergeRollupInputs { * @returns A new MergeRollupInputs instance. */ static fromString(str: string) { - return MergeRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return MergeRollupInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } - /** Creates an instance from a hex string. */ + /** Creates an instance from a string. */ static get schema() { - return hexSchemaFor(MergeRollupInputs); + return bufferSchemaFor(MergeRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/private_base_rollup_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/private_base_rollup_inputs.ts index 1d354861e1a..a83a6655e28 100644 --- a/yarn-project/circuits.js/src/structs/rollup/private_base_rollup_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/private_base_rollup_inputs.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { PrivateBaseRollupHints } from './base_rollup_hints.js'; @@ -26,24 +27,24 @@ export class PrivateBaseRollupInputs { } static fromString(str: string) { - return PrivateBaseRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return PrivateBaseRollupInputs.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static empty() { return new PrivateBaseRollupInputs(PrivateTubeData.empty(), PrivateBaseRollupHints.empty()); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a buffer representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(PrivateBaseRollupInputs); + return bufferSchemaFor(PrivateBaseRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/public_base_rollup_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/public_base_rollup_inputs.ts index 1fa11ed3688..2bf644f4b81 100644 --- a/yarn-project/circuits.js/src/structs/rollup/public_base_rollup_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/public_base_rollup_inputs.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { AvmProofData } from './avm_proof_data.js'; @@ -33,25 +34,26 @@ export class PublicBaseRollupInputs { toBuffer() { return serializeToBuffer(...PublicBaseRollupInputs.getFields(this)); } + static fromString(str: string) { - return PublicBaseRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return PublicBaseRollupInputs.fromBuffer(hexToBuffer(str)); } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static empty() { return new PublicBaseRollupInputs(PublicTubeData.empty(), AvmProofData.empty(), PublicBaseRollupHints.empty()); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } - /** Creates an instance from a hex string. */ + /** Creates an instance from a string. */ static get schema() { - return hexSchemaFor(PublicBaseRollupInputs); + return bufferSchemaFor(PublicBaseRollupInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index a8eb8b433e5..180bfbdcc30 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, type Tuple, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { AZTEC_MAX_EPOCH_DURATION } from '../../constants.gen.js'; @@ -36,7 +37,7 @@ export class RootRollupInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -76,17 +77,17 @@ export class RootRollupInputs { * @returns A new RootRollupInputs instance. */ static fromString(str: string) { - return RootRollupInputs.fromBuffer(Buffer.from(str, 'hex')); + return RootRollupInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } - /** Creates an instance from a hex string. */ + /** Creates an instance from a string. */ static get schema() { - return hexSchemaFor(RootRollupInputs); + return bufferSchemaFor(RootRollupInputs); } } @@ -163,20 +164,20 @@ export class RootRollupPublicInputs { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(str: string) { - return RootRollupPublicInputs.fromBuffer(Buffer.from(str, 'hex')); + return RootRollupPublicInputs.fromBuffer(hexToBuffer(str)); } - /** Returns a hex representation for JSON serialization. */ + /** Returns a representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } - /** Creates an instance from a hex string. */ + /** Creates an instance from a string. */ static get schema() { - return hexSchemaFor(RootRollupPublicInputs); + return bufferSchemaFor(RootRollupPublicInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/tube_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/tube_inputs.ts index 0320d0ec228..86a58efbaf8 100644 --- a/yarn-project/circuits.js/src/structs/rollup/tube_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/tube_inputs.ts @@ -1,5 +1,6 @@ -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { ClientIvcProof } from '../client_ivc_proof.js'; @@ -28,7 +29,7 @@ export class TubeInputs { * @returns The instance serialized to a hex string. */ toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** @@ -50,7 +51,7 @@ export class TubeInputs { * @returns A new TubeInputs instance. */ static fromString(str: string) { - return TubeInputs.fromBuffer(Buffer.from(str, 'hex')); + return TubeInputs.fromBuffer(hexToBuffer(str)); } static empty() { @@ -59,11 +60,11 @@ export class TubeInputs { /** Returns a hex representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(TubeInputs); + return bufferSchemaFor(TubeInputs); } } diff --git a/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts b/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts index 4113649893d..2d2279b8c88 100644 --- a/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts +++ b/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts @@ -1,5 +1,6 @@ import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { MaxBlockNumber } from './max_block_number.js'; @@ -23,7 +24,7 @@ export class RollupValidationRequests { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromFields(fields: Fr[] | FieldReader) { @@ -47,7 +48,7 @@ export class RollupValidationRequests { * @returns Deserialized object. */ static fromString(str: string) { - return RollupValidationRequests.fromBuffer(Buffer.from(str, 'hex')); + return RollupValidationRequests.fromBuffer(hexToBuffer(str)); } static empty() { diff --git a/yarn-project/circuits.js/src/structs/shared.ts b/yarn-project/circuits.js/src/structs/shared.ts index c8cce1576fe..ae40dd95953 100644 --- a/yarn-project/circuits.js/src/structs/shared.ts +++ b/yarn-project/circuits.js/src/structs/shared.ts @@ -43,8 +43,3 @@ export enum RollupTypes { Merge = 1, Root = 2, } - -/** - * String encoding of serialized buffer data - */ -export const STRING_ENCODING: BufferEncoding = 'hex'; diff --git a/yarn-project/circuits.js/src/structs/state_reference.ts b/yarn-project/circuits.js/src/structs/state_reference.ts index 8f0c1fd0be0..49e91ac5324 100644 --- a/yarn-project/circuits.js/src/structs/state_reference.ts +++ b/yarn-project/circuits.js/src/structs/state_reference.ts @@ -19,10 +19,6 @@ export class StateReference { public partial: PartialStateReference, ) {} - toJSON() { - return { l1ToL2MessageTree: this.l1ToL2MessageTree, partial: this.partial }; - } - static get schema() { return z .object({ diff --git a/yarn-project/circuits.js/src/structs/trees/nullifier_leaf.ts b/yarn-project/circuits.js/src/structs/trees/nullifier_leaf.ts index 8d561e1ebfb..52b8be14aec 100644 --- a/yarn-project/circuits.js/src/structs/trees/nullifier_leaf.ts +++ b/yarn-project/circuits.js/src/structs/trees/nullifier_leaf.ts @@ -38,14 +38,6 @@ export class NullifierLeafPreimage implements IndexedTreeLeafPreimage { ); } - toJSON() { - return { - nullifier: this.nullifier.toString(), - nextNullifier: this.nextNullifier.toString(), - nextIndex: '0x' + this.nextIndex.toString(16), - }; - } - getKey(): bigint { return this.nullifier.toBigInt(); } @@ -102,14 +94,6 @@ export class NullifierLeafPreimage implements IndexedTreeLeafPreimage { static clone(preimage: NullifierLeafPreimage): NullifierLeafPreimage { return new NullifierLeafPreimage(preimage.nullifier, preimage.nextNullifier, preimage.nextIndex); } - - static fromJSON(json: any): NullifierLeafPreimage { - return new NullifierLeafPreimage( - Fr.fromString(json.nullifier), - Fr.fromString(json.nextNullifier), - BigInt(json.nextIndex), - ); - } } /** diff --git a/yarn-project/circuits.js/src/structs/tx_context.ts b/yarn-project/circuits.js/src/structs/tx_context.ts index 526ff0860ef..33234b4417a 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.ts @@ -37,14 +37,6 @@ export class TxContext { .transform(TxContext.from); } - toJSON() { - return { - chainId: this.chainId, - version: this.version, - gasSettings: this.gasSettings, - }; - } - getSize() { return this.chainId.size + this.version.size + this.gasSettings.getSize(); } diff --git a/yarn-project/circuits.js/src/structs/verification_key.ts b/yarn-project/circuits.js/src/structs/verification_key.ts index 22aa2d68e04..f3fc4a27610 100644 --- a/yarn-project/circuits.js/src/structs/verification_key.ts +++ b/yarn-project/circuits.js/src/structs/verification_key.ts @@ -1,8 +1,9 @@ import { makeTuple } from '@aztec/foundation/array'; import { times } from '@aztec/foundation/collection'; import { Fq, Fr } from '@aztec/foundation/fields'; -import { hexSchemaFor } from '@aztec/foundation/schemas'; +import { bufferSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { HONK_VERIFICATION_KEY_LENGTH_IN_FIELDS } from '../constants.gen.js'; import { CircuitType } from './shared.js'; @@ -100,11 +101,11 @@ export class VerificationKeyAsFields { static get schema() { // TODO(palla/schemas): Should we verify the hash matches the key when deserializing? - return hexSchemaFor(VerificationKeyAsFields); + return bufferSchemaFor(VerificationKeyAsFields); } toJSON() { - return '0x' + this.toBuffer().toString('hex'); + return this.toBuffer(); } /** @@ -261,7 +262,7 @@ export class VerificationKeyData { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromBuffer(buffer: Buffer | BufferReader): VerificationKeyData { @@ -273,7 +274,7 @@ export class VerificationKeyData { } static fromString(str: string): VerificationKeyData { - return VerificationKeyData.fromBuffer(Buffer.from(str, 'hex')); + return VerificationKeyData.fromBuffer(hexToBuffer(str)); } public clone() { @@ -282,11 +283,11 @@ export class VerificationKeyData { /** Returns a hex representation for JSON serialization. */ toJSON() { - return this.toString(); + return this.toBuffer(); } /** Creates an instance from a hex string. */ static get schema() { - return hexSchemaFor(VerificationKeyData); + return bufferSchemaFor(VerificationKeyData); } } diff --git a/yarn-project/circuits.js/src/structs/vk_witness_data.ts b/yarn-project/circuits.js/src/structs/vk_witness_data.ts index 723475b5fa2..90e2239cd65 100644 --- a/yarn-project/circuits.js/src/structs/vk_witness_data.ts +++ b/yarn-project/circuits.js/src/structs/vk_witness_data.ts @@ -1,6 +1,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex } from '@aztec/foundation/string'; import { VK_TREE_HEIGHT } from '../constants.gen.js'; import { type UInt32 } from './shared.js'; @@ -37,6 +38,6 @@ export class VkWitnessData { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } } diff --git a/yarn-project/circuits.js/src/types/public_keys.ts b/yarn-project/circuits.js/src/types/public_keys.ts index 321fc04c7a3..d426ab2f3b8 100644 --- a/yarn-project/circuits.js/src/types/public_keys.ts +++ b/yarn-project/circuits.js/src/types/public_keys.ts @@ -2,6 +2,7 @@ import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr, Point } from '@aztec/foundation/fields'; import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { bufferToHex } from '@aztec/foundation/string'; import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; @@ -184,7 +185,7 @@ export class PublicKeys { } toString() { - return this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } static fromString(keys: string) { diff --git a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts index c0fb4812f77..2d6ae924075 100644 --- a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts +++ b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts @@ -45,7 +45,7 @@ export async function cancelTx( log(` Tx fee: ${cancelReceipt.transactionFee}`); log(` Status: ${cancelReceipt.status}`); log(` Block number: ${cancelReceipt.blockNumber}`); - log(` Block hash: ${cancelReceipt.blockHash?.toString('hex')}`); + log(` Block hash: ${cancelReceipt.blockHash?.toString()}`); } catch (err: any) { log(`Could not cancel transaction\n ${err.message}`); } diff --git a/yarn-project/cli-wallet/src/cmds/send.ts b/yarn-project/cli-wallet/src/cmds/send.ts index fa6af43fa93..b87097ec125 100644 --- a/yarn-project/cli-wallet/src/cmds/send.ts +++ b/yarn-project/cli-wallet/src/cmds/send.ts @@ -42,7 +42,7 @@ export async function send( log(` Tx fee: ${receipt.transactionFee}`); log(` Status: ${receipt.status}`); log(` Block number: ${receipt.blockNumber}`); - log(` Block hash: ${receipt.blockHash?.toString('hex')}`); + log(` Block hash: ${receipt.blockHash?.toString()}`); } catch (err: any) { log(`Transaction failed\n ${err.message}`); } diff --git a/yarn-project/cli/src/cmds/infrastructure/setup_protocol_contract.ts b/yarn-project/cli/src/cmds/infrastructure/setup_protocol_contract.ts index 113bfea6a09..a7473487d31 100644 --- a/yarn-project/cli/src/cmds/infrastructure/setup_protocol_contract.ts +++ b/yarn-project/cli/src/cmds/infrastructure/setup_protocol_contract.ts @@ -1,5 +1,6 @@ import { SignerlessWallet, type WaitOpts, createPXEClient, makeFetch } from '@aztec/aztec.js'; import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { type LogFn } from '@aztec/foundation/log'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; @@ -18,7 +19,7 @@ export async function setupProtocolContracts( proven: !skipProofWait, provenTimeout: 600, }; - log('setupProtocolContracts: Wait options' + JSON.stringify(waitOpts)); + log('setupProtocolContracts: Wait options' + jsonStringify(waitOpts)); log('setupProtocolContracts: Creating PXE client...'); const pxe = createPXEClient(rpcUrl, makeFetch([1, 1, 1, 1, 1], false)); const wallet = new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(l1ChainId, 1)); diff --git a/yarn-project/cli/src/cmds/pxe/get_current_base_fee.ts b/yarn-project/cli/src/cmds/pxe/get_current_base_fee.ts index 1d64ad585f2..c736a4766b6 100644 --- a/yarn-project/cli/src/cmds/pxe/get_current_base_fee.ts +++ b/yarn-project/cli/src/cmds/pxe/get_current_base_fee.ts @@ -1,8 +1,9 @@ import { createCompatibleClient } from '@aztec/aztec.js'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { type DebugLogger, type LogFn } from '@aztec/foundation/log'; export async function getCurrentBaseFee(rpcUrl: string, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); const fees = await client.getCurrentBaseFees(); - log(`Current fees: ${JSON.stringify(fees.toJSON())}`); + log(`Current fees: ${jsonStringify(fees)}`); } diff --git a/yarn-project/cli/src/utils/inspect.ts b/yarn-project/cli/src/utils/inspect.ts index 855c38b9ef5..77d6c067a7e 100644 --- a/yarn-project/cli/src/utils/inspect.ts +++ b/yarn-project/cli/src/utils/inspect.ts @@ -58,7 +58,7 @@ export async function inspectTx( const artifactMap = opts?.artifactMap ?? (await getKnownArtifacts(pxe)); if (opts.includeBlockInfo) { - log(` Block: ${receipt.blockNumber} (${receipt.blockHash?.toString('hex')})`); + log(` Block: ${receipt.blockNumber} (${receipt.blockHash?.toString()})`); } if (receipt.transactionFee) { log(` Fee: ${receipt.transactionFee.toString()}`); diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index dcacb4ca441..664f920873d 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -242,7 +242,7 @@ describe('e2e_fees failures', () => { }, }) .wait(), - ).rejects.toThrow(/Transaction [0-9a-f]{64} was dropped\. Reason: Tx dropped by P2P node\./); + ).rejects.toThrow(/Transaction (0x)?[0-9a-fA-F]{64} was dropped\. Reason: Tx dropped by P2P node\./); }); it('includes transaction that error in teardown', async () => { diff --git a/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts b/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts index 15e77e4e775..e2d230a40a2 100644 --- a/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts +++ b/yarn-project/end-to-end/src/e2e_prover/e2e_prover_test.ts @@ -253,7 +253,7 @@ export class FullProverTest { // The simulated prover node (now shutdown) used private key index 2 const proverNodePrivateKey = getPrivateKeyFromIndex(2); - const proverNodeSenderAddress = privateKeyToAddress(new Buffer32(proverNodePrivateKey!).to0xString()); + const proverNodeSenderAddress = privateKeyToAddress(new Buffer32(proverNodePrivateKey!).toString()); this.proverAddress = EthAddress.fromString(proverNodeSenderAddress); this.logger.verbose(`Funding prover node at ${proverNodeSenderAddress}`); diff --git a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts index 3a85d0ff79b..6f58a48dda6 100644 --- a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts +++ b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts @@ -368,7 +368,7 @@ async function setupFromFresh( const cheatCodes = await CheatCodes.create(aztecNodeConfig.l1RpcUrl, pxe); if (statePath) { - writeFileSync(`${statePath}/aztec_node_config.json`, JSON.stringify(aztecNodeConfig)); + writeFileSync(`${statePath}/aztec_node_config.json`, JSON.stringify(aztecNodeConfig, resolver)); } return { @@ -497,7 +497,7 @@ export const addAccounts = logger.verbose('Account deployment tx hashes:'); for (const provenTx of provenTxs) { - logger.verbose(provenTx.getTxHash().to0xString()); + logger.verbose(provenTx.getTxHash().toString()); } logger.verbose('Deploying accounts...'); diff --git a/yarn-project/end-to-end/src/prover-coordination/e2e_prover_coordination.test.ts b/yarn-project/end-to-end/src/prover-coordination/e2e_prover_coordination.test.ts index 665abe523dc..6ec6832ff53 100644 --- a/yarn-project/end-to-end/src/prover-coordination/e2e_prover_coordination.test.ts +++ b/yarn-project/end-to-end/src/prover-coordination/e2e_prover_coordination.test.ts @@ -112,7 +112,7 @@ describe('e2e_prover_coordination', () => { const proverKey = Buffer32.random(); proverSigner = new Secp256k1Signer(proverKey); proverWallet = createWalletClient({ - account: privateKeyToAccount(proverKey.to0xString()), + account: privateKeyToAccount(proverKey.toString()), chain: foundry, transport: http(ctx.aztecNodeConfig.l1RpcUrl), }); diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index 2f13d6ab67a..4ba09fb11a9 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -230,7 +230,7 @@ export interface FunctionArtifact extends FunctionAbi { export const FunctionArtifactSchema = FunctionAbiSchema.and( z.object({ - bytecode: schemas.BufferB64, + bytecode: schemas.Buffer, verificationKey: z.string().optional(), debugSymbols: z.string(), debug: FunctionDebugMetadataSchema.optional(), diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index 0f1e6841cba..0b901d030ef 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -1,7 +1,7 @@ import { AztecAddress } from '../aztec-address/index.js'; import { Fr } from '../fields/fields.js'; import { Point } from '../fields/point.js'; -import { jsonParseWithSchema } from '../json-rpc/convert.js'; +import { jsonParseWithSchema, jsonStringify } from '../json-rpc/convert.js'; import { schemas } from '../schemas/schemas.js'; import { type FunctionAbi, FunctionType } from './abi.js'; import { encodeArguments } from './encoder.js'; @@ -30,7 +30,7 @@ describe('abi/encoder', () => { const field = Fr.random(); expect(encodeArguments(abi, [field])).toEqual([field]); - const serializedField = jsonParseWithSchema(JSON.stringify(field), schemas.Fr); + const serializedField = jsonParseWithSchema(jsonStringify(field), schemas.Fr); expect(encodeArguments(abi, [serializedField])).toEqual([field]); }); @@ -122,7 +122,7 @@ describe('abi/encoder', () => { const completeAddressLike = { address, publicKey: Point.random(), partialAddress: Fr.random() }; expect(encodeArguments(abi, [completeAddressLike])).toEqual([address.toField()]); - const serializedAddress = jsonParseWithSchema(JSON.stringify(address), schemas.AztecAddress); + const serializedAddress = jsonParseWithSchema(jsonStringify(address), schemas.AztecAddress); expect(encodeArguments(abi, [serializedAddress])).toEqual([address.toField()]); }); diff --git a/yarn-project/foundation/src/abi/event_selector.ts b/yarn-project/foundation/src/abi/event_selector.ts index ea4d8bd234c..0203d562380 100644 --- a/yarn-project/foundation/src/abi/event_selector.ts +++ b/yarn-project/foundation/src/abi/event_selector.ts @@ -1,6 +1,7 @@ import { fromHex, toBigIntBE } from '../bigint-buffer/index.js'; import { poseidon2HashBytes, randomBytes } from '../crypto/index.js'; import { type Fr } from '../fields/fields.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader } from '../serialize/buffer_reader.js'; import { Selector } from './selector.js'; @@ -83,9 +84,10 @@ export class EventSelector extends Selector { } toJSON() { - return { - type: 'EventSelector', - value: this.toString(), - }; + return this.toString(); + } + + static get schema() { + return hexSchemaFor(EventSelector); } } diff --git a/yarn-project/foundation/src/abi/function_selector.ts b/yarn-project/foundation/src/abi/function_selector.ts index 7641234f9ab..00b75d1b500 100644 --- a/yarn-project/foundation/src/abi/function_selector.ts +++ b/yarn-project/foundation/src/abi/function_selector.ts @@ -1,6 +1,7 @@ import { fromHex, toBigIntBE } from '../bigint-buffer/index.js'; import { poseidon2HashBytes, randomBytes } from '../crypto/index.js'; import { type Fr } from '../fields/fields.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader } from '../serialize/buffer_reader.js'; import { FieldReader } from '../serialize/field_reader.js'; import { TypeRegistry } from '../serialize/type_registry.js'; @@ -132,10 +133,11 @@ export class FunctionSelector extends Selector { } toJSON() { - return { - type: 'FunctionSelector', - value: this.toString(), - }; + return this.toString(); + } + + static get schema() { + return hexSchemaFor(FunctionSelector); } } diff --git a/yarn-project/foundation/src/abi/note_selector.ts b/yarn-project/foundation/src/abi/note_selector.ts index 8fdcaa945c3..10f784620f1 100644 --- a/yarn-project/foundation/src/abi/note_selector.ts +++ b/yarn-project/foundation/src/abi/note_selector.ts @@ -1,6 +1,7 @@ import { toBigIntBE } from '../bigint-buffer/index.js'; import { randomBytes } from '../crypto/index.js'; import { type Fr } from '../fields/fields.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader } from '../serialize/buffer_reader.js'; import { TypeRegistry } from '../serialize/type_registry.js'; import { Selector } from './selector.js'; @@ -58,14 +59,11 @@ export class NoteSelector extends Selector { } toJSON() { - return { - type: 'NoteSelector', - value: this.toString(), - }; + return this.toString(); } - static fromJSON(json: any): NoteSelector { - return NoteSelector.fromString(json.value); + static get schema() { + return hexSchemaFor(NoteSelector); } } diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index e8f56e01093..9ee416654b3 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -2,6 +2,7 @@ import { inspect } from 'util'; import { toBufferBE } from '../bigint-buffer/index.js'; import { Fr } from '../fields/index.js'; +import { bufferToHex } from '../string/index.js'; /** A selector is the first 4 bytes of the hash of a signature. */ export abstract class Selector { @@ -36,7 +37,7 @@ export abstract class Selector { * @returns The string. */ toString(): string { - return '0x' + this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } [inspect.custom]() { diff --git a/yarn-project/foundation/src/aztec-address/index.ts b/yarn-project/foundation/src/aztec-address/index.ts index d58fd9b0d77..fe965da95e1 100644 --- a/yarn-project/foundation/src/aztec-address/index.ts +++ b/yarn-project/foundation/src/aztec-address/index.ts @@ -2,6 +2,7 @@ import { inspect } from 'util'; import { Fr, Point, fromBuffer } from '../fields/index.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { type BufferReader, FieldReader } from '../serialize/index.js'; import { TypeRegistry } from '../serialize/type_registry.js'; import { hexToBuffer } from '../string/index.js'; @@ -133,10 +134,11 @@ export class AztecAddress { } toJSON() { - return { - type: 'AztecAddress', - value: this.toString(), - }; + return this.toString(); + } + + static get schema() { + return hexSchemaFor(AztecAddress, AztecAddress.isAddress); } } diff --git a/yarn-project/foundation/src/buffer/buffer32.ts b/yarn-project/foundation/src/buffer/buffer32.ts index 4b1c2e1c25d..799df3f27ec 100644 --- a/yarn-project/foundation/src/buffer/buffer32.ts +++ b/yarn-project/foundation/src/buffer/buffer32.ts @@ -2,6 +2,8 @@ import { randomBytes } from '@aztec/foundation/crypto'; import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, deserializeBigInt, serializeBigInt } from '@aztec/foundation/serialize'; +import { bufferToHex } from '../string/index.js'; + /** * A class representing a 32 byte Buffer. */ @@ -67,17 +69,13 @@ export class Buffer32 { * @returns The hex string. */ public toString() { - return this.buffer.toString('hex'); + return bufferToHex(this.buffer); } toJSON() { return this.toString(); } - public to0xString(): `0x${string}` { - return `0x${this.buffer.toString('hex')}`; - } - /** * Convert this hash to a big int. * @returns The big int. @@ -117,18 +115,6 @@ export class Buffer32 { * @param str - The TX hash in string format. * @returns A new Buffer32 object. */ - public static fromStringUnchecked(str: string): Buffer32 { - return new Buffer32(Buffer.from(str, 'hex')); - } - - /** - * Converts a string into a Buffer32 object. - * NOTE: this method includes checks for the 0x prefix and the length of the string. - * if you dont need this checks, use fromStringUnchecked instead. - * - * @param str - The TX hash in string format. - * @returns A new Buffer32 object. - */ public static fromString(str: string): Buffer32 { if (str.startsWith('0x')) { str = str.slice(2); diff --git a/yarn-project/foundation/src/crypto/secp256k1-signer/secp256k1_signer.test.ts b/yarn-project/foundation/src/crypto/secp256k1-signer/secp256k1_signer.test.ts index 707227208f2..05c9d12fdc7 100644 --- a/yarn-project/foundation/src/crypto/secp256k1-signer/secp256k1_signer.test.ts +++ b/yarn-project/foundation/src/crypto/secp256k1-signer/secp256k1_signer.test.ts @@ -31,13 +31,13 @@ describe('Secp256k1Signer', () => { const ethHashedMessage = hashMessage({ raw: message }); const ethHashedMessageBuffer = Buffer32.fromBuffer(Buffer.from(ethHashedMessage.slice(2), 'hex')); - const viemSignature = Signature.from0xString(await viemSigner.signMessage({ message: { raw: message } })); + const viemSignature = Signature.fromString(await viemSigner.signMessage({ message: { raw: message } })); const lightSignature = lightSigner.sign(ethHashedMessageBuffer); // Check signatures match expect(viemSignature.equals(lightSignature)).toBe(true); - const viemPublicKey = await viemRecoverPublicKey({ hash: ethHashedMessage, signature: viemSignature.to0xString() }); + const viemPublicKey = await viemRecoverPublicKey({ hash: ethHashedMessage, signature: viemSignature.toString() }); const lightPublicKey = lightRecoverPublicKey(ethHashedMessageBuffer, lightSignature); // Check recovered public keys match @@ -46,7 +46,7 @@ describe('Secp256k1Signer', () => { // Get the eth address can be recovered from the message and signature const viemPublicKeyToAddress = publicKeyToAddress(viemPublicKey); const viemAddress = EthAddress.fromString( - await viemRecoverAddress({ hash: ethHashedMessage, signature: viemSignature.to0xString() }), + await viemRecoverAddress({ hash: ethHashedMessage, signature: viemSignature.toString() }), ); const lightAddress = lightRecoverAddress( Buffer32.fromBuffer(Buffer.from(ethHashedMessage.slice(2), 'hex')), diff --git a/yarn-project/foundation/src/eth-address/index.ts b/yarn-project/foundation/src/eth-address/index.ts index f30e61a0230..ed9acffbb5b 100644 --- a/yarn-project/foundation/src/eth-address/index.ts +++ b/yarn-project/foundation/src/eth-address/index.ts @@ -3,8 +3,10 @@ import { inspect } from 'util'; import { keccak256String } from '../crypto/keccak/index.js'; import { randomBytes } from '../crypto/random/index.js'; import { Fr } from '../fields/index.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader, FieldReader } from '../serialize/index.js'; import { TypeRegistry } from '../serialize/type_registry.js'; +import { bufferToHex } from '../string/index.js'; /** * Represents an Ethereum address as a 20-byte buffer and provides various utility methods @@ -154,7 +156,7 @@ export class EthAddress { * @returns A hex-encoded string representation of the Ethereum address. */ public toString() { - return `0x${this.buffer.toString('hex')}` as `0x${string}`; + return bufferToHex(this.buffer); } [inspect.custom]() { @@ -226,19 +228,12 @@ export class EthAddress { return new EthAddress(reader.readBytes(EthAddress.SIZE_IN_BYTES)); } - /** - * Friendly representation for debugging purposes. - * @returns A hex string representing the address. - */ - toFriendlyJSON() { + toJSON() { return this.toString(); } - toJSON() { - return { - type: 'EthAddress', - value: this.toString(), - }; + static get schema() { + return hexSchemaFor(EthAddress, EthAddress.isAddress); } } diff --git a/yarn-project/foundation/src/eth-signature/eth_signature.test.ts b/yarn-project/foundation/src/eth-signature/eth_signature.test.ts index 2a2fd690184..ec76be5b6fa 100644 --- a/yarn-project/foundation/src/eth-signature/eth_signature.test.ts +++ b/yarn-project/foundation/src/eth-signature/eth_signature.test.ts @@ -25,15 +25,15 @@ describe('eth signature', () => { expect(deserialized).toEqual(serialized); }; - it('should serialize / deserialize to buffer', () => { + it('should serialize and deserialize to buffer', () => { const serialized = signature.toBuffer(); const deserialized = Signature.fromBuffer(serialized); checkEquivalence(signature, deserialized); }); - it('should serialize / deserialize real signature to hex string', () => { - const serialized = signature.to0xString(); - const deserialized = Signature.from0xString(serialized); + it('should serialize and deserialize real signature to hex string', () => { + const serialized = signature.toString(); + const deserialized = Signature.fromString(serialized); checkEquivalence(signature, deserialized); }); @@ -42,24 +42,24 @@ describe('eth signature', () => { expect(sender).toEqual(signer.address); }); - it('should serialize / deserialize to hex string with v=0', () => { + it('should serialize and deserialize to hex string with v=0', () => { const signature = new Signature(Buffer32.random(), Buffer32.random(), 0, false); - const serialized = signature.to0xString(); - const deserialized = Signature.from0xString(serialized); + const serialized = signature.toString(); + const deserialized = Signature.fromString(serialized); checkEquivalence(signature, deserialized); }); - it('should serialize / deserialize to hex string with 1-digit v', () => { + it('should serialize and deserialize to hex string with 1-digit v', () => { const signature = new Signature(Buffer32.random(), Buffer32.random(), 1, false); - const serialized = signature.to0xString(); - const deserialized = Signature.from0xString(serialized); + const serialized = signature.toString(); + const deserialized = Signature.fromString(serialized); checkEquivalence(signature, deserialized); }); - it('should serialize / deserialize to hex string with 2-digit v', () => { + it('should serialize and deserialize to hex string with 2-digit v', () => { const signature = new Signature(Buffer32.random(), Buffer32.random(), 26, false); - const serialized = signature.to0xString(); - const deserialized = Signature.from0xString(serialized); + const serialized = signature.toString(); + const deserialized = Signature.fromString(serialized); checkEquivalence(signature, deserialized); }); }); diff --git a/yarn-project/foundation/src/eth-signature/eth_signature.ts b/yarn-project/foundation/src/eth-signature/eth_signature.ts index 521cf680e9e..dec046702d0 100644 --- a/yarn-project/foundation/src/eth-signature/eth_signature.ts +++ b/yarn-project/foundation/src/eth-signature/eth_signature.ts @@ -1,6 +1,10 @@ import { Buffer32 } from '@aztec/foundation/buffer'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { z } from 'zod'; + +import { hasHexPrefix, hexToBuffer } from '../string/index.js'; + /**Viem Signature * * A version of the Signature class that uses `0x${string}` values for r and s rather than @@ -45,7 +49,7 @@ export class Signature { return new Signature(r, s, v, isEmpty); } - static isValid0xString(sig: `0x${string}`): boolean { + static isValidString(sig: `0x${string}`): boolean { return /^0x[0-9a-f]{129,}$/i.test(sig); } @@ -54,10 +58,9 @@ export class Signature { * parsing from viem, we can expect the v value to be a u8, rather than our * default serialization of u32 */ - static from0xString(sig: `0x${string}`): Signature { - const buf = Buffer.from(sig.slice(2), 'hex'); + static fromString(sig: `0x${string}`): Signature { + const buf = hexToBuffer(sig); const reader = BufferReader.asReader(buf); - const r = reader.readObject(Buffer32); const s = reader.readObject(Buffer32); const v = parseInt(sig.slice(2 + 64 * 2), 16); @@ -95,8 +98,8 @@ export class Signature { return this.size; } - to0xString(): `0x${string}` { - return `0x${this.r.toString()}${this.s.toString()}${this.v.toString(16)}`; + toString(): `0x${string}` { + return `0x${this.r.buffer.toString('hex')}${this.s.buffer.toString('hex')}${this.v.toString(16)}`; } /** @@ -104,14 +107,22 @@ export class Signature { */ toViemSignature(): ViemSignature { return { - r: this.r.to0xString(), - s: this.s.to0xString(), + r: this.r.toString(), + s: this.s.toString(), v: this.v, isEmpty: this.isEmpty, }; } toJSON() { - return this.to0xString(); + return this.toString(); + } + + static get schema() { + return z + .string() + .refine(hasHexPrefix, 'No hex prefix') + .refine(Signature.isValidString, 'Not a valid Ethereum signature') + .transform(Signature.fromString); } } diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 4653d0eeee8..84b559c4f3c 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -4,6 +4,7 @@ import { inspect } from 'util'; import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; import { randomBytes } from '../crypto/random/index.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader } from '../serialize/buffer_reader.js'; import { TypeRegistry } from '../serialize/type_registry.js'; @@ -300,12 +301,12 @@ export class Fr extends BaseField { return Fr.fromBuffer(rootBuf); } - // TODO(palla/schemas): Use toString instead of structured type toJSON() { - return { - type: 'Fr', - value: this.toString(), - }; + return this.toString(); + } + + static get schema() { + return hexSchemaFor(Fr); } } @@ -385,10 +386,11 @@ export class Fq extends BaseField { } toJSON() { - return { - type: 'Fq', - value: this.toString(), - }; + return this.toString(); + } + + static get schema() { + return hexSchemaFor(Fq); } } diff --git a/yarn-project/foundation/src/fields/point.test.ts b/yarn-project/foundation/src/fields/point.test.ts index f2b4813683a..f98771fb5c0 100644 --- a/yarn-project/foundation/src/fields/point.test.ts +++ b/yarn-project/foundation/src/fields/point.test.ts @@ -1,3 +1,4 @@ +import { jsonParseWithSchema, jsonStringify } from '../json-rpc/convert.js'; import { schemas } from '../schemas/schemas.js'; import { updateInlineTestData } from '../testing/test_data.js'; import { Fr } from './fields.js'; @@ -93,7 +94,7 @@ describe('Point', () => { it('serializes from and to JSON', () => { const p = Point.random(); - const p2 = schemas.Point.parse(JSON.parse(JSON.stringify(p))); + const p2 = jsonParseWithSchema(jsonStringify(p), schemas.Point); expect(p).toEqual(p2); expect(p2).toBeInstanceOf(Point); }); diff --git a/yarn-project/foundation/src/fields/point.ts b/yarn-project/foundation/src/fields/point.ts index bfe1adcb3e7..96135f47b50 100644 --- a/yarn-project/foundation/src/fields/point.ts +++ b/yarn-project/foundation/src/fields/point.ts @@ -1,7 +1,9 @@ import { toBigIntBE } from '../bigint-buffer/index.js'; import { poseidon2Hash } from '../crypto/poseidon/index.js'; import { randomBoolean } from '../crypto/random/index.js'; +import { hexSchemaFor } from '../schemas/utils.js'; import { BufferReader, FieldReader, serializeToBuffer } from '../serialize/index.js'; +import { bufferToHex, hexToBuffer } from '../string/index.js'; import { Fr } from './fields.js'; /** @@ -34,6 +36,14 @@ export class Point { // TODO(#7386): check if on curve } + toJSON() { + return this.toString(); + } + + static get schema() { + return hexSchemaFor(Point); + } + /** * Generate a random Point instance. * @@ -84,14 +94,14 @@ export class Point { /** * Create a Point instance from a hex-encoded string. - * The input 'address' should be prefixed with '0x' or not, and have exactly 128 hex characters representing the x and y coordinates. + * The input should be prefixed with '0x' or not, and have exactly 128 hex characters representing the x and y coordinates. * Throws an error if the input length is invalid or coordinate values are out of range. * - * @param address - The hex-encoded string representing the Point coordinates. + * @param str - The hex-encoded string representing the Point coordinates. * @returns A Point instance. */ - static fromString(address: string) { - return this.fromBuffer(Buffer.from(address.replace(/^0x/i, ''), 'hex')); + static fromString(str: string) { + return this.fromBuffer(hexToBuffer(str)); } /** @@ -211,7 +221,7 @@ export class Point { * @returns A hex-encoded string representing the Point instance. */ toString() { - return '0x' + this.toBuffer().toString('hex'); + return bufferToHex(this.toBuffer()); } /** diff --git a/yarn-project/foundation/src/json-rpc/client/fetch.ts b/yarn-project/foundation/src/json-rpc/client/fetch.ts index f93dce97f43..56773431b6d 100644 --- a/yarn-project/foundation/src/json-rpc/client/fetch.ts +++ b/yarn-project/foundation/src/json-rpc/client/fetch.ts @@ -1,4 +1,4 @@ -import { format } from 'util'; +import { format, inspect } from 'util'; import { type DebugLogger, createDebugLogger } from '../../log/index.js'; import { NoRetryError, makeBackoff, retry } from '../../retry/index.js'; @@ -25,18 +25,23 @@ export async function defaultFetch( ) { log.debug(format(`JsonRpcClient.fetch`, host, rpcMethod, '->', body)); let resp: Response; - if (useApiEndpoints) { - resp = await fetch(`${host}/${rpcMethod}`, { - method: 'POST', - body: jsonStringify(body), - headers: { 'content-type': 'application/json' }, - }); - } else { - resp = await fetch(host, { - method: 'POST', - body: jsonStringify({ ...body, method: rpcMethod }), - headers: { 'content-type': 'application/json' }, - }); + try { + if (useApiEndpoints) { + resp = await fetch(`${host}/${rpcMethod}`, { + method: 'POST', + body: jsonStringify(body), + headers: { 'content-type': 'application/json' }, + }); + } else { + resp = await fetch(host, { + method: 'POST', + body: jsonStringify({ ...body, method: rpcMethod }), + headers: { 'content-type': 'application/json' }, + }); + } + } catch (err) { + const errorMessage = `Error fetching from host ${host} with method ${rpcMethod}: ${inspect(err)}`; + throw new Error(errorMessage); } let responseJson; diff --git a/yarn-project/foundation/src/json-rpc/convert.test.ts b/yarn-project/foundation/src/json-rpc/convert.test.ts index b0817f765d4..98f06a0fb70 100644 --- a/yarn-project/foundation/src/json-rpc/convert.test.ts +++ b/yarn-project/foundation/src/json-rpc/convert.test.ts @@ -1,5 +1,6 @@ import { type ZodTypeAny, z } from 'zod'; +import { schemas } from '../schemas/schemas.js'; import { mapSchema, setSchema } from '../schemas/utils.js'; import { jsonStringify } from './convert.js'; @@ -9,27 +10,27 @@ describe('jsonStringify', () => { expect(schema.parse(JSON.parse(json))).toEqual(value); }; - it('object with primitive types', () => { + it('handles object with primitive types', () => { const values = { a: 10, b: 'foo', c: true }; test(values, z.object({ a: z.number(), b: z.string(), c: z.boolean() })); }); - it('object with bigints', () => { + it('handles object with bigints', () => { const values = { a: 10n }; test(values, z.object({ a: z.coerce.bigint() })); }); - it('tuples', () => { + it('handles tuples', () => { const values = [10, 'foo', true]; test(values, z.tuple([z.number(), z.string(), z.boolean()])); }); - it('arrays', () => { + it('handles arrays', () => { const values = [10, 20, 30]; test(values, z.array(z.number())); }); - it('maps', () => { + it('handles maps', () => { const values = new Map([ ['a', 10], ['b', 20], @@ -37,8 +38,21 @@ describe('jsonStringify', () => { test(values, mapSchema(z.string(), z.number())); }); - it('sets', () => { + it('handles sets', () => { const values = new Set([10, 20]); test(values, setSchema(z.number())); }); + + it('handles buffers', () => { + const value = Buffer.from('hello'); + const json = jsonStringify(value); + expect(json).toEqual('"aGVsbG8="'); + test(value, schemas.Buffer); + }); + + it('handles nullish', () => { + const values = [null, undefined]; + const json = jsonStringify(values); + expect(JSON.parse(json)).toEqual([null, null]); + }); }); diff --git a/yarn-project/foundation/src/json-rpc/convert.ts b/yarn-project/foundation/src/json-rpc/convert.ts index 8b040d74483..c518b3faa36 100644 --- a/yarn-project/foundation/src/json-rpc/convert.ts +++ b/yarn-project/foundation/src/json-rpc/convert.ts @@ -23,7 +23,9 @@ export function jsonStringify(obj: object, prettify?: boolean): string { (_key, value) => { if (typeof value === 'bigint') { return value.toString(); - } else if (typeof value === 'object' && Buffer.isBuffer(value)) { + } else if (typeof value === 'object' && value && value.type === 'Buffer' && Array.isArray(value.data)) { + return Buffer.from(value.data).toString('base64'); + } else if (typeof value === 'object' && value && Buffer.isBuffer(value)) { return value.toString('base64'); } else if (typeof value === 'object' && value instanceof Map) { return Array.from(value.entries()); diff --git a/yarn-project/foundation/src/json-rpc/index.ts b/yarn-project/foundation/src/json-rpc/index.ts index 2e33ff54f4e..8b918b16c74 100644 --- a/yarn-project/foundation/src/json-rpc/index.ts +++ b/yarn-project/foundation/src/json-rpc/index.ts @@ -1 +1 @@ -export { jsonStringify } from './convert.js'; +export { jsonStringify, jsonParseWithSchema, tryJsonStringify } from './convert.js'; diff --git a/yarn-project/foundation/src/schemas/schemas.ts b/yarn-project/foundation/src/schemas/schemas.ts index eca83d8bcd0..5677274d59c 100644 --- a/yarn-project/foundation/src/schemas/schemas.ts +++ b/yarn-project/foundation/src/schemas/schemas.ts @@ -7,65 +7,45 @@ import { NoteSelector } from '../abi/note_selector.js'; import { AztecAddress } from '../aztec-address/index.js'; import { Buffer32 } from '../buffer/buffer32.js'; import { EthAddress } from '../eth-address/index.js'; -import { Signature } from '../eth-signature/eth_signature.js'; import { Fq, Fr } from '../fields/fields.js'; import { Point } from '../fields/point.js'; -import { hasHexPrefix, isHex, withoutHexPrefix } from '../string/index.js'; +import { isHex, withoutHexPrefix } from '../string/index.js'; import { type ZodFor } from './types.js'; -import { hexSchema, maybeStructuredStringSchemaFor } from './utils.js'; - -const FrSchema = maybeStructuredStringSchemaFor('Fr', Fr, isHex); -const FqSchema = maybeStructuredStringSchemaFor('Fq', Fq, isHex); +import { bufferSchema, hexSchema } from './utils.js'; /** Validation schemas for common types. Every schema must match its toJSON. */ export const schemas = { - /** Accepts both a 0x string and a structured `{ type: EthAddress, value: '0x...' }` */ - EthAddress: maybeStructuredStringSchemaFor('EthAddress', EthAddress, EthAddress.isAddress), - - /** Accepts both a 0x string and a structured `{ type: AztecAddress, value: '0x...' }` */ - AztecAddress: maybeStructuredStringSchemaFor('AztecAddress', AztecAddress, AztecAddress.isAddress), + /** Accepts a hex string. */ + EthAddress: EthAddress.schema, - /** Accepts both a 0x string and a structured type. */ - FunctionSelector: maybeStructuredStringSchemaFor('FunctionSelector', FunctionSelector), + /** Accepts a hex string. */ + AztecAddress: AztecAddress.schema, - /** Accepts both a 0x string and a structured type. */ - NoteSelector: maybeStructuredStringSchemaFor('NoteSelector', NoteSelector), + /** Accepts a hex string. */ + FunctionSelector: FunctionSelector.schema, - /** Accepts both a 0x string and a structured type. */ - EventSelector: maybeStructuredStringSchemaFor('EventSelector', EventSelector), + /** Accepts a hex string. */ + NoteSelector: NoteSelector.schema, - /** Field element. Accepts a 0x prefixed hex string or a structured type. */ - Fr: FrSchema, + /** Accepts a hex string. */ + EventSelector: EventSelector.schema, - /** Field element. Accepts a 0x prefixed hex string or a structured type. */ - Fq: FqSchema, + /** Accepts a hex string. */ + Fr: Fr.schema, - /** Point. Serialized as 0x prefixed string or a type. */ - Point: z - .object({ - x: FrSchema, - y: FrSchema, - isInfinite: z.boolean().optional(), - }) - .or(hexSchema) - .transform(value => - typeof value === 'string' ? Point.fromString(value) : new Point(value.x, value.y, value.isInfinite ?? false), - ), + /** Accepts a hex string. */ + Fq: Fq.schema, - /** Accepts a 0x string */ - Signature: z - .string() - .refine(hasHexPrefix, 'No hex prefix') - .refine(Signature.isValid0xString, 'Not a valid Ethereum signature') - .transform(Signature.from0xString), + /** Point. Serialized as a hex string. */ + Point: Point.schema, - /** Coerces any input to bigint */ + /** Coerces any input to bigint. */ BigInt: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.bigint()), - /** Coerces any input to integer number */ + /** Coerces any input to integer number. */ Integer: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.number().int()), - /** Coerces input to UInt32 */ + /** Coerces input to UInt32. */ UInt32: z.union([z.bigint(), z.number(), z.string()]).pipe( z.coerce .number() @@ -74,31 +54,28 @@ export const schemas = { .max(2 ** 32 - 1), ), - /** Accepts a hex string as a Buffer32 type */ + /** Accepts a hex string as a Buffer32 type. */ Buffer32: z.string().refine(isHex, 'Not a valid hex string').transform(Buffer32.fromString), - /** Accepts a base64 string or a structured `{ type: 'Buffer', data: [byte, byte...] }` as a buffer */ - BufferB64: z.union([ - z - .string() - .base64() - .transform(data => Buffer.from(data, 'base64')), + /** Accepts a base64 string or an object `{ type: 'Buffer', data: [byte, byte...] }` as a buffer. */ + Buffer: z.union([ + bufferSchema, z .object({ type: z.literal('Buffer'), - data: z.array(z.number().int().max(255)), + data: z.array(z.number().int().min(0).max(255)), }) .transform(({ data }) => Buffer.from(data)), ]), - /** Accepts a hex string with optional 0x prefix as a buffer */ + /** Accepts a hex string as a buffer. */ BufferHex: z .string() .refine(isHex, 'Not a valid hex string') .transform(withoutHexPrefix) .transform(data => Buffer.from(data, 'hex')), - /** Hex string with an optional 0x prefix, which gets removed as part of the parsing */ + /** Hex string with an optional 0x prefix which gets removed as part of the parsing. */ HexString: hexSchema, }; diff --git a/yarn-project/foundation/src/schemas/utils.ts b/yarn-project/foundation/src/schemas/utils.ts index 412c49bc967..5e12c46848b 100644 --- a/yarn-project/foundation/src/schemas/utils.ts +++ b/yarn-project/foundation/src/schemas/utils.ts @@ -15,6 +15,17 @@ import { type ZodFor } from './types.js'; export const hexSchema = z.string().refine(isHex, 'Not a valid hex string').transform(withoutHexPrefix); +// Copied from zod internals, which was copied from https://stackoverflow.com/questions/7860392/determine-if-string-is-in-base64-using-javascript +const base64Regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; + +/** Schema for a buffer represented as a base64 string. */ +export const bufferSchema = z + .string() + // We only test the str for base64 if it's shorter than 1024 bytes, otherwise we've run into maximum + // stack size exceeded errors when trying to validate excessively long strings (such as contract bytecode). + .refine(str => str.length > 1024 || base64Regex.test(str), 'Not a valid base64 string') + .transform(data => Buffer.from(data, 'base64')); + export class ZodNullableOptional extends ZodOptional { _isNullableOptional = true; @@ -43,6 +54,8 @@ export function optional(schema: T) { return ZodNullableOptional.create(schema); } +type ToJsonIs = T extends { toJSON(): TRet } ? T : never; + /** * Creates a schema that accepts a hex string and uses it to hydrate an instance. * @param klazz - Class that implements either fromString or fromBuffer. @@ -50,28 +63,34 @@ export function optional(schema: T) { */ export function hexSchemaFor( klazz: TClass, + refinement?: (input: string) => boolean, ): ZodType< TClass extends { fromString(str: string): infer TInstance } | { fromBuffer(buf: Buffer): infer TInstance } - ? TInstance + ? ToJsonIs : never, any, string > { + const stringSchema = refinement ? z.string().refine(refinement, `Not a valid instance`) : z.string(); + const hexSchema = stringSchema.refine(isHex, 'Not a valid hex string').transform(withoutHexPrefix); return 'fromString' in klazz ? hexSchema.transform(klazz.fromString.bind(klazz)) : hexSchema.transform(str => Buffer.from(str, 'hex')).transform(klazz.fromBuffer.bind(klazz)); } -// TODO(palla/schemas): Delete this class once all serialization of the type { type: string, value: string } are removed. -export function maybeStructuredStringSchemaFor( - name: string, +/** + * Creates a schema that accepts a base64 string and uses it to hydrate an instance. + * @param klazz - Class that implements fromBuffer. + * @returns A schema for the class. + */ +export function bufferSchemaFor( klazz: TClass, - refinement?: (input: string) => boolean, -): ZodFor { - const stringSchema = refinement ? z.string().refine(refinement, `Not a valid ${name}`) : z.string(); - return z - .union([stringSchema, z.object({ type: z.literal(name), value: stringSchema })]) - .transform(input => klazz.fromString(typeof input === 'string' ? input : input.value)); +): ZodType< + TClass extends { fromBuffer(buf: Buffer): infer TInstance } ? ToJsonIs : never, + any, + string +> { + return bufferSchema.transform(klazz.fromBuffer.bind(klazz)); } /** Creates a schema for a js Map type that matches the serialization used in jsonStringify. */ diff --git a/yarn-project/foundation/src/serialize/type_registry.test.ts b/yarn-project/foundation/src/serialize/type_registry.test.ts new file mode 100644 index 00000000000..b77e96a837f --- /dev/null +++ b/yarn-project/foundation/src/serialize/type_registry.test.ts @@ -0,0 +1,90 @@ +import { EventSelector } from '../abi/event_selector.js'; +import { FunctionSelector } from '../abi/function_selector.js'; +import { NoteSelector } from '../abi/note_selector.js'; +import { AztecAddress } from '../aztec-address/index.js'; +import { EthAddress } from '../eth-address/index.js'; +import { Fq, Fr } from '../fields/fields.js'; +import { resolver, reviver } from './type_registry.js'; + +describe('TypeRegistry', () => { + it('serializes registered type with type info', () => { + const data = { fr: Fr.random() }; + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json); + expect(parsed.fr).toEqual({ type: 'Fr', value: data.fr.toString() }); + }); + + it('deserializes registered types in objects', () => { + const data = { + fr: Fr.random(), + fq: Fq.random(), + aztecAddress: AztecAddress.random(), + ethAddress: EthAddress.random(), + functionSelector: FunctionSelector.random(), + noteSelector: NoteSelector.random(), + }; + + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json, reviver); + + expect(parsed).toEqual(data); + expect(parsed.fr).toBeInstanceOf(Fr); + expect(parsed.fq).toBeInstanceOf(Fq); + expect(parsed.aztecAddress).toBeInstanceOf(AztecAddress); + expect(parsed.ethAddress).toBeInstanceOf(EthAddress); + expect(parsed.functionSelector).toBeInstanceOf(FunctionSelector); + expect(parsed.noteSelector).toBeInstanceOf(NoteSelector); + }); + + it('deserializes registered types in arrays', () => { + const data = [ + Fr.random(), + Fq.random(), + AztecAddress.random(), + EthAddress.random(), + FunctionSelector.random(), + NoteSelector.random(), + ]; + + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json, reviver); + + expect(parsed).toEqual(data); + expect(parsed[0]).toBeInstanceOf(Fr); + expect(parsed[1]).toBeInstanceOf(Fq); + expect(parsed[2]).toBeInstanceOf(AztecAddress); + expect(parsed[3]).toBeInstanceOf(EthAddress); + expect(parsed[4]).toBeInstanceOf(FunctionSelector); + expect(parsed[5]).toBeInstanceOf(NoteSelector); + }); + + it('ignores unregistered types', () => { + const data = { eventSelector: EventSelector.random() }; + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json); + expect(parsed.eventSelector).toEqual(data.eventSelector.toString()); + }); + + it('handles plain objects', () => { + const data = { obj: { number: 10, string: 'string', fr: Fr.random() } }; + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json, reviver); + expect(parsed).toEqual(data); + expect(parsed.obj.fr).toBeInstanceOf(Fr); + }); + + it('handles plain arrays', () => { + const data = [10, 'string', Fr.random()]; + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json, reviver); + expect(parsed).toEqual(data); + expect(parsed[2]).toBeInstanceOf(Fr); + }); + + it('handles bigints', () => { + const data = { bigInt: BigInt(10) }; + const json = JSON.stringify(data, resolver); + const parsed = JSON.parse(json, reviver); + expect(parsed.bigInt).toEqual(BigInt(10)); + }); +}); diff --git a/yarn-project/foundation/src/serialize/type_registry.ts b/yarn-project/foundation/src/serialize/type_registry.ts index 85146710ed8..39a6bd00ad3 100644 --- a/yarn-project/foundation/src/serialize/type_registry.ts +++ b/yarn-project/foundation/src/serialize/type_registry.ts @@ -1,3 +1,5 @@ +import { mapValues } from '../collection/object.js'; + type Deserializable = { fromString(str: string): object }; /** @@ -23,9 +25,39 @@ export class TypeRegistry { } } +function replace(value: T) { + if ( + value && + typeof value === 'object' && + 'toString' in value && + TypeRegistry.getConstructor(value.constructor.name) + ) { + return { + type: value.constructor.name, + value: value.toString(), + }; + } + + return value; +} + // Resolver function that enables JSON serialization of BigInts. export function resolver(_: any, value: any) { - return typeof value === 'bigint' ? value.toString() + 'n' : value; + if (typeof value === 'bigint') { + return value.toString() + 'n'; + } + + if (typeof value === 'object' && value) { + if (Array.isArray(value)) { + return value.map(replace); + } else if (Buffer.isBuffer(value)) { + return { type: 'buffer', value: value.toString('hex') }; + } else { + return mapValues(value, replace); + } + } + + return value; } // Reviver function that uses TypeRegistry to instantiate objects. diff --git a/yarn-project/foundation/src/string/index.ts b/yarn-project/foundation/src/string/index.ts index 250b3c02581..1b85173fc1a 100644 --- a/yarn-project/foundation/src/string/index.ts +++ b/yarn-project/foundation/src/string/index.ts @@ -14,6 +14,10 @@ export function hexToBuffer(str: string): Buffer { return Buffer.from(withoutHexPrefix(str), 'hex'); } +export function bufferToHex(buffer: Buffer): `0x${string}` { + return `0x${buffer.toString('hex')}`; +} + export function pluralize(str: string, count: number | bigint, plural?: string): string { return count === 1 || count === 1n ? str : plural ?? `${str}s`; } diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap index c5b038f46bb..af7128a8549 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap @@ -9,7 +9,7 @@ exports[`Data generation for noir tests Computes contract info for defaultContra address: AztecAddress { inner: 0x29bc2e90ff6ec5f4a7c7f502e368af01eb74131a2eec6320e0e45419cddc7b6d }, partial_address: PartialAddress { inner: 0x1a68423cf4f04eaede2b0e93131916b8b7330dae6e8ee202679d12a4eb49cc0b }, contract_class_id: ContractClassId { inner: 0x1195b865ef122d75c8c4d6102d536193b69bbb712c85bafcbf7694f52e2d8c36 }, - public_keys: PublicKeys { inner: 01498945581e0eb9f8427ad6021184c700ef091d570892c437d12c7d90364bbd170ae506787c5c43d6ca9255d571c10fa9ffa9d141666e290c347c5c9ab7e34400c044b05b6ca83b9c2dbae79cc1135155956a64e136819136e9947fe5e5866c1c1f0ca244c7cd46b682552bff8ae77dea40b966a71de076ec3b7678f2bdb1511b00316144359e9a3ec8e49c1cdb7eeb0cedd190dfd9dc90eea5115aa779e287080ffc74d7a8b0bccb88ac11f45874172f3847eb8b92654aaa58a3d2b8dc7833019c111f36ad3fc1d9b7a7a14344314d2864b94f030594cd67f753ef774a1efb2039907fe37f08d10739255141bb066c506a12f7d1e8dfec21abc58494705b6f }, + public_keys: PublicKeys { inner: 0x01498945581e0eb9f8427ad6021184c700ef091d570892c437d12c7d90364bbd170ae506787c5c43d6ca9255d571c10fa9ffa9d141666e290c347c5c9ab7e34400c044b05b6ca83b9c2dbae79cc1135155956a64e136819136e9947fe5e5866c1c1f0ca244c7cd46b682552bff8ae77dea40b966a71de076ec3b7678f2bdb1511b00316144359e9a3ec8e49c1cdb7eeb0cedd190dfd9dc90eea5115aa779e287080ffc74d7a8b0bccb88ac11f45874172f3847eb8b92654aaa58a3d2b8dc7833019c111f36ad3fc1d9b7a7a14344314d2864b94f030594cd67f753ef774a1efb2039907fe37f08d10739255141bb066c506a12f7d1e8dfec21abc58494705b6f }, salted_initialization_hash: SaltedInitializationHash { inner: 0x13a939daa511233e5446905ed2cadbee14948fa75df183b53b5c14b612bffe88 }, deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 } }" @@ -24,7 +24,7 @@ exports[`Data generation for noir tests Computes contract info for parentContrac address: AztecAddress { inner: 0x2749b685f752f6dfe1d4e532fc036839004926b7c18abf1a4f69ddf97d62f40e }, partial_address: PartialAddress { inner: 0x1c30ee02dcd41bcdfc5191dc36ccaae15cdc7e1fc6bd8a0cbe1baeaf1335a771 }, contract_class_id: ContractClassId { inner: 0x24f1b8df215c10ee7edd213b439c8f8e99198a802a3e1e41597b6554b17049a3 }, - public_keys: PublicKeys { inner: 01498945581e0eb9f8427ad6021184c700ef091d570892c437d12c7d90364bbd170ae506787c5c43d6ca9255d571c10fa9ffa9d141666e290c347c5c9ab7e34400c044b05b6ca83b9c2dbae79cc1135155956a64e136819136e9947fe5e5866c1c1f0ca244c7cd46b682552bff8ae77dea40b966a71de076ec3b7678f2bdb1511b00316144359e9a3ec8e49c1cdb7eeb0cedd190dfd9dc90eea5115aa779e287080ffc74d7a8b0bccb88ac11f45874172f3847eb8b92654aaa58a3d2b8dc7833019c111f36ad3fc1d9b7a7a14344314d2864b94f030594cd67f753ef774a1efb2039907fe37f08d10739255141bb066c506a12f7d1e8dfec21abc58494705b6f }, + public_keys: PublicKeys { inner: 0x01498945581e0eb9f8427ad6021184c700ef091d570892c437d12c7d90364bbd170ae506787c5c43d6ca9255d571c10fa9ffa9d141666e290c347c5c9ab7e34400c044b05b6ca83b9c2dbae79cc1135155956a64e136819136e9947fe5e5866c1c1f0ca244c7cd46b682552bff8ae77dea40b966a71de076ec3b7678f2bdb1511b00316144359e9a3ec8e49c1cdb7eeb0cedd190dfd9dc90eea5115aa779e287080ffc74d7a8b0bccb88ac11f45874172f3847eb8b92654aaa58a3d2b8dc7833019c111f36ad3fc1d9b7a7a14344314d2864b94f030594cd67f753ef774a1efb2039907fe37f08d10739255141bb066c506a12f7d1e8dfec21abc58494705b6f }, salted_initialization_hash: SaltedInitializationHash { inner: 0x24bd6ac7a182e2cf25e437c72f53544ef81dfd97d9afee23abb07a638e7be749 }, deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 } }" diff --git a/yarn-project/prover-client/src/proving_broker/proving_job_database/persisted.ts b/yarn-project/prover-client/src/proving_broker/proving_job_database/persisted.ts index 748ad387124..c03684b1bf3 100644 --- a/yarn-project/prover-client/src/proving_broker/proving_job_database/persisted.ts +++ b/yarn-project/prover-client/src/proving_broker/proving_job_database/persisted.ts @@ -1,4 +1,5 @@ import { type V2ProofOutput, V2ProvingJob, type V2ProvingJobId, V2ProvingJobResult } from '@aztec/circuit-types'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; import { type AztecKVStore, type AztecMap } from '@aztec/kv-store'; import { type ProvingJobDatabase } from '../proving_job_database.js'; @@ -13,14 +14,14 @@ export class PersistedProvingJobDatabase implements ProvingJobDatabase { } async addProvingJob(job: V2ProvingJob): Promise { - await this.jobs.set(job.id, JSON.stringify(job)); + await this.jobs.set(job.id, jsonStringify(job)); } *allProvingJobs(): Iterable<[V2ProvingJob, V2ProvingJobResult | undefined]> { for (const jobStr of this.jobs.values()) { - const job = V2ProvingJob.parse(JSON.parse(jobStr)); + const job = jsonParseWithSchema(jobStr, V2ProvingJob); const resultStr = this.jobResults.get(job.id); - const result = resultStr ? V2ProvingJobResult.parse(JSON.parse(resultStr)) : undefined; + const result = resultStr ? jsonParseWithSchema(resultStr, V2ProvingJobResult) : undefined; yield [job, result]; } } @@ -34,11 +35,11 @@ export class PersistedProvingJobDatabase implements ProvingJobDatabase { async setProvingJobError(id: V2ProvingJobId, err: Error): Promise { const res: V2ProvingJobResult = { error: err.message }; - await this.jobResults.set(id, JSON.stringify(res)); + await this.jobResults.set(id, jsonStringify(res)); } async setProvingJobResult(id: V2ProvingJobId, value: V2ProofOutput): Promise { const res: V2ProvingJobResult = { value }; - await this.jobResults.set(id, JSON.stringify(res)); + await this.jobResults.set(id, jsonStringify(res)); } } diff --git a/yarn-project/prover-node/src/quote-provider/http.ts b/yarn-project/prover-node/src/quote-provider/http.ts index 2e3a6ce6798..a50318143e9 100644 --- a/yarn-project/prover-node/src/quote-provider/http.ts +++ b/yarn-project/prover-node/src/quote-provider/http.ts @@ -1,4 +1,5 @@ import { type L2Block } from '@aztec/circuit-types'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { type QuoteProvider, type QuoteProviderResult } from './index.js'; import { getTotalFees, getTxCount } from './utils.js'; @@ -17,7 +18,7 @@ export class HttpQuoteProvider implements QuoteProvider { const response = await fetch(this.url, { method: 'POST', - body: JSON.stringify(payload), + body: jsonStringify(payload), headers: { 'content-type': 'application/json' }, }); @@ -27,7 +28,7 @@ export class HttpQuoteProvider implements QuoteProvider { const data = await response.json(); if (!data.basisPointFee || !data.bondAmount) { - throw new Error(`Missing required fields (basisPointFee | bondAmount) in response: ${JSON.stringify(data)}`); + throw new Error(`Missing required fields (basisPointFee | bondAmount) in response: ${jsonStringify(data)}`); } const basisPointFee = Number(data.basisPointFee); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index a7ca08660f2..00dfea9c56d 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -27,6 +27,7 @@ import { } from '@aztec/circuits.js'; import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi'; import { poseidon2Hash } from '@aztec/foundation/crypto'; +import { tryJsonStringify } from '@aztec/foundation/json-rpc'; import { createDebugLogger } from '@aztec/foundation/log'; import { type KeyStore } from '@aztec/key-store'; import { type AcirSimulator, type DBOracle, MessageLoadOracleInputs } from '@aztec/simulator'; @@ -556,9 +557,9 @@ export class SimulatorOracle implements DBOracle { if (incomingNotePayload || outgoingNotePayload) { if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) { this.log.warn( - `Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify( + `Incoming and outgoing note payloads do not match. Incoming: ${tryJsonStringify( incomingNotePayload, - )}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`, + )}, Outgoing: ${tryJsonStringify(outgoingNotePayload)}`, ); continue; } diff --git a/yarn-project/sequencer-client/src/block_builder/light.ts b/yarn-project/sequencer-client/src/block_builder/light.ts index 44d92ca2a23..35ac23d476a 100644 --- a/yarn-project/sequencer-client/src/block_builder/light.ts +++ b/yarn-project/sequencer-client/src/block_builder/light.ts @@ -17,6 +17,8 @@ import { buildBaseRollupHints, buildHeaderFromTxEffects, getTreeSnapshot } from import { type TelemetryClient } from '@aztec/telemetry-client'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; +import { inspect } from 'util'; + /** * Builds a block and its header from a set of processed tx without running any circuits. */ @@ -32,7 +34,7 @@ export class LightweightBlockBuilder implements BlockBuilder { constructor(private db: MerkleTreeWriteOperations, private telemetry: TelemetryClient) {} async startNewBlock(numTxs: number, globalVariables: GlobalVariables, l1ToL2Messages: Fr[]): Promise { - this.logger.verbose('Starting new block', { numTxs, globalVariables: globalVariables.toJSON(), l1ToL2Messages }); + this.logger.verbose('Starting new block', { numTxs, globalVariables: inspect(globalVariables), l1ToL2Messages }); this.numTxs = numTxs; this.globalVariables = globalVariables; this.l1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); 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 adb1cb4f9e5..3ca0a790c77 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 @@ -89,7 +89,7 @@ export class GlobalVariableBuilder implements GlobalVariableBuilderInterface { feeRecipient, gasFees, ); - this.log.debug(`Built global variables for block ${blockNumber}`, globalVariables.toJSON()); + this.log.debug(`Built global variables for block ${blockNumber}`, globalVariables.toFriendlyJSON()); return globalVariables; } } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 29b4c8d1de3..2bc6c67d9b8 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -738,7 +738,7 @@ export class L1Publisher { const attestations = encodedData.attestations ? encodedData.attestations.map(attest => attest.toViemSignature()) : []; - const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.to0xString()) : []; + const txHashes = encodedData.txHashes ? encodedData.txHashes.map(txHash => txHash.toString()) : []; const args = [ { header: `0x${encodedData.header.toString('hex')}`, diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index f89d4c94f90..90bb0e75b89 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -9,6 +9,7 @@ import { } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash'; import { Fr } from '@aztec/foundation/fields'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { createDebugLogger } from '@aztec/foundation/log'; import assert from 'assert'; @@ -468,7 +469,7 @@ export class AvmPersistableStateManager { if (exists) { const instance = new SerializableContractInstance(instanceWithAddress); this.log.debug( - `Got contract instance (address=${contractAddress}): exists=${exists}, instance=${JSON.stringify(instance)}`, + `Got contract instance (address=${contractAddress}): exists=${exists}, instance=${jsonStringify(instance)}`, ); this.trace.traceGetContractInstance(contractAddress, exists, instance); diff --git a/yarn-project/simulator/src/common/errors.ts b/yarn-project/simulator/src/common/errors.ts index f51536ac457..da35b96d784 100644 --- a/yarn-project/simulator/src/common/errors.ts +++ b/yarn-project/simulator/src/common/errors.ts @@ -6,6 +6,7 @@ import { } from '@aztec/circuit-types'; import { type Fr } from '@aztec/circuits.js'; import type { BrilligFunctionId, FunctionAbi, FunctionDebugMetadata, OpcodeLocation } from '@aztec/foundation/abi'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { type RawAssertionPayload } from '@noir-lang/acvm_js'; import { abiDecodeError } from '@noir-lang/noirc_abi'; @@ -153,7 +154,7 @@ export function resolveAssertionMessage(errorPayload: RawAssertionPayload, abi: if (typeof decoded === 'string') { return decoded; } else { - return JSON.stringify(decoded); + return jsonStringify(decoded); } } diff --git a/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts b/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts index 768243bf473..41298d80f63 100644 --- a/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts +++ b/yarn-project/simulator/src/public/enqueued_call_side_effect_trace.ts @@ -58,6 +58,7 @@ import { import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js/hash'; import { padArrayEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { createDebugLogger } from '@aztec/foundation/log'; import { assert } from 'console'; @@ -495,9 +496,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI new AvmContractBytecodeHints(bytecode, instance, contractClass), ); this.log.debug( - `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${JSON.stringify( - contractInstance, - )}`, + `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${jsonStringify(contractInstance)}`, ); } diff --git a/yarn-project/simulator/src/public/side_effect_trace.ts b/yarn-project/simulator/src/public/side_effect_trace.ts index ac1f4a98f16..dcb86a1850d 100644 --- a/yarn-project/simulator/src/public/side_effect_trace.ts +++ b/yarn-project/simulator/src/public/side_effect_trace.ts @@ -45,6 +45,7 @@ import { TreeLeafReadRequest, } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; +import { jsonStringify } from '@aztec/foundation/json-rpc'; import { createDebugLogger } from '@aztec/foundation/log'; import { assert } from 'console'; @@ -362,9 +363,7 @@ export class PublicSideEffectTrace implements PublicSideEffectTraceInterface { new AvmContractBytecodeHints(bytecode, instance, contractClass), ); this.log.debug( - `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${JSON.stringify( - contractInstance, - )}`, + `Bytecode retrieval for contract execution traced: exists=${exists}, instance=${jsonStringify(contractInstance)}`, ); } diff --git a/yarn-project/txe/src/util/encoding.ts b/yarn-project/txe/src/util/encoding.ts index 0b65122a61f..1853378af76 100644 --- a/yarn-project/txe/src/util/encoding.ts +++ b/yarn-project/txe/src/util/encoding.ts @@ -1,6 +1,7 @@ import { AztecAddress } from '@aztec/circuits.js'; import { type ContractArtifact, ContractArtifactSchema } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; +import { hexToBuffer } from '@aztec/foundation/string'; import { z } from 'zod'; @@ -23,7 +24,7 @@ export function addressFromSingle(obj: ForeignCallSingle) { } export function fromArray(obj: ForeignCallArray) { - return obj.map(str => Fr.fromBuffer(Buffer.from(str, 'hex'))); + return obj.map(str => Fr.fromBuffer(hexToBuffer(str))); } export function toSingle(obj: Fr | AztecAddress) { diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 0141145e7b3..7e2f5b54bdd 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -13,6 +13,7 @@ import { type StructValue, type TypedStructFieldValue, } from '@aztec/foundation/abi'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; import { AZTEC_INITIALIZER_ATTRIBUTE, @@ -29,21 +30,7 @@ import { * @returns A buffer. */ export function contractArtifactToBuffer(artifact: ContractArtifact): Buffer { - return Buffer.from( - JSON.stringify(artifact, (key, value) => { - if ( - key === 'bytecode' && - value !== null && - typeof value === 'object' && - value.type === 'Buffer' && - Array.isArray(value.data) - ) { - return Buffer.from(value.data).toString('base64'); - } - return value; - }), - 'utf-8', - ); + return Buffer.from(jsonStringify(artifact), 'utf-8'); } /** @@ -52,7 +39,7 @@ export function contractArtifactToBuffer(artifact: ContractArtifact): Buffer { * @returns Deserialized artifact. */ export function contractArtifactFromBuffer(buffer: Buffer): ContractArtifact { - return ContractArtifactSchema.parse(JSON.parse(buffer.toString('utf-8'))); + return jsonParseWithSchema(buffer.toString('utf-8'), ContractArtifactSchema); } /** diff --git a/yarn-project/world-state/package.json b/yarn-project/world-state/package.json index 29b1124e272..6ffcf4bd889 100644 --- a/yarn-project/world-state/package.json +++ b/yarn-project/world-state/package.json @@ -71,7 +71,8 @@ "@aztec/types": "workspace:^", "bindings": "^1.5.0", "msgpackr": "^1.10.2", - "tslib": "^2.4.0" + "tslib": "^2.4.0", + "zod": "^3.23.8" }, "devDependencies": { "@aztec/archiver": "workspace:^", diff --git a/yarn-project/world-state/src/native/world_state_version.ts b/yarn-project/world-state/src/native/world_state_version.ts index 20707d354ab..2be422b9e16 100644 --- a/yarn-project/world-state/src/native/world_state_version.ts +++ b/yarn-project/world-state/src/native/world_state_version.ts @@ -1,38 +1,29 @@ import { EthAddress } from '@aztec/circuits.js'; +import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc'; import { readFile, writeFile } from 'fs/promises'; +import { z } from 'zod'; export class WorldStateVersion { - constructor(readonly version: number, readonly rollupAddress: EthAddress) {} + constructor(public readonly version: number, public readonly rollupAddress: EthAddress) {} static async readVersion(filename: string) { const versionData = await readFile(filename, 'utf-8').catch(() => undefined); - if (versionData === undefined) { - return undefined; - } - const versionJSON = JSON.parse(versionData); - if (versionJSON.version === undefined || versionJSON.rollupAddress === undefined) { - return undefined; - } - return WorldStateVersion.fromJSON(versionJSON); + return versionData === undefined ? undefined : jsonParseWithSchema(versionData, WorldStateVersion.schema); } public async writeVersionFile(filename: string) { - const data = JSON.stringify(this.toJSON()); + const data = jsonStringify(this); await writeFile(filename, data, 'utf-8'); } - toJSON() { - return { - version: this.version, - rollupAddress: this.rollupAddress.toChecksumString(), - }; - } - - static fromJSON(obj: any): WorldStateVersion { - const version = obj.version; - const rollupAddress = EthAddress.fromString(obj.rollupAddress); - return new WorldStateVersion(version, rollupAddress); + static get schema() { + return z + .object({ + version: z.number(), + rollupAddress: EthAddress.schema, + }) + .transform(({ version, rollupAddress }) => new WorldStateVersion(version, rollupAddress)); } static empty() { diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 57c3aa91fda..2d0af3c2c7c 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -1328,6 +1328,7 @@ __metadata: ts-node: ^10.9.1 tslib: ^2.4.0 typescript: ^5.0.4 + zod: ^3.23.8 languageName: unknown linkType: soft