From 95580a0c851aa1112dfecf031b85e3cbefcd47f1 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Apr 2019 14:30:46 +0530 Subject: [PATCH 1/4] Added clash checker script --- contracts/mocks/functionSigClash1 | 4 +++ contracts/mocks/functionSigClash2 | 4 +++ scripts/clashCheck.js | 48 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 contracts/mocks/functionSigClash1 create mode 100644 contracts/mocks/functionSigClash2 create mode 100644 scripts/clashCheck.js diff --git a/contracts/mocks/functionSigClash1 b/contracts/mocks/functionSigClash1 new file mode 100644 index 000000000..b991a51e0 --- /dev/null +++ b/contracts/mocks/functionSigClash1 @@ -0,0 +1,4 @@ +contract functionSigClash1 { + function clash550254402() public { + } +} diff --git a/contracts/mocks/functionSigClash2 b/contracts/mocks/functionSigClash2 new file mode 100644 index 000000000..deb1be836 --- /dev/null +++ b/contracts/mocks/functionSigClash2 @@ -0,0 +1,4 @@ +contract functionSigClash2 { + function proxyOwner() public { + } +} diff --git a/scripts/clashCheck.js b/scripts/clashCheck.js new file mode 100644 index 000000000..ca4e53a7c --- /dev/null +++ b/scripts/clashCheck.js @@ -0,0 +1,48 @@ +const fs = require('fs'); +const exec = require('child_process').execSync; +const chalk = require('chalk'); +const Web3 = require('web3'); + +async function readFiles() { + if (fs.existsSync("./build/contracts/")) { + return fs.readdirSync("./build/contracts/"); + } else { + console.log(chalk.yellow('Compiling contracts. This may take a while, please wait.')); + exec('truffle compile'); + return fs.readdirSync("./build/contracts/"); + } +} + +async function checkClashes() { + let files = await readFiles(); + let contractFunctions = new Set(); + let functionSelectors = new Map(); + files.forEach(item => { + let ABI = JSON.parse(fs.readFileSync(`./build/contracts/${item}`).toString()).abi; + ABI.forEach(element => { + if (element['type'] == 'function') { + let functionSig = element['name'] + '('; + element['inputs'].forEach(input => { + functionSig = functionSig + input['type'] + ','; + }); + if(functionSig[functionSig.length - 1] == ',') + functionSig = functionSig.slice(0, -1) + ')'; + else + functionSig = functionSig + ')'; + contractFunctions.add(functionSig); + } + }); + }); + contractFunctions.forEach(functionSig => { + let fnSelector = Web3.utils.sha3(functionSig).slice(0, 10); + if(functionSelectors.has(fnSelector)) { + console.log(chalk.red('Function selector clash found!', functionSelectors.get(fnSelector), 'and', functionSig, 'have the same function selector:', fnSelector)); + functionSelectors.set(fnSelector, functionSelectors.get(fnSelector) + ', ' + functionSig); + } else { + functionSelectors.set(fnSelector, functionSig); + } + }); + console.log(chalk.green("Clash check finished. If you don't see any red error messages, you are good to go.")); +} + +checkClashes(); \ No newline at end of file From 121c4dd3489ce75d4cae2417707801639505b51e Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Apr 2019 14:40:51 +0530 Subject: [PATCH 2/4] Beutified function selector clash check script --- contracts/mocks/FunctionSigClash1.sol | 4 ++++ contracts/mocks/FunctionSigClash2.sol | 4 ++++ contracts/mocks/functionSigClash1 | 4 ---- contracts/mocks/functionSigClash2 | 4 ---- scripts/clashCheck.js | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 contracts/mocks/FunctionSigClash1.sol create mode 100644 contracts/mocks/FunctionSigClash2.sol delete mode 100644 contracts/mocks/functionSigClash1 delete mode 100644 contracts/mocks/functionSigClash2 diff --git a/contracts/mocks/FunctionSigClash1.sol b/contracts/mocks/FunctionSigClash1.sol new file mode 100644 index 000000000..51f505ade --- /dev/null +++ b/contracts/mocks/FunctionSigClash1.sol @@ -0,0 +1,4 @@ +contract functionSigClash1 { + // function clash550254402() public { + // } +} diff --git a/contracts/mocks/FunctionSigClash2.sol b/contracts/mocks/FunctionSigClash2.sol new file mode 100644 index 000000000..0cd0e9f9e --- /dev/null +++ b/contracts/mocks/FunctionSigClash2.sol @@ -0,0 +1,4 @@ +contract functionSigClash2 { + // function proxyOwner() public { + // } +} diff --git a/contracts/mocks/functionSigClash1 b/contracts/mocks/functionSigClash1 deleted file mode 100644 index b991a51e0..000000000 --- a/contracts/mocks/functionSigClash1 +++ /dev/null @@ -1,4 +0,0 @@ -contract functionSigClash1 { - function clash550254402() public { - } -} diff --git a/contracts/mocks/functionSigClash2 b/contracts/mocks/functionSigClash2 deleted file mode 100644 index deb1be836..000000000 --- a/contracts/mocks/functionSigClash2 +++ /dev/null @@ -1,4 +0,0 @@ -contract functionSigClash2 { - function proxyOwner() public { - } -} diff --git a/scripts/clashCheck.js b/scripts/clashCheck.js index ca4e53a7c..9435f6080 100644 --- a/scripts/clashCheck.js +++ b/scripts/clashCheck.js @@ -14,6 +14,7 @@ async function readFiles() { } async function checkClashes() { + console.log(chalk.green("Starting function selector clash check")); let files = await readFiles(); let contractFunctions = new Set(); let functionSelectors = new Map(); From 5d43466a642828343f12cf84ff35b09747c73b6f Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Apr 2019 14:56:46 +0530 Subject: [PATCH 3/4] Throw on finding a clash --- package.json | 1 + scripts/clashCheck.js | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a33a07af8..3adad2e2c 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ }, "scripts": { "test": "scripts/test.sh 2> /dev/null", + "clash-check": "node scripts/clashCheck.js", "gas": "scripts/gasUsage.sh", "wintest": "scripts\\wintest.cmd", "wincov": "scripts\\wincov.cmd", diff --git a/scripts/clashCheck.js b/scripts/clashCheck.js index 9435f6080..09f36d31c 100644 --- a/scripts/clashCheck.js +++ b/scripts/clashCheck.js @@ -34,16 +34,22 @@ async function checkClashes() { } }); }); + let clashesFound = false; contractFunctions.forEach(functionSig => { let fnSelector = Web3.utils.sha3(functionSig).slice(0, 10); if(functionSelectors.has(fnSelector)) { + clashesFound = true; console.log(chalk.red('Function selector clash found!', functionSelectors.get(fnSelector), 'and', functionSig, 'have the same function selector:', fnSelector)); functionSelectors.set(fnSelector, functionSelectors.get(fnSelector) + ', ' + functionSig); } else { functionSelectors.set(fnSelector, functionSig); } }); - console.log(chalk.green("Clash check finished. If you don't see any red error messages, you are good to go.")); + if (clashesFound) { + console.log(chalk.yellow("The clash(es) might be in two different contracts and hence not be am Issue.\nThis script can not detect this (yet) because of proxy contracts")); + throw("Clash(es) found! Please fix."); + } + console.log(chalk.green("Clash check finished. No Clashes found.")); } checkClashes(); \ No newline at end of file From 801cafcb9caa09e7b6bf88f839ad55de2d81fec8 Mon Sep 17 00:00:00 2001 From: Mudit Gupta Date: Tue, 2 Apr 2019 14:58:20 +0530 Subject: [PATCH 4/4] Added circle CI job --- .circleci/config.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8bd70f869..42c27b22c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -54,6 +54,21 @@ jobs: - node_modules - store_artifacts: path: ./coverage/lcov.info + clash-check: + docker: + - image: maxsam4/solidity-kit + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ checksum "package.json" }} + - run: yarn install + - run: node --version + - run: truffle version + - run: npm run clash-check + - save_cache: + key: dependency-cache-{{ checksum "package.json" }} + paths: + - node_modules docs: docker: - image: maxsam4/solidity-kit @@ -74,6 +89,7 @@ workflows: commit: jobs: - coverage + - clash-check daily-builds: triggers: - schedule: