From 1ccc2d07bcfdde45f1ec31fd3d1856193c27ccdb Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 23 Apr 2024 10:27:02 +0000 Subject: [PATCH 1/6] feat: add the storage layout to the contract artifact --- .../aztec.js/src/contract/contract.test.ts | 1 + .../aztec.js/src/contract/contract_base.ts | 21 ++++------- .../src/contract-interface-gen/typescript.ts | 36 ++++++++----------- yarn-project/circuit-types/src/mocks.ts | 1 + .../src/contract/artifact_hash.test.ts | 1 + yarn-project/foundation/src/abi/abi.ts | 19 ++++++++++ .../types/src/abi/contract_artifact.ts | 29 +++++++++++++++ 7 files changed, 72 insertions(+), 36 deletions(-) diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index af425afcc90..89048525509 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -105,6 +105,7 @@ describe('Contract Class', () => { globals: {}, }, fileMap: {}, + storageLayout: {}, }; beforeEach(() => { diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index 5758973849e..da63a0cb5db 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -1,5 +1,10 @@ import { type Fr, computePartialAddress } from '@aztec/circuits.js'; -import { type ContractArtifact, type FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi'; +import { + type ContractArtifact, + type FieldLayout, + type FunctionArtifact, + FunctionSelector, +} from '@aztec/foundation/abi'; import { type ContractInstanceWithAddress } from '@aztec/types/contracts'; import { type Wallet } from '../account/index.js'; @@ -16,20 +21,6 @@ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & readonly selector: FunctionSelector; }; -/** - * Type representing a field layout in the storage of a contract. - */ -type FieldLayout = { - /** - * Slot in which the field is stored. - */ - slot: Fr; - /** - * Type being stored at the slot - */ - typ: string; -}; - /** * Type representing a note in use in the contract. */ diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index b86a32dcbdb..62d1b7a6b2f 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -4,9 +4,7 @@ import { type ContractArtifact, type FunctionArtifact, type IntegerValue, - type StructValue, type TupleValue, - type TypedStructFieldValue, getDefaultInitializer, isAztecAddressStruct, isEthAddressStruct, @@ -192,33 +190,29 @@ function generateAbiStatement(name: string, artifactImportPath: string) { * @param input - The contract artifact. */ function generateStorageLayoutGetter(input: ContractArtifact) { - const storage = input.outputs.globals.storage ? (input.outputs.globals.storage[0] as StructValue) : { fields: [] }; - const storageFields = storage.fields as TypedStructFieldValue[]; - const storageFieldsUnionType = storageFields.map(f => `'${f.name}'`).join(' | '); - const layout = storageFields + const entries = Object.entries(input.storageLayout); + + if (entries.length === 0) { + return ''; + } + + const storageFieldsUnionType = entries.map(([name]) => `'${name}'`).join(' | '); + const layout = entries .map( - ({ - name, - value: { - fields: [slot, typ], - }, - }) => + ([name, { slot, typ }]) => `${name}: { - slot: new Fr(${(slot.value as IntegerValue).value}n), - typ: "${(typ.value as BasicValue<'string', string>).value}", - } - `, + slot: new Fr(${slot.toBigInt()}), + typ: "${typ}", + }`, ) .join(',\n'); - return storageFields.length > 0 - ? ` - public static get storage(): ContractStorageLayout<${storageFieldsUnionType}> { + + return `public static get storage(): ContractStorageLayout<${storageFieldsUnionType}> { return { ${layout} } as ContractStorageLayout<${storageFieldsUnionType}>; } - ` - : ''; + `; } /** diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 7f0442ffd3e..cd7936f5961 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -125,6 +125,7 @@ export const randomContractArtifact = (): ContractArtifact => ({ globals: {}, }, fileMap: {}, + storageLayout: {}, }); export const randomContractInstanceWithAddress = (opts: { contractClassId?: Fr } = {}): ContractInstanceWithAddress => diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts index 2953da240c1..9a46506818f 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -12,6 +12,7 @@ describe('ArtifactHash', () => { globals: {}, structs: {}, }, + storageLayout: {}, }; expect(computeArtifactHash(emptyArtifact).toString()).toMatchInlineSnapshot( `"0x0dea64e7fa0688017f77bcb7075485485afb4a5f1f8508483398869439f82fdf"`, diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index 9f2d48800f8..711a46b393a 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -1,5 +1,6 @@ import { inflate } from 'pako'; +import { type Fr } from '../fields/fields.js'; import { type FunctionSelector } from './function_selector.js'; /** @@ -267,6 +268,20 @@ export type DebugFileMap = Record< } >; +/** + * Type representing a field layout in the storage of a contract. + */ +export type FieldLayout = { + /** + * Slot in which the field is stored. + */ + slot: Fr; + /** + * Type being stored at the slot + */ + typ: string; +}; + /** * Defines artifact of a contract. */ @@ -292,6 +307,10 @@ export interface ContractArtifact { structs: Record; globals: Record; }; + /** + * Storage layout + */ + storageLayout: Record; /** * The map of file ID to the source code and path of the file. diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index f2c605a0886..cf237d84415 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -2,10 +2,16 @@ import { type ABIParameter, type ABIParameterVisibility, type AbiType, + type BasicValue, type ContractArtifact, + type FieldLayout, type FunctionArtifact, FunctionType, + type IntegerValue, + type StructValue, + type TypedStructFieldValue, } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; import { AZTEC_INITIALIZER_ATTRIBUTE, @@ -198,6 +204,28 @@ function hasKernelFunctionInputs(params: ABIParameter[]): boolean { return firstParam?.type.kind === 'struct' && firstParam.type.path.includes('ContextInputs'); } +/** + * Generates a storage layout for the contract artifact. + * @param contract + * @returns A storage layout for the contract. + */ +function getStorageLayout(input: NoirCompiledContract) { + const storage = input.outputs.globals.storage ? (input.outputs.globals.storage[0] as StructValue) : { fields: [] }; + const storageFields = storage.fields as TypedStructFieldValue[]; + const layout: Record = storageFields.reduce((acc: Record, field) => { + const name = field.name; + const slot = field.value.fields[0].value as IntegerValue; + const typ = field.value.fields[1].value as BasicValue<'string', string>; + acc[name] = { + slot: new Fr(BigInt(slot.value)), + typ: typ.value, + }; + return acc; + }, {}); + + return layout; +} + /** * Given a Nargo output generates an Aztec-compatible contract artifact. * @param compiled - Noir build output. @@ -208,6 +236,7 @@ function generateContractArtifact(contract: NoirCompiledContract, aztecNrVersion name: contract.name, functions: contract.functions.map(f => generateFunctionArtifact(f, contract)), outputs: contract.outputs, + storageLayout: getStorageLayout(contract), fileMap: contract.file_map, aztecNrVersion, }; From 8ec9d8ede4928e3ca93b96809efce4aedb0a0de8 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 23 Apr 2024 12:42:47 +0000 Subject: [PATCH 2/6] fix: replaces uses and unbrick deployer --- .../end-to-end/src/e2e_account_init_fees.test.ts | 2 +- yarn-project/end-to-end/src/sample-dapp/index.mjs | 2 +- .../end-to-end/src/sample-dapp/index.test.mjs | 2 +- yarn-project/end-to-end/src/shared/browser.ts | 2 +- .../simulator/src/client/private_execution.test.ts | 2 +- yarn-project/simulator/src/public/index.test.ts | 2 +- yarn-project/types/src/abi/contract_artifact.test.ts | 1 - yarn-project/types/src/abi/contract_artifact.ts | 12 ++++++++++++ 8 files changed, 18 insertions(+), 7 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts b/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts index 75c225f4d52..54edfd7f77e 100644 --- a/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts @@ -333,7 +333,7 @@ describe('e2e_fees_account_init', () => { }); async function addTransparentNoteToPxe(owner: AztecAddress, amount: bigint, secretHash: Fr, txHash: TxHash) { - const storageSlot = new Fr(5); // The storage slot of `pending_shields` is 5. + const storageSlot = bananaCoin.artifact.storageLayout['pending_shields'].slot; const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote const note = new Note([new Fr(amount), secretHash]); diff --git a/yarn-project/end-to-end/src/sample-dapp/index.mjs b/yarn-project/end-to-end/src/sample-dapp/index.mjs index 6f421f61f3a..f7302c01510 100644 --- a/yarn-project/end-to-end/src/sample-dapp/index.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/index.mjs @@ -37,7 +37,7 @@ async function mintPrivateFunds(pxe) { const secretHash = await computeSecretHash(secret); const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait(); - const storageSlot = new Fr(5); + const storageSlot = token.artifact.storageLayout['pending_shields'].slot; const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote const note = new Note([new Fr(mintAmount), secretHash]); diff --git a/yarn-project/end-to-end/src/sample-dapp/index.test.mjs b/yarn-project/end-to-end/src/sample-dapp/index.test.mjs index 9508ab1631b..293accc90ab 100644 --- a/yarn-project/end-to-end/src/sample-dapp/index.test.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/index.test.mjs @@ -22,7 +22,7 @@ describe('token', () => { const secretHash = await computeSecretHash(secret); const receipt = await token.methods.mint_private(initialBalance, secretHash).send().wait(); - const storageSlot = new Fr(5); + const storageSlot = token.artifact.storageLayout['pending_shields'].slot; const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote const note = new Note([new Fr(initialBalance), secretHash]); const extendedNote = new ExtendedNote( diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index 370a7698337..184dbd9fb32 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -264,7 +264,7 @@ export const browserTestSuite = ( const secretHash = computeSecretHash(secret); const mintPrivateReceipt = await token.methods.mint_private(initialBalance, secretHash).send().wait(); - const storageSlot = new Fr(5); + const storageSlot = token.artifact.storageLayout['pending_shields'].slot; const noteTypeId = new Fr(84114971101151129711410111011678111116101n); const note = new Note([new Fr(initialBalance), secretHash]); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index ecff905aea0..67879b3a302 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -729,7 +729,7 @@ describe('Private Execution test suite', () => { const secret = new Fr(1n); const secretHash = computeSecretHash(secret); const note = new Note([secretHash]); - const storageSlot = new Fr(5); + const storageSlot = TestContractArtifact.storageLayout['example_set'].slot; oracle.getNotes.mockResolvedValue([ { contractAddress, diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 886ebf355fb..8e8fb651afe 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -335,7 +335,7 @@ describe('ACIR public execution simulator', () => { expect(result.newNoteHashes.length).toEqual(1); const expectedNoteHash = computeNoteContentHash([amount, secretHash]); - const storageSlot = new Fr(5); // for pending_shields + const storageSlot = TokenContractArtifact.storageLayout['pending_shields'].slot; const expectedInnerNoteHash = computeInnerNoteHash(storageSlot, expectedNoteHash); expect(result.newNoteHashes[0].value).toEqual(expectedInnerNoteHash); }); diff --git a/yarn-project/types/src/abi/contract_artifact.test.ts b/yarn-project/types/src/abi/contract_artifact.test.ts index de830666e09..1e1bb30e6e7 100644 --- a/yarn-project/types/src/abi/contract_artifact.test.ts +++ b/yarn-project/types/src/abi/contract_artifact.test.ts @@ -4,7 +4,6 @@ import { contractArtifactFromBuffer, contractArtifactToBuffer } from './contract describe('contract_artifact', () => { it('serializes and deserializes an instance', () => { const artifact = getSampleContractArtifact(); - delete artifact.aztecNrVersion; const serialized = contractArtifactToBuffer(artifact); const deserialized = contractArtifactFromBuffer(serialized); expect(deserialized).toEqual(artifact); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index cf237d84415..2ccf00fbf1c 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -56,6 +56,18 @@ export function contractArtifactFromBuffer(buffer: Buffer): ContractArtifact { if (key === 'bytecode' && typeof value === 'string') { return Buffer.from(value, 'base64'); } + if (key === 'storageLayout') { + const layout: Record = Object.entries( + value as Record, + ).reduce((acc, [name, { slot, typ }]) => { + acc[name as string] = { + slot: Fr.fromString(slot.value), + typ, + }; + return acc; + }, {} as Record); + return layout; + } return value; }); } From f5d7d25cd7be4a95e5ca0b90c447cde011574b4a Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 23 Apr 2024 17:01:08 +0000 Subject: [PATCH 3/6] feat: add notes to the contract-artifact --- .../aztec.js/src/contract/contract.test.ts | 1 + .../aztec.js/src/contract/contract_base.ts | 17 +------ yarn-project/builder/package.json | 2 - .../src/contract-interface-gen/typescript.ts | 34 ++++++-------- yarn-project/circuit-types/src/mocks.ts | 1 + .../src/contract/artifact_hash.test.ts | 1 + .../src/e2e_account_init_fees.test.ts | 2 +- .../end-to-end/src/sample-dapp/index.mjs | 2 +- .../end-to-end/src/sample-dapp/index.test.mjs | 2 +- yarn-project/end-to-end/src/shared/browser.ts | 2 +- yarn-project/foundation/src/abi/abi.ts | 18 ++++++++ .../src/client/private_execution.test.ts | 26 +++++++---- .../simulator/src/client/simulator.test.ts | 4 +- .../types/src/abi/contract_artifact.ts | 45 +++++++++++++------ yarn-project/yarn.lock | 18 -------- 15 files changed, 93 insertions(+), 82 deletions(-) diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 89048525509..bcdac6b8dc9 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -106,6 +106,7 @@ describe('Contract Class', () => { }, fileMap: {}, storageLayout: {}, + notes: {}, }; beforeEach(() => { diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index da63a0cb5db..0ec2240a404 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -1,6 +1,7 @@ -import { type Fr, computePartialAddress } from '@aztec/circuits.js'; +import { computePartialAddress } from '@aztec/circuits.js'; import { type ContractArtifact, + type ContractNote, type FieldLayout, type FunctionArtifact, FunctionSelector, @@ -21,20 +22,6 @@ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & readonly selector: FunctionSelector; }; -/** - * Type representing a note in use in the contract. - */ -type ContractNote = { - /** - * Note identifier - */ - id: Fr; - /** - * Type of the note - */ - typ: string; -}; - /** * Type representing the storage layout of a contract. */ diff --git a/yarn-project/builder/package.json b/yarn-project/builder/package.json index 5f87dd34488..cac014a948c 100644 --- a/yarn-project/builder/package.json +++ b/yarn-project/builder/package.json @@ -58,7 +58,6 @@ "fs-extra": "^11.1.1", "lodash.camelcase": "^4.3.0", "lodash.capitalize": "^4.2.1", - "lodash.uniqby": "^4.7.0", "memfs": "^4.6.0", "pako": "^2.1.0", "semver": "^7.5.4", @@ -71,7 +70,6 @@ "@types/jest": "^29.5.0", "@types/lodash.camelcase": "^4.3.7", "@types/lodash.capitalize": "^4.2.7", - "@types/lodash.uniqby": "^4.7.9", "@types/node": "^18.7.23", "@types/pako": "^2.0.0", "@types/semver": "^7.5.4", diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index 62d1b7a6b2f..5edb7f32117 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -1,10 +1,7 @@ import { type ABIParameter, - type BasicValue, type ContractArtifact, type FunctionArtifact, - type IntegerValue, - type TupleValue, getDefaultInitializer, isAztecAddressStruct, isEthAddressStruct, @@ -12,8 +9,6 @@ import { isWrappedFieldStruct, } from '@aztec/foundation/abi'; -import uniqBy from 'lodash.uniqby'; - /** * Returns the corresponding typescript type for a given Noir type. * @param type - The input Noir type. @@ -220,30 +215,29 @@ function generateStorageLayoutGetter(input: ContractArtifact) { * @param input - The contract artifact. */ function generateNotesGetter(input: ContractArtifact) { - const notes = input.outputs.globals.notes - ? uniqBy(input.outputs.globals.notes as TupleValue[], n => (n.fields[1] as BasicValue<'string', string>).value) - : []; - const notesUnionType = notes.map(n => `'${(n.fields[1] as BasicValue<'string', string>).value}'`).join(' | '); + const entries = Object.entries(input.notes); + + if (entries.length === 0) { + return ''; + } - const noteMetadata = notes + const notesUnionType = entries.map(([name]) => `'${name}'`).join(' | '); + const noteMetadata = entries .map( - ({ fields: [id, typ] }) => - `${(typ as BasicValue<'string', string>).value}: { - id: new Fr(${(id as IntegerValue).value}n), - } - `, + ([name, { id }]) => + `${name}: { + id: new Fr(${id.toBigInt()}), + }`, ) .join(',\n'); - return notes.length > 0 - ? ` - public static get notes(): ContractNotes<${notesUnionType}> { + + return `public static get notes(): ContractNotes<${notesUnionType}> { const notes = this.artifact.outputs.globals.notes ? (this.artifact.outputs.globals.notes as any) : []; return { ${noteMetadata} } as ContractNotes<${notesUnionType}>; } - ` - : ''; + `; } /** diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index cd7936f5961..9cc201d2feb 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -126,6 +126,7 @@ export const randomContractArtifact = (): ContractArtifact => ({ }, fileMap: {}, storageLayout: {}, + notes: {}, }); export const randomContractInstanceWithAddress = (opts: { contractClassId?: Fr } = {}): ContractInstanceWithAddress => diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts index 9a46506818f..2d17740c9c2 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -13,6 +13,7 @@ describe('ArtifactHash', () => { structs: {}, }, storageLayout: {}, + notes: {}, }; expect(computeArtifactHash(emptyArtifact).toString()).toMatchInlineSnapshot( `"0x0dea64e7fa0688017f77bcb7075485485afb4a5f1f8508483398869439f82fdf"`, diff --git a/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts b/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts index 54edfd7f77e..2f488cca319 100644 --- a/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_init_fees.test.ts @@ -334,7 +334,7 @@ describe('e2e_fees_account_init', () => { async function addTransparentNoteToPxe(owner: AztecAddress, amount: bigint, secretHash: Fr, txHash: TxHash) { const storageSlot = bananaCoin.artifact.storageLayout['pending_shields'].slot; - const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote + const noteTypeId = bananaCoin.artifact.notes['TransparentNote'].id; const note = new Note([new Fr(amount), secretHash]); // this note isn't encrypted but we need to provide a registered public key diff --git a/yarn-project/end-to-end/src/sample-dapp/index.mjs b/yarn-project/end-to-end/src/sample-dapp/index.mjs index f7302c01510..f575fe89569 100644 --- a/yarn-project/end-to-end/src/sample-dapp/index.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/index.mjs @@ -38,7 +38,7 @@ async function mintPrivateFunds(pxe) { const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait(); const storageSlot = token.artifact.storageLayout['pending_shields'].slot; - const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote + const noteTypeId = token.artifact.notes['TransparentNote'].id; const note = new Note([new Fr(mintAmount), secretHash]); const extendedNote = new ExtendedNote( diff --git a/yarn-project/end-to-end/src/sample-dapp/index.test.mjs b/yarn-project/end-to-end/src/sample-dapp/index.test.mjs index 293accc90ab..49a6156046d 100644 --- a/yarn-project/end-to-end/src/sample-dapp/index.test.mjs +++ b/yarn-project/end-to-end/src/sample-dapp/index.test.mjs @@ -23,7 +23,7 @@ describe('token', () => { const receipt = await token.methods.mint_private(initialBalance, secretHash).send().wait(); const storageSlot = token.artifact.storageLayout['pending_shields'].slot; - const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote + const noteTypeId = token.artifact.notes['TransparentNote'].id; const note = new Note([new Fr(initialBalance), secretHash]); const extendedNote = new ExtendedNote( note, diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index 184dbd9fb32..42f316b9c7e 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -266,7 +266,7 @@ export const browserTestSuite = ( const storageSlot = token.artifact.storageLayout['pending_shields'].slot; - const noteTypeId = new Fr(84114971101151129711410111011678111116101n); + const noteTypeId = token.artifact.notes['TransparentNote'].id; const note = new Note([new Fr(initialBalance), secretHash]); const extendedNote = new ExtendedNote( note, diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index 711a46b393a..d242ae50e0f 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -268,6 +268,20 @@ export type DebugFileMap = Record< } >; +/** + * Type representing a note in use in the contract. + */ +export type ContractNote = { + /** + * Note identifier + */ + id: Fr; + /** + * Type of the note + */ + typ: string; +}; + /** * Type representing a field layout in the storage of a contract. */ @@ -311,6 +325,10 @@ export interface ContractArtifact { * Storage layout */ storageLayout: Record; + /** + * The notes used in the contract. + */ + notes: Record; /** * The map of file ID to the source code and path of the file. diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 67879b3a302..91d0dd93a38 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -340,10 +340,13 @@ describe('Private Execution test suite', () => { const amountToTransfer = 100n; const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create_no_init_check'); - const storageSlot = computeSlotForMapping(new Fr(1n), owner); - const recipientStorageSlot = computeSlotForMapping(new Fr(1n), recipient); + const storageSlot = computeSlotForMapping(StatefulTestContractArtifact.storageLayout['notes'].slot, owner); + const recipientStorageSlot = computeSlotForMapping( + StatefulTestContractArtifact.storageLayout['notes'].slot, + recipient, + ); - const noteTypeId = new Fr(869710811710178111116101n); // ValueNote + const noteTypeId = StatefulTestContractArtifact.notes['ValueNote'].id; const notes = [buildNote(60n, owner, storageSlot, noteTypeId), buildNote(80n, owner, storageSlot, noteTypeId)]; oracle.getNotes.mockResolvedValue(notes); @@ -398,7 +401,7 @@ describe('Private Execution test suite', () => { const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create_no_init_check'); const storageSlot = computeSlotForMapping(new Fr(1n), owner); - const noteTypeId = new Fr(869710811710178111116101n); // ValueNote + const noteTypeId = StatefulTestContractArtifact.notes['ValueNote'].id; const notes = [buildNote(balance, owner, storageSlot, noteTypeId)]; oracle.getNotes.mockResolvedValue(notes); @@ -729,6 +732,7 @@ describe('Private Execution test suite', () => { const secret = new Fr(1n); const secretHash = computeSecretHash(secret); const note = new Note([secretHash]); + // @todo @LHerskind Need to investigate why this was working with `new Fr(5)` as the `example_set = 2` should have caused a failure. const storageSlot = TestContractArtifact.storageLayout['example_set'].slot; oracle.getNotes.mockResolvedValue([ { @@ -861,8 +865,11 @@ describe('Private Execution test suite', () => { expect(newNoteHashes).toHaveLength(1); const noteHash = newNoteHashes[0]; - const storageSlot = computeSlotForMapping(new Fr(1n), owner); - const noteTypeId = new Fr(869710811710178111116101n); // ValueNote + const storageSlot = computeSlotForMapping( + PendingNoteHashesContractArtifact.storageLayout['balances'].slot, + owner, + ); + const noteTypeId = PendingNoteHashesContractArtifact.notes['ValueNote'].id; const innerNoteHash = await acirSimulator.computeInnerNoteHash( contractAddress, @@ -917,8 +924,11 @@ describe('Private Execution test suite', () => { const execInsert = result.nestedExecutions[0]; const execGetThenNullify = result.nestedExecutions[1]; - const storageSlot = computeSlotForMapping(new Fr(1n), owner); - const noteTypeId = new Fr(869710811710178111116101n); // ValueNote + const storageSlot = computeSlotForMapping( + PendingNoteHashesContractArtifact.storageLayout['balances'].slot, + owner, + ); + const noteTypeId = PendingNoteHashesContractArtifact.notes['ValueNote'].id; expect(execInsert.newNotes).toHaveLength(1); const noteAndSlot = execInsert.newNotes[0]; diff --git a/yarn-project/simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts index 62bb0c13b07..ef9fd366291 100644 --- a/yarn-project/simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -59,8 +59,8 @@ describe('Simulator', () => { describe('computeNoteHashAndNullifier', () => { const artifact = getFunctionArtifact(TokenContractArtifact, 'compute_note_hash_and_nullifier'); const nonce = Fr.random(); - const storageSlot = Fr.random(); - const noteTypeId = new Fr(8411110710111078111116101n); // TODO(#5833): This can be imported from artifact now + const storageSlot = TokenContractArtifact.storageLayout['balances'].slot; + const noteTypeId = TokenContractArtifact.notes['TokenNote'].id; const createNote = (amount = 123n) => new Note([new Fr(amount), owner.toField(), Fr.random()]); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 2ccf00fbf1c..12b203d3cab 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -4,6 +4,7 @@ import { type AbiType, type BasicValue, type ContractArtifact, + type ContractNote, type FieldLayout, type FunctionArtifact, FunctionType, @@ -56,17 +57,8 @@ export function contractArtifactFromBuffer(buffer: Buffer): ContractArtifact { if (key === 'bytecode' && typeof value === 'string') { return Buffer.from(value, 'base64'); } - if (key === 'storageLayout') { - const layout: Record = Object.entries( - value as Record, - ).reduce((acc, [name, { slot, typ }]) => { - acc[name as string] = { - slot: Fr.fromString(slot.value), - typ, - }; - return acc; - }, {} as Record); - return layout; + if (typeof value === 'object' && value !== null && value.type === 'Fr') { + return new Fr(BigInt(value.value)); } return value; }); @@ -224,7 +216,12 @@ function hasKernelFunctionInputs(params: ABIParameter[]): boolean { function getStorageLayout(input: NoirCompiledContract) { const storage = input.outputs.globals.storage ? (input.outputs.globals.storage[0] as StructValue) : { fields: [] }; const storageFields = storage.fields as TypedStructFieldValue[]; - const layout: Record = storageFields.reduce((acc: Record, field) => { + + if (!storageFields) { + return {}; + } + + return storageFields.reduce((acc: Record, field) => { const name = field.name; const slot = field.value.fields[0].value as IntegerValue; const typ = field.value.fields[1].value as BasicValue<'string', string>; @@ -234,8 +231,29 @@ function getStorageLayout(input: NoirCompiledContract) { }; return acc; }, {}); +} + +function getNoteTypes(input: NoirCompiledContract) { + type t = { + kind: string; + fields: [{ kind: string; sign: boolean; value: string }, { kind: string; value: string }]; + }; + + const notes = input.outputs.globals.notes as t[]; - return layout; + if (!notes) { + return {}; + } + + return notes.reduce((acc: Record, note) => { + const name = note.fields[1].value as string; + const id = new Fr(BigInt(note.fields[0].value)); + acc[name] = { + id, + typ: name, + }; + return acc; + }, {}); } /** @@ -249,6 +267,7 @@ function generateContractArtifact(contract: NoirCompiledContract, aztecNrVersion functions: contract.functions.map(f => generateFunctionArtifact(f, contract)), outputs: contract.outputs, storageLayout: getStorageLayout(contract), + notes: getNoteTypes(contract), fileMap: contract.file_map, aztecNrVersion, }; diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 12ef01aca7c..95c28c7b512 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -252,7 +252,6 @@ __metadata: "@types/jest": ^29.5.0 "@types/lodash.camelcase": ^4.3.7 "@types/lodash.capitalize": ^4.2.7 - "@types/lodash.uniqby": ^4.7.9 "@types/node": ^18.7.23 "@types/pako": ^2.0.0 "@types/semver": ^7.5.4 @@ -262,7 +261,6 @@ __metadata: jest: ^29.5.0 lodash.camelcase: ^4.3.0 lodash.capitalize: ^4.2.1 - lodash.uniqby: ^4.7.0 memfs: ^4.6.0 pako: ^2.1.0 semver: ^7.5.4 @@ -3710,15 +3708,6 @@ __metadata: languageName: node linkType: hard -"@types/lodash.uniqby@npm:^4.7.9": - version: 4.7.9 - resolution: "@types/lodash.uniqby@npm:4.7.9" - dependencies: - "@types/lodash": "*" - checksum: 24cc8af36e0d4c52b7294c7ba7d814c89ce2c8118d94350bbed21031fef850fa1a280bfd2b30a47e0b5f7aa6ac649a36a5089aa76bc23787963a5ee6443f631e - languageName: node - linkType: hard - "@types/lodash@npm:*": version: 4.17.0 resolution: "@types/lodash@npm:4.17.0" @@ -9867,13 +9856,6 @@ __metadata: languageName: node linkType: hard -"lodash.uniqby@npm:^4.7.0": - version: 4.7.0 - resolution: "lodash.uniqby@npm:4.7.0" - checksum: 659264545a95726d1493123345aad8cbf56e17810fa9a0b029852c6d42bc80517696af09d99b23bef1845d10d95e01b8b4a1da578f22aeba7a30d3e0022a4938 - languageName: node - linkType: hard - "lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" From 183a54cf2dc97be7c5f24e726f2102d042f3012c Mon Sep 17 00:00:00 2001 From: LHerskind Date: Tue, 23 Apr 2024 21:57:22 +0000 Subject: [PATCH 4/6] fix: missing n for bigint, oh the pain --- .../builder/src/contract-interface-gen/typescript.ts | 4 ++-- yarn-project/types/src/abi/contract_artifact.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index 5edb7f32117..a8fb0ef4a1b 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -196,7 +196,7 @@ function generateStorageLayoutGetter(input: ContractArtifact) { .map( ([name, { slot, typ }]) => `${name}: { - slot: new Fr(${slot.toBigInt()}), + slot: new Fr(${slot.toBigInt()}n), typ: "${typ}", }`, ) @@ -226,7 +226,7 @@ function generateNotesGetter(input: ContractArtifact) { .map( ([name, { id }]) => `${name}: { - id: new Fr(${id.toBigInt()}), + id: new Fr(${id.toBigInt()}n), }`, ) .join(',\n'); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 12b203d3cab..0998899167e 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -210,7 +210,7 @@ function hasKernelFunctionInputs(params: ABIParameter[]): boolean { /** * Generates a storage layout for the contract artifact. - * @param contract + * @param input - The compiled noir contract to get storage layout for * @returns A storage layout for the contract. */ function getStorageLayout(input: NoirCompiledContract) { @@ -233,6 +233,11 @@ function getStorageLayout(input: NoirCompiledContract) { }, {}); } +/** + * Generates records of the notes with note type ids of the artifact. + * @param input - The compiled noir contract to get note types for + * @return A record of the note types and their ids + */ function getNoteTypes(input: NoirCompiledContract) { type t = { kind: string; From 6078bb0c6f9daf289b13c4fc0da406b3918b6a76 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 24 Apr 2024 10:41:55 +0000 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20browser=20stuff=20=F0=9F=92=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yarn-project/aztec.js/src/api/abi.ts | 2 +- yarn-project/end-to-end/src/shared/browser.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn-project/aztec.js/src/api/abi.ts b/yarn-project/aztec.js/src/api/abi.ts index 7e94b7eb30f..03a5b41d4f2 100644 --- a/yarn-project/aztec.js/src/api/abi.ts +++ b/yarn-project/aztec.js/src/api/abi.ts @@ -1,3 +1,3 @@ export { ContractArtifact, FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi'; -export { loadContractArtifact } from '@aztec/types/abi'; +export { loadContractArtifact, contractArtifactToBuffer, contractArtifactFromBuffer } from '@aztec/types/abi'; export { NoirCompiledContract } from '@aztec/types/noir'; diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index 42f316b9c7e..9a94d89db75 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -227,11 +227,11 @@ export const browserTestSuite = ( INITIAL_TEST_SIGNING_KEYS, INITIAL_TEST_ACCOUNT_SALTS, Buffer, + contractArtifactFromBuffer, } = window.AztecJs; // We serialize the artifact since buffers (used for bytecode) do not cross well from one realm to another - const TokenContractArtifact = JSON.parse( - Buffer.from(serializedTokenContractArtifact, 'base64').toString('utf-8'), - (key, value) => (key === 'bytecode' && typeof value === 'string' ? Buffer.from(value, 'base64') : value), + const TokenContractArtifact = contractArtifactFromBuffer( + Buffer.from(serializedTokenContractArtifact, 'base64'), ); const pxe = createPXEClient(rpcUrl!); From e4135f392df0ecee1fe6a965e941cc89d5a218c9 Mon Sep 17 00:00:00 2001 From: LHerskind Date: Wed, 24 Apr 2024 14:03:42 +0000 Subject: [PATCH 6/6] chore: flaky discv5, increasing jest timeout --- yarn-project/builder/src/contract-interface-gen/typescript.ts | 1 - yarn-project/foundation/src/abi/abi.ts | 4 ++-- yarn-project/p2p/src/service/discv5_service.test.ts | 3 +++ yarn-project/simulator/src/client/private_execution.test.ts | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index a8fb0ef4a1b..4c2911fba97 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -232,7 +232,6 @@ function generateNotesGetter(input: ContractArtifact) { .join(',\n'); return `public static get notes(): ContractNotes<${notesUnionType}> { - const notes = this.artifact.outputs.globals.notes ? (this.artifact.outputs.globals.notes as any) : []; return { ${noteMetadata} } as ContractNotes<${notesUnionType}>; diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index d242ae50e0f..3dbe2dc7036 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -277,7 +277,7 @@ export type ContractNote = { */ id: Fr; /** - * Type of the note + * Type of the note (e.g., 'TransparentNote') */ typ: string; }; @@ -291,7 +291,7 @@ export type FieldLayout = { */ slot: Fr; /** - * Type being stored at the slot + * Type being stored at the slot (e.g., 'Map>') */ typ: string; }; diff --git a/yarn-project/p2p/src/service/discv5_service.test.ts b/yarn-project/p2p/src/service/discv5_service.test.ts index 9228e1b87d0..4ce6a233075 100644 --- a/yarn-project/p2p/src/service/discv5_service.test.ts +++ b/yarn-project/p2p/src/service/discv5_service.test.ts @@ -1,3 +1,4 @@ +import { jest } from '@jest/globals'; import type { PeerId } from '@libp2p/interface'; import { BootstrapNode } from '../bootstrap/bootstrap.js'; @@ -21,6 +22,8 @@ const waitForPeers = (node: DiscV5Service, expectedCount: number): Promise }; describe('Discv5Service', () => { + jest.setTimeout(10_000); + let bootNode: BootstrapNode; let bootNodePeerId: PeerId; let port = 1234; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 91d0dd93a38..b34939ce8ee 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -732,7 +732,7 @@ describe('Private Execution test suite', () => { const secret = new Fr(1n); const secretHash = computeSecretHash(secret); const note = new Note([secretHash]); - // @todo @LHerskind Need to investigate why this was working with `new Fr(5)` as the `example_set = 2` should have caused a failure. + // @todo @LHerskind (#6001) Need to investigate why this was working with `new Fr(5)` as the `example_set = 2` should have caused a failure. const storageSlot = TestContractArtifact.storageLayout['example_set'].slot; oracle.getNotes.mockResolvedValue([ {