@@ -58,28 +58,56 @@ export function computeArtifactHashPreimage(artifact: ContractArtifact) {
5858 return { privateFunctionRoot, unconstrainedFunctionRoot, metadataHash } ;
5959}
6060
61- 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
61+ const sortAndHashArtifactMetadata = ( metadata : Record < string | number , NonNullable < any > > ) => {
62+ const obj = structuredClone ( metadata ) ;
6663
67- const metadata = { name : artifact . name , outputs : artifact . outputs } ;
64+ const sortAndHashNestedObject = ( obj : Record < string | number , NonNullable < any > > ) => {
65+ if ( Array . isArray ( obj ) ) {
66+ for ( let i = 0 ; i < obj . length ; i ++ ) {
67+ if ( Array . isArray ( obj [ i ] ) || ( typeof obj [ i ] === 'object' && obj [ i ] !== null ) ) {
68+ obj [ i ] = sortAndHashNestedObject ( obj [ i ] ) ;
69+ }
70+ }
6871
69- const exceptions : string [ ] = [
70- 'AuthRegistry' ,
71- 'FeeJuice' ,
72- 'ContractInstanceDeployer' ,
73- 'ContractClassRegisterer' ,
74- 'Router' ,
75- ] ;
76-
77- // This is a temporary workaround for the canonical contracts to have deterministic deployments.
78- if ( exceptions . includes ( artifact . name ) ) {
79- return sha256Fr ( Buffer . from ( JSON . stringify ( { name : artifact . name } ) , 'utf-8' ) ) ;
80- }
72+ const sorted = obj . sort ( ) ;
73+
74+ const hashed = sha256Fr ( Buffer . from ( JSON . stringify ( sorted ) , 'utf-8' ) ) ;
75+
76+ return hashed ;
77+ }
78+
79+ if ( typeof obj === 'object' ) {
80+ for ( const [ key , value ] of Object . entries ( obj ) ) {
81+ if ( Array . isArray ( value ) || ( typeof value === 'object' && value !== null ) ) {
82+ obj [ key ] = sortAndHashNestedObject ( value ) ;
83+ }
84+ }
85+
86+ const sorted = Object . keys ( obj )
87+ . sort ( )
88+ . reduce (
89+ ( acc , key ) => ( {
90+ ...acc ,
91+ [ key ] : obj [ key ] ,
92+ } ) ,
93+ { } ,
94+ ) ;
95+
96+ const hashed = sha256Fr ( Buffer . from ( JSON . stringify ( sorted ) , 'utf-8' ) ) ;
97+
98+ return hashed ;
99+ }
100+
101+ throw new Error ( 'Can only be called on an object or array' ) ;
102+ } ;
103+
104+ return sortAndHashNestedObject ( obj ) ;
105+ } ;
106+
107+ export function computeArtifactMetadataHash ( artifact : ContractArtifact ) {
108+ const metadata = { name : artifact . name , outputs : artifact . outputs } ;
81109
82- return sha256Fr ( Buffer . from ( JSON . stringify ( metadata ) , 'utf-8' ) ) ;
110+ return sortAndHashArtifactMetadata ( metadata ) ;
83111}
84112
85113export function computeArtifactFunctionTreeRoot ( artifact : ContractArtifact , fnType : FunctionType ) {
0 commit comments