Check inheritance tree consistency (#2727)

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
This commit is contained in:
Hadrien Croubois
2021-06-18 17:08:13 +02:00
committed by GitHub
parent 27e09007cc
commit 4d0f8c1da8
5 changed files with 173 additions and 3 deletions

View File

@ -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

View File

@ -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
View File

@ -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",

View File

@ -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",

View 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.');
}