Skip to content

Commit aba568a

Browse files
sklppy88nventuro
andauthored
fix: sorting artifact props and members in metadata (#9772)
After discussions with @spalladino, it was decided to use the schema parser to enforce object property ordering, and a schema transform to enforce array ordering. This PR is enabled to work by the schema work done by @spalladino, and simply sorts our known arrays that are normally outputted in a non-deterministic fashion by the noir compiler. --------- Co-authored-by: Nicolás Venturo <nicolas.venturo@gmail.com>
1 parent c6b65ab commit aba568a

File tree

4 files changed

+33
-10
lines changed

4 files changed

+33
-10
lines changed

yarn-project/circuits.js/src/contract/artifact_hash.test.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { type ContractArtifact } from '@aztec/foundation/abi';
2+
import { loadContractArtifact } from '@aztec/types/abi';
3+
import type { NoirCompiledContract } from '@aztec/types/noir';
24

3-
import { getTestContractArtifact } from '../tests/fixtures.js';
5+
import { readFileSync } from 'fs';
6+
7+
import { getPathToFixture, getTestContractArtifact } from '../tests/fixtures.js';
48
import { computeArtifactHash } from './artifact_hash.js';
59

610
describe('ArtifactHash', () => {
@@ -17,7 +21,7 @@ describe('ArtifactHash', () => {
1721
notes: {},
1822
};
1923
expect(computeArtifactHash(emptyArtifact).toString()).toMatchInlineSnapshot(
20-
`"0x0c6fd9b48570721c5d36f978d084d77cacbfd2814f1344985f40e62bea6e61be"`,
24+
`"0x0dea64e7fa0688017f77bcb7075485485afb4a5f1f8508483398869439f82fdf"`,
2125
);
2226
});
2327

@@ -26,8 +30,20 @@ describe('ArtifactHash', () => {
2630

2731
for (let i = 0; i < 1000; i++) {
2832
expect(computeArtifactHash(testArtifact).toString()).toMatchInlineSnapshot(
29-
`"0x11ba97d2d4de6335cc86d271d3c4a6237840cf630eaa442cf75d1666ff475f61"`,
33+
`"0x237feccc8e34a39c0e5133c8653fc278b39275bfa3f7459e4aba07d53b752c19"`,
3034
);
3135
}
3236
});
37+
38+
it('calculates the test contract artifact hash', () => {
39+
const path = getPathToFixture('Test.test.json');
40+
const content = JSON.parse(readFileSync(path).toString()) as NoirCompiledContract;
41+
content.outputs.structs.functions.reverse();
42+
43+
const testArtifact = loadContractArtifact(content);
44+
45+
expect(computeArtifactHash(testArtifact).toString()).toMatchInlineSnapshot(
46+
`"0x237feccc8e34a39c0e5133c8653fc278b39275bfa3f7459e4aba07d53b752c19"`,
47+
);
48+
});
3349
});

yarn-project/circuits.js/src/contract/artifact_hash.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,7 @@ export function computeArtifactHashPreimage(artifact: ContractArtifact) {
5959
}
6060

6161
export function computeArtifactMetadataHash(artifact: ContractArtifact) {
62-
// TODO: #6021 We need to make sure the artifact is deterministic from any specific compiler run. This relates to selectors not being sorted and being
63-
// apparently random in the order they appear after compiled w/ nargo. We can try to sort this upon loading an artifact.
64-
// TODO: #6021: Should we use the sorted event selectors instead? They'd need to be unique for that.
65-
// Response - The output selectors need to be sorted, because if not noir makes no guarantees on the order of outputs for some reason
66-
return sha256Fr(Buffer.from(JSON.stringify({ name: artifact.name }), 'utf-8'));
62+
return sha256Fr(Buffer.from(JSON.stringify({ name: artifact.name, outputs: artifact.outputs }), 'utf-8'));
6763
}
6864

6965
export function computeArtifactFunctionTreeRoot(artifact: ContractArtifact, fnType: FunctionType) {

yarn-project/circuits.js/src/tests/fixtures.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ export function getSampleUnconstrainedFunctionBroadcastedEventPayload(): Buffer
4848
return Buffer.from(readFileSync(path).toString(), 'hex');
4949
}
5050

51-
function getPathToFixture(name: string) {
51+
export function getPathToFixture(name: string) {
5252
return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`);
5353
}

yarn-project/foundation/src/abi/abi.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,18 @@ export const ContractArtifactSchema: ZodFor<ContractArtifact> = z.object({
358358
aztecNrVersion: z.string().optional(),
359359
functions: z.array(FunctionArtifactSchema),
360360
outputs: z.object({
361-
structs: z.record(z.array(AbiTypeSchema)),
361+
structs: z.record(z.array(AbiTypeSchema)).transform(structs => {
362+
for (const [key, value] of Object.entries(structs)) {
363+
// We are manually ordering events and functions in the abi by path.
364+
// The path ordering is arbitrary, and only needed to ensure deterministic order.
365+
// These are the only arrays in the artifact with arbitrary order, and hence the only ones
366+
// we need to sort.
367+
if (key === 'events' || key === 'functions') {
368+
structs[key] = (value as StructType[]).sort((a, b) => (a.path > b.path ? -1 : 1));
369+
}
370+
}
371+
return structs;
372+
}),
362373
globals: z.record(z.array(AbiValueSchema)),
363374
}),
364375
storageLayout: z.record(z.object({ slot: schemas.Fr })),

0 commit comments

Comments
 (0)