diff --git a/yarn-project/circuits.js/src/structs/contract_storage_read.test.ts b/yarn-project/circuits.js/src/structs/contract_storage_read.test.ts new file mode 100644 index 00000000000..51264c92afd --- /dev/null +++ b/yarn-project/circuits.js/src/structs/contract_storage_read.test.ts @@ -0,0 +1,21 @@ +import { makeContractStorageRead } from '../tests/factories.js'; +import { ContractStorageRead } from './contract_storage_read.js'; + +describe('ContractStorageRead', () => { + it('serializes to buffer and deserializes it back', () => { + const randomInt = Math.floor(Math.random() * 1000); + const expected = makeContractStorageRead(randomInt); + const buffer = expected.toBuffer(); + const res = ContractStorageRead.fromBuffer(buffer); + expect(res).toEqual(expected); + }); + + it('serializes to field array and deserializes it back', () => { + const randomInt = Math.floor(Math.random() * 1000); + const expected = makeContractStorageRead(randomInt); + + const fieldArray = expected.toFields(); + const res = ContractStorageRead.fromFields(fieldArray); + expect(res).toEqual(expected); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/contract_storage_read.ts b/yarn-project/circuits.js/src/structs/contract_storage_read.ts new file mode 100644 index 00000000000..907470b132d --- /dev/null +++ b/yarn-project/circuits.js/src/structs/contract_storage_read.ts @@ -0,0 +1,77 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +/** + * Contract storage read operation on a specific contract. + * + * Note: Similar to `PublicDataRead` but it's from the POV of contract storage so we are not working with public data + * tree leaf index but storage slot index. + */ +export class ContractStorageRead { + constructor( + /** + * Storage slot we are reading from. + */ + public readonly storageSlot: Fr, + /** + * Value read from the storage slot. + */ + public readonly currentValue: Fr, + /** + * Optional side effect counter tracking position of this event in tx execution. + * Note: Not serialized + */ + public readonly sideEffectCounter?: number, + ) {} + + static from(args: { + /** + * Storage slot we are reading from. + */ + storageSlot: Fr; + /** + * Value read from the storage slot. + */ + currentValue: Fr; + /** + * Optional side effect counter tracking position of this event in tx execution. + */ + sideEffectCounter?: number; + }) { + return new ContractStorageRead(args.storageSlot, args.currentValue, args.sideEffectCounter); + } + + toBuffer() { + return serializeToBuffer(this.storageSlot, this.currentValue); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ContractStorageRead(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); + } + + static empty() { + return new ContractStorageRead(Fr.ZERO, Fr.ZERO); + } + + isEmpty() { + return this.storageSlot.isZero() && this.currentValue.isZero(); + } + + toFriendlyJSON() { + return `Slot=${this.storageSlot.toFriendlyJSON()}: ${this.currentValue.toFriendlyJSON()}`; + } + + toFields(): Fr[] { + return [this.storageSlot, this.currentValue]; + } + + static fromFields(fields: Fr[] | FieldReader): ContractStorageRead { + const reader = FieldReader.asReader(fields); + + const storageSlot = reader.readField(); + const currentValue = reader.readField(); + + return new ContractStorageRead(storageSlot, currentValue); + } +} diff --git a/yarn-project/circuits.js/src/structs/contract_storage_update_request.test.ts b/yarn-project/circuits.js/src/structs/contract_storage_update_request.test.ts new file mode 100644 index 00000000000..e38a0b031aa --- /dev/null +++ b/yarn-project/circuits.js/src/structs/contract_storage_update_request.test.ts @@ -0,0 +1,21 @@ +import { makeContractStorageUpdateRequest } from '../tests/factories.js'; +import { ContractStorageUpdateRequest } from './contract_storage_update_request.js'; + +describe('ContractStorageUpdateRequest', () => { + it('serializes to buffer and deserializes it back', () => { + const randomInt = Math.floor(Math.random() * 1000); + const expected = makeContractStorageUpdateRequest(randomInt); + const buffer = expected.toBuffer(); + const res = ContractStorageUpdateRequest.fromBuffer(buffer); + expect(res).toEqual(expected); + }); + + it('serializes to field array and deserializes it back', () => { + const randomInt = Math.floor(Math.random() * 1000); + const expected = makeContractStorageUpdateRequest(randomInt); + + const fieldArray = expected.toFields(); + const res = ContractStorageUpdateRequest.fromFields(fieldArray); + expect(res).toEqual(expected); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts new file mode 100644 index 00000000000..351ea091825 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts @@ -0,0 +1,83 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +/** + * Contract storage update request for a slot on a specific contract. + * + * Note: Similar to `PublicDataUpdateRequest` but it's from the POV of contract storage so we are not working with + * public data tree leaf index but storage slot index. + */ +export class ContractStorageUpdateRequest { + constructor( + /** + * Storage slot we are updating. + */ + public readonly storageSlot: Fr, + /** + * Old value of the storage slot. + */ + public readonly oldValue: Fr, + /** + * New value of the storage slot. + */ + public readonly newValue: Fr, + /** + * Optional side effect counter tracking position of this event in tx execution. + */ + public readonly sideEffectCounter?: number, + ) {} + + toBuffer() { + return serializeToBuffer(this.storageSlot, this.oldValue, this.newValue); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ContractStorageUpdateRequest(Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader)); + } + + /** + * Create PublicCallRequest from a fields dictionary. + * @param fields - The dictionary. + * @returns A PublicCallRequest object. + */ + static from(fields: FieldsOf): ContractStorageUpdateRequest { + return new ContractStorageUpdateRequest(...ContractStorageUpdateRequest.getFields(fields)); + } + + /** + * Serialize into a field array. Low-level utility. + * @param fields - Object with fields. + * @returns The array. + */ + static getFields(fields: FieldsOf) { + return [fields.storageSlot, fields.oldValue, fields.newValue, fields.sideEffectCounter] as const; + } + + static empty() { + return new ContractStorageUpdateRequest(Fr.ZERO, Fr.ZERO, Fr.ZERO); + } + + isEmpty() { + return this.storageSlot.isZero() && this.oldValue.isZero() && this.newValue.isZero(); + } + + toFriendlyJSON() { + return `Slot=${this.storageSlot.toFriendlyJSON()}: ${this.oldValue.toFriendlyJSON()} => ${this.newValue.toFriendlyJSON()}`; + } + + toFields(): Fr[] { + return [this.storageSlot, this.oldValue, this.newValue]; + } + + static fromFields(fields: Fr[] | FieldReader): ContractStorageUpdateRequest { + const reader = FieldReader.asReader(fields); + + const storageSlot = reader.readField(); + const oldValue = reader.readField(); + const newValue = reader.readField(); + + return new ContractStorageUpdateRequest(storageSlot, oldValue, newValue); + } +} diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 2218c043152..cb06d1b1412 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -5,6 +5,8 @@ export * from './call_request.js'; export * from './call_stack_item.js'; export * from './complete_address.js'; export * from './contract_deployment_data.js'; +export * from './contract_storage_read.js'; +export * from './contract_storage_update_request.js'; export * from './function_data.js'; export * from './function_leaf_preimage.js'; export * from './global_variables.js'; diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index 572e76e273b..a1e1abad29e 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -2,7 +2,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { isArrayEmpty } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; import { @@ -15,134 +15,7 @@ import { RETURN_VALUES_LENGTH, } from '../constants.gen.js'; import { CallContext } from './call_context.js'; -import { Header, SideEffect, SideEffectLinkedToNoteHash } from './index.js'; - -/** - * Contract storage read operation on a specific contract. - * - * Note: Similar to `PublicDataRead` but it's from the POV of contract storage so we are not working with public data - * tree leaf index but storage slot index. - */ -export class ContractStorageRead { - constructor( - /** - * Storage slot we are reading from. - */ - public readonly storageSlot: Fr, - /** - * Value read from the storage slot. - */ - public readonly currentValue: Fr, - /** - * Optional side effect counter tracking position of this event in tx execution. - */ - public readonly sideEffectCounter?: number, - ) {} - - static from(args: { - /** - * Storage slot we are reading from. - */ - storageSlot: Fr; - /** - * Value read from the storage slot. - */ - currentValue: Fr; - /** - * Optional side effect counter tracking position of this event in tx execution. - */ - sideEffectCounter?: number; - }) { - return new ContractStorageRead(args.storageSlot, args.currentValue, args.sideEffectCounter); - } - - toBuffer() { - return serializeToBuffer(this.storageSlot, this.currentValue); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new ContractStorageRead(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); - } - - static empty() { - return new ContractStorageRead(Fr.ZERO, Fr.ZERO); - } - - isEmpty() { - return this.storageSlot.isZero() && this.currentValue.isZero(); - } - - toFriendlyJSON() { - return `Slot=${this.storageSlot.toFriendlyJSON()}: ${this.currentValue.toFriendlyJSON()}`; - } -} - -/** - * Contract storage update request for a slot on a specific contract. - * - * Note: Similar to `PublicDataUpdateRequest` but it's from the POV of contract storage so we are not working with - * public data tree leaf index but storage slot index. - */ -export class ContractStorageUpdateRequest { - constructor( - /** - * Storage slot we are updating. - */ - public readonly storageSlot: Fr, - /** - * Old value of the storage slot. - */ - public readonly oldValue: Fr, - /** - * New value of the storage slot. - */ - public readonly newValue: Fr, - /** - * Optional side effect counter tracking position of this event in tx execution. - */ - public readonly sideEffectCounter?: number, - ) {} - - toBuffer() { - return serializeToBuffer(this.storageSlot, this.oldValue, this.newValue); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new ContractStorageUpdateRequest(Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader)); - } - - /** - * Create PublicCallRequest from a fields dictionary. - * @param fields - The dictionary. - * @returns A PublicCallRequest object. - */ - static from(fields: FieldsOf): ContractStorageUpdateRequest { - return new ContractStorageUpdateRequest(...ContractStorageUpdateRequest.getFields(fields)); - } - - /** - * Serialize into a field array. Low-level utility. - * @param fields - Object with fields. - * @returns The array. - */ - static getFields(fields: FieldsOf) { - return [fields.storageSlot, fields.oldValue, fields.newValue, fields.sideEffectCounter] as const; - } - - static empty() { - return new ContractStorageUpdateRequest(Fr.ZERO, Fr.ZERO, Fr.ZERO); - } - - isEmpty() { - return this.storageSlot.isZero() && this.oldValue.isZero() && this.newValue.isZero(); - } - - toFriendlyJSON() { - return `Slot=${this.storageSlot.toFriendlyJSON()}: ${this.oldValue.toFriendlyJSON()} => ${this.newValue.toFriendlyJSON()}`; - } -} +import { ContractStorageRead, ContractStorageUpdateRequest, Header, SideEffect, SideEffectLinkedToNoteHash } from './index.js'; /** * Public inputs to a public circuit.