Procházet zdrojové kódy

Check inheritance tree consistency (#2727)

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
Hadrien Croubois před 4 roky
rodič
revize
4d0f8c1da8

+ 1 - 0
.github/workflows/test.yml

@@ -29,6 +29,7 @@ jobs:
         env:
           FORCE_COLOR: 1
           ENABLE_GAS_REPORT: true
+      - run: npm run test:inheritance 
       - name: Print gas report
         run: cat gas-report.txt
 

+ 1 - 1
contracts/mocks/ERC1155ReceiverMock.sol

@@ -5,7 +5,7 @@ pragma solidity ^0.8.0;
 import "../token/ERC1155/IERC1155Receiver.sol";
 import "../utils/introspection/ERC165.sol";
 
-contract ERC1155ReceiverMock is IERC1155Receiver, ERC165 {
+contract ERC1155ReceiverMock is ERC165, IERC1155Receiver {
     bytes4 private _recRetval;
     bool private _recReverts;
     bytes4 private _batRetval;

+ 130 - 2
package-lock.json

@@ -27,6 +27,7 @@
         "eth-sig-util": "^3.0.0",
         "ethereumjs-util": "^7.0.7",
         "ethereumjs-wallet": "^1.0.1",
+        "graphlib": "^2.1.8",
         "hardhat": "^2.0.6",
         "hardhat-gas-reporter": "^1.0.4",
         "keccak256": "^1.0.2",
@@ -38,6 +39,7 @@
         "prettier-plugin-solidity": "^1.0.0-beta.13",
         "rimraf": "^3.0.2",
         "solhint": "^3.3.6",
+        "solidity-ast": "^0.4.25",
         "solidity-coverage": "^0.7.11",
         "solidity-docgen": "^0.5.3",
         "web3": "^1.3.0",
@@ -7713,7 +7715,104 @@
       "bundleDependencies": [
         "source-map-support",
         "yargs",
-        "ethereumjs-util"
+        "ethereumjs-util",
+        "@types/bn.js",
+        "@types/node",
+        "@types/pbkdf2",
+        "@types/secp256k1",
+        "ansi-regex",
+        "ansi-styles",
+        "base-x",
+        "blakejs",
+        "bn.js",
+        "brorand",
+        "browserify-aes",
+        "bs58",
+        "bs58check",
+        "buffer-from",
+        "buffer-xor",
+        "camelcase",
+        "cipher-base",
+        "cliui",
+        "color-convert",
+        "color-name",
+        "create-hash",
+        "create-hmac",
+        "cross-spawn",
+        "decamelize",
+        "elliptic",
+        "emoji-regex",
+        "end-of-stream",
+        "ethereum-cryptography",
+        "ethjs-util",
+        "evp_bytestokey",
+        "execa",
+        "find-up",
+        "get-caller-file",
+        "get-stream",
+        "hash-base",
+        "hash.js",
+        "hmac-drbg",
+        "inherits",
+        "invert-kv",
+        "is-fullwidth-code-point",
+        "is-hex-prefixed",
+        "is-stream",
+        "isexe",
+        "keccak",
+        "lcid",
+        "locate-path",
+        "map-age-cleaner",
+        "md5.js",
+        "mem",
+        "mimic-fn",
+        "minimalistic-assert",
+        "minimalistic-crypto-utils",
+        "nice-try",
+        "node-addon-api",
+        "node-gyp-build",
+        "npm-run-path",
+        "once",
+        "os-locale",
+        "p-defer",
+        "p-finally",
+        "p-is-promise",
+        "p-limit",
+        "p-locate",
+        "p-try",
+        "path-exists",
+        "path-key",
+        "pbkdf2",
+        "pump",
+        "randombytes",
+        "readable-stream",
+        "require-directory",
+        "require-main-filename",
+        "ripemd160",
+        "rlp",
+        "safe-buffer",
+        "scrypt-js",
+        "secp256k1",
+        "semver",
+        "set-blocking",
+        "setimmediate",
+        "sha.js",
+        "shebang-command",
+        "shebang-regex",
+        "signal-exit",
+        "source-map",
+        "string_decoder",
+        "string-width",
+        "strip-ansi",
+        "strip-eof",
+        "strip-hex-prefix",
+        "util-deprecate",
+        "which",
+        "which-module",
+        "wrap-ansi",
+        "wrappy",
+        "y18n",
+        "yargs-parser"
       ],
       "dev": true,
       "dependencies": {
@@ -9040,6 +9139,15 @@
       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
       "dev": true
     },
+    "node_modules/graphlib": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
+      "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
+      "dev": true,
+      "dependencies": {
+        "lodash": "^4.17.15"
+      }
+    },
     "node_modules/growl": {
       "version": "1.10.5",
       "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@@ -15965,6 +16073,12 @@
         "node": ">=4"
       }
     },
+    "node_modules/solidity-ast": {
+      "version": "0.4.25",
+      "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.25.tgz",
+      "integrity": "sha512-8IpweS/vgHEpKvY4l0sfr3EsHk+JFIzRWqq/0JefRjzP/Wyi2xZYfx8aHlJ9kcEn2M2RCQK9PexuZ+scaa83OQ==",
+      "dev": true
+    },
     "node_modules/solidity-comments-extractor": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz",
@@ -20678,7 +20792,6 @@
       "integrity": "sha512-5vwpq6kbvwkQwKqAoOU3L72GZ3Ta8RRrewKj9OJRolx28KLJJ8Dg9Rf7obRwt5jQA9bkYd8gqzMTrI7H3xLfaw==",
       "dev": true,
       "requires": {
-        "@oclif/config": "^1.15.1",
         "@oclif/errors": "^1.3.3",
         "@oclif/parser": "^3.8.3",
         "@oclif/plugin-help": "^3",
@@ -27034,6 +27147,15 @@
       "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
       "dev": true
     },
+    "graphlib": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
+      "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
+      "dev": true,
+      "requires": {
+        "lodash": "^4.17.15"
+      }
+    },
     "growl": {
       "version": "1.10.5",
       "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@@ -32535,6 +32657,12 @@
         }
       }
     },
+    "solidity-ast": {
+      "version": "0.4.25",
+      "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.25.tgz",
+      "integrity": "sha512-8IpweS/vgHEpKvY4l0sfr3EsHk+JFIzRWqq/0JefRjzP/Wyi2xZYfx8aHlJ9kcEn2M2RCQK9PexuZ+scaa83OQ==",
+      "dev": true
+    },
     "solidity-comments-extractor": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz",

+ 3 - 0
package.json

@@ -28,6 +28,7 @@
     "release": "scripts/release/release.sh",
     "version": "scripts/release/version.sh",
     "test": "hardhat test",
+    "test:inheritance": "node scripts/inheritanceOrdering artifacts/build-info/*",
     "gas-report": "env ENABLE_GAS_REPORT=true npm run test"
   },
   "repository": {
@@ -64,6 +65,7 @@
     "eth-sig-util": "^3.0.0",
     "ethereumjs-util": "^7.0.7",
     "ethereumjs-wallet": "^1.0.1",
+    "graphlib": "^2.1.8",
     "hardhat": "^2.0.6",
     "hardhat-gas-reporter": "^1.0.4",
     "keccak256": "^1.0.2",
@@ -75,6 +77,7 @@
     "prettier-plugin-solidity": "^1.0.0-beta.13",
     "rimraf": "^3.0.2",
     "solhint": "^3.3.6",
+    "solidity-ast": "^0.4.25",
     "solidity-coverage": "^0.7.11",
     "solidity-docgen": "^0.5.3",
     "web3": "^1.3.0",

+ 38 - 0
scripts/inheritanceOrdering.js

@@ -0,0 +1,38 @@
+const path = require('path');
+const graphlib = require('graphlib');
+const { findAll } = require('solidity-ast/utils');
+const { _: artifacts } = require('yargs').argv;
+
+for (const artifact of artifacts) {
+  const { output: solcOutput } = require(path.resolve(__dirname, '..', artifact));
+
+  const graph = new graphlib.Graph({ directed: true });
+  const names = {};
+  const linearized = [];
+
+  for (const source in solcOutput.contracts) {
+    for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) {
+      names[contractDef.id] = contractDef.name;
+      linearized.push(contractDef.linearizedBaseContracts);
+
+      contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => contracts.slice(i + 1).forEach(c2 => {
+        graph.setEdge(c1, c2);
+      }));
+    }
+  }
+
+  graphlib.alg.findCycles(graph).forEach(([ c1, c2 ]) => {
+    console.log(`Conflict between ${names[c1]} and ${names[c2]} detected in the following dependency chains:`);
+    linearized
+      .filter(chain => chain.includes(parseInt(c1)) && chain.includes(parseInt(c2)))
+      .forEach(chain => {
+        const comp = chain.indexOf(c1) < chain.indexOf(c2) ? '>' : '<';
+        console.log(`- ${names[c1]} ${comp} ${names[c2]}: ${chain.reverse().map(id => names[id]).join(', ')}`);
+      });
+    process.exitCode = 1;
+  });
+}
+
+if (!process.exitCode) {
+  console.log('Contract ordering is consistent.');
+}