Check inheritance tree consistency (#2727)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
This commit is contained in:
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
132
package-lock.json
generated
132
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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
scripts/inheritanceOrdering.js
Normal file
38
scripts/inheritanceOrdering.js
Normal file
@ -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.');
|
||||
}
|
||||
Reference in New Issue
Block a user