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 c6261e83bd1..c965dbc57b5 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -1,6 +1,7 @@ import { type ContractArtifact } from '@aztec/foundation/abi'; import { computeArtifactHash } from './artifact_hash.js'; +import { getTestContractArtifact } from '../tests/fixtures.js'; describe('ArtifactHash', () => { it('calculates the artifact hash', () => { @@ -19,4 +20,14 @@ describe('ArtifactHash', () => { `"0x0c6fd9b48570721c5d36f978d084d77cacbfd2814f1344985f40e62bea6e61be"`, ); }); + + it('calculates the test contract artifact hash multiple times to ensure deterministic hashing', () => { + const testArtifact = getTestContractArtifact(); + + for (let i = 0; i < 1000; i++) { + expect(computeArtifactHash(testArtifact).toString()).toMatchInlineSnapshot( + `"0x193c8f0e49d2a1b865f8afec829f3cf0bc136232ce7d09f823192dcc3e876df2"`, + ); + } + }); }); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 4fc0616e78c..cf11ecf5aa3 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, + ContractArtifactSchema, type ContractNote, type FieldLayout, type FunctionArtifact, @@ -133,7 +134,10 @@ type NoirCompiledContractFunction = NoirCompiledContract['functions'][number]; * @param contract - Parent contract. * @returns Function artifact. */ -function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: NoirCompiledContract): FunctionArtifact { +function generateFunctionArtifact( + fn: NoirCompiledContractFunction, + contract: NoirCompiledContract, +): Omit & { bytecode: string } { if (fn.custom_attributes === undefined) { throw new Error( `No custom attributes found for contract function ${fn.name}. Try rebuilding the contract with the latest nargo version.`, @@ -178,7 +182,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction, contract: No isInitializer: fn.custom_attributes.includes(AZTEC_INITIALIZER_ATTRIBUTE), parameters, returnTypes, - bytecode: Buffer.from(fn.bytecode, 'base64'), + bytecode: fn.bytecode, debugSymbols: fn.debug_symbols, errorTypes: fn.abi.error_types, ...(fn.assert_messages ? { assertMessages: fn.assert_messages } : undefined), @@ -238,11 +242,11 @@ function getStorageLayout(input: NoirCompiledContract) { return {}; } - return storageFields.reduce((acc: Record, field) => { + return storageFields.reduce((acc: Record & { slot: string }>, field) => { const name = field.name; const slot = field.value.fields[0].value as IntegerValue; acc[name] = { - slot: Fr.fromString(slot.value), + slot: slot.value, }; return acc; }, {}); @@ -262,7 +266,7 @@ function getNoteTypes(input: NoirCompiledContract) { return {}; } - return notes.reduce((acc: Record, note) => { + return notes.reduce((acc: Record & { id: string }>, note) => { const noteFields = note.fields; // We find note type id by looking for respective kinds as each of them is unique @@ -274,7 +278,7 @@ function getNoteTypes(input: NoirCompiledContract) { throw new Error(`Could not find note type id, name or fields for note ${note}`); } - const noteTypeId = NoteSelector.fromField(Fr.fromString(rawNoteTypeId.value)); + const noteTypeId = rawNoteTypeId.value as string; const name = rawName.value as string; // Note type id is encoded as a hex string @@ -301,7 +305,7 @@ function getNoteTypes(input: NoirCompiledContract) { */ function generateContractArtifact(contract: NoirCompiledContract, aztecNrVersion?: string): ContractArtifact { try { - return { + return ContractArtifactSchema.parse({ name: contract.name, functions: contract.functions.map(f => generateFunctionArtifact(f, contract)), outputs: contract.outputs, @@ -309,7 +313,7 @@ function generateContractArtifact(contract: NoirCompiledContract, aztecNrVersion notes: getNoteTypes(contract), fileMap: contract.file_map, ...(aztecNrVersion ? { aztecNrVersion } : {}), - }; + }); } catch (err) { throw new Error(`Could not generate contract artifact for ${contract.name}: ${err}`); }