diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fef538e..0f9b0199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes will be documented in this file. Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. ## 12.0.0 + - [Breaking change: Implementation of topological sort to sort custom types by their type dependencies (change attribute visibility)](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/224) ## 11.0.0 - [Breaking change: Sender is now mandatory when constructing a transaction](https://github.com/ElrondNetwork/elrond-sdk-erdjs/pull/TBD) diff --git a/package-lock.json b/package-lock.json index 75bca5df..430b15b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2519,9 +2519,9 @@ } }, "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.1.tgz", + "integrity": "sha512-OvgH5rB0XM+iDZGQ1Eg/o7IZn0XYJFVrN/9FQ4OWIYILyJJgVP2s1hLTOFn6UOZoDUI/HctGa0PFlE2n2HW3NQ==", "dev": true }, "node_modules/falafel": { @@ -7961,9 +7961,9 @@ }, "dependencies": { "type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/type/-/type-2.6.1.tgz", + "integrity": "sha512-OvgH5rB0XM+iDZGQ1Eg/o7IZn0XYJFVrN/9FQ4OWIYILyJJgVP2s1hLTOFn6UOZoDUI/HctGa0PFlE2n2HW3NQ==", "dev": true } } diff --git a/src/smartcontracts/typesystem/abiRegistry.ts b/src/smartcontracts/typesystem/abiRegistry.ts index ecb3377b..1438db5c 100644 --- a/src/smartcontracts/typesystem/abiRegistry.ts +++ b/src/smartcontracts/typesystem/abiRegistry.ts @@ -9,7 +9,7 @@ import { EndpointDefinition, EndpointParameterDefinition } from "./endpoint"; export class AbiRegistry { readonly interfaces: ContractInterface[] = []; - readonly customTypes: CustomType[] = []; + private customTypes: CustomType[] = []; static create(json: { name: string; endpoints: any[]; types: any[] }): AbiRegistry { let registry = new AbiRegistry().extend(json); @@ -49,17 +49,37 @@ export class AbiRegistry { } private sortCustomTypesByDependencies() { - // TODO: Improve consistency of the sorting function (and make sure the sorting is stable): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort - this.customTypes.sort((a: CustomType, b: CustomType) => { - const bDependsOnA = b.getNamesOfDependencies().indexOf(a.getName()) > -1; - if (bDependsOnA) { - // Sort "a" before "b". - return -1; + // Use of topological sort algorithm to sort custom types by dependencies. + let dependencies: { [key: string]: string[] } = {}; + let visited: { [key: string]: boolean } = {}; + this.customTypes.forEach((type: CustomType) => { + dependencies[type.getName()] = type.getNamesOfDependencies(); + visited[type.getName()] = false; + }); + let sortedArray = new Array(); + + const topologicalSortUtil = (name: string, visited: { [key: string]: boolean }, sortedArray: CustomType[]) => { + visited[name] = true; + + for (const dependency of dependencies[name]) { + if (!this.customTypes.find((e) => e.getName() == dependency)) continue; + if (!visited[dependency]) { + topologicalSortUtil(dependency, visited, sortedArray); + } } + const type = this.customTypes.find((e) => e.getName() == name); + if (type) { + sortedArray.push(type); + } + }; - // Sort "b" before "a". - return 1; - }); + for (const type of this.customTypes) { + if (!visited[type.getName()]) { + topologicalSortUtil(type.getName(), visited, sortedArray); + } + } + + this.customTypes = sortedArray; } getInterface(name: string): ContractInterface { diff --git a/src/testdata/custom-types-out-of-order.abi.json b/src/testdata/custom-types-out-of-order.abi.json index aa407c32..899cc0ae 100644 --- a/src/testdata/custom-types-out-of-order.abi.json +++ b/src/testdata/custom-types-out-of-order.abi.json @@ -22,6 +22,15 @@ } ] }, + "TypeC": { + "type": "struct", + "fields": [ + { + "name": "foobar", + "type": "u64" + } + ] + }, "EsdtTokenType": { "type": "enum", "variants": [ @@ -35,15 +44,6 @@ } ] }, - "TypeA": { - "type": "struct", - "fields": [ - { - "name": "b", - "type": "TypeB" - } - ] - }, "TypeB": { "type": "struct", "fields": [ @@ -53,12 +53,12 @@ } ] }, - "TypeC": { + "TypeA": { "type": "struct", "fields": [ { - "name": "foobar", - "type": "u64" + "name": "b", + "type": "TypeB" } ] }