diff --git a/.circleci/config.yml b/.circleci/config.yml index b4ced1a..fdb57df 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,11 +12,9 @@ step_install_nvm: &step_install_nvm set +e export NVM_DIR="/opt/circleci/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - nvm install v14.19.0 - nvm alias default v14.19.0 + nvm install v18 echo 'export NVM_DIR="/opt/circleci/.nvm"' >> $BASH_ENV echo "[ -s \"$NVM_DIR/nvm.sh\" ] && . \"$NVM_DIR/nvm.sh\"" >> $BASH_ENV - jobs: unit-test: docker: @@ -32,9 +30,13 @@ jobs: command: | yarn - run: - name: Run tests + name: Tests ( optimizer.enabled=false ) command: | npm run test:ci + - run: + name: Tests ( viaIR=true ) + command: | + npm run test:ci:viaIR - run: name: Upload coverage command: | diff --git a/lib/api.js b/lib/api.js index 296fcb4..8632dcc 100644 --- a/lib/api.js +++ b/lib/api.js @@ -54,6 +54,7 @@ class API { this.istanbulFolder = config.istanbulFolder || false; this.istanbulReporter = config.istanbulReporter || ['html', 'lcov', 'text', 'json']; + this.viaIR = config.viaIR; this.solcOptimizerDetails = config.solcOptimizerDetails; this.setLoggingLevel(config.silent); @@ -176,7 +177,7 @@ class API { // Hardhat async attachToHardhatVM(provider){ const self = this; - this.collector = new DataCollector(this.instrumenter.instrumentationData); + this.collector = new DataCollector(this.instrumenter.instrumentationData, this.viaIR); if ('init' in provider) { // Newer versions of Hardhat initialize the provider lazily, so we need to diff --git a/lib/collector.js b/lib/collector.js index d43ee7a..062de10 100644 --- a/lib/collector.js +++ b/lib/collector.js @@ -3,12 +3,31 @@ * coverage map constructed by the Instrumenter. */ class DataCollector { - constructor(instrumentationData={}){ + constructor(instrumentationData={}, viaIR){ this.instrumentationData = instrumentationData; this.validOpcodes = { "PUSH1": true, + "DUP1": viaIR, + "DUP2": viaIR, + "DUP3": viaIR, + "DUP4": viaIR, + "DUP5": viaIR, + "DUP6": viaIR, + "DUP7": viaIR, + "DUP8": viaIR, + "DUP9": viaIR, + "DUP10": viaIR, + "DUP11": viaIR, + "DUP12": viaIR, + "DUP13": viaIR, + "DUP14": viaIR, + "DUP15": viaIR, + "DUP16": viaIR, } + + this.lastHash = null; + this.viaIR = viaIR; } /** @@ -46,7 +65,26 @@ class DataCollector { hash = this._normalizeHash(hash); if(this.instrumentationData[hash]){ - this.instrumentationData[hash].hits++; + // abi.encode (used to circumvent viaIR) sometimes puts the hash on the stack twice + if (this.lastHash !== hash) { + this.lastHash = hash; + this.instrumentationData[hash].hits++ + } + return; + } + + // Detect and recover from viaIR mangled hashes by left-padding single `0` + if(this.viaIR && hash.length === 18) { + hash = hash.slice(2); + hash = '0' + hash; + hash = hash.slice(0,16); + hash = '0x' + hash; + if(this.instrumentationData[hash]){ + if (this.lastHash !== hash) { + this.lastHash = hash; + this.instrumentationData[hash].hits++ + } + } } } @@ -56,10 +94,14 @@ class DataCollector { * but prevents left-padding shorter irrelevant hashes * * @param {String} hash data hash from evm stack. - * @return {String} 0x prefixed hash of length 66. + * @return {String} 0x prefixed hash of length 18. */ _normalizeHash(hash){ - if (hash.length < 18 && hash.length > 11){ + // viaIR sometimes right-pads the hashes out to 32 bytes + // but it doesn't preserve leading zeroes when it does this + if (this.viaIR && hash.length >= 18) { + hash = hash.slice(0,18); + } else if (hash.length < 18 && hash.length > 11){ hash = hash.slice(2); while(hash.length < 16) hash = '0' + hash; hash = '0x' + hash diff --git a/lib/injector.js b/lib/injector.js index e1bd0b0..693a28f 100644 --- a/lib/injector.js +++ b/lib/injector.js @@ -1,7 +1,8 @@ const web3Utils = require("web3-utils"); class Injector { - constructor(){ + constructor(viaIR){ + this.viaIR = viaIR; this.hashCounter = 0; this.modifierCounter = 0; this.modifiers = {}; @@ -23,7 +24,9 @@ class Injector { case 'modifier': return ` ${this._getModifierIdentifier(id)} `; default: - return `${this._getDefaultMethodIdentifier(id)}(${hash}); /* ${type} */ \n`; + return (this.viaIR) + ? `${this._getAbiEncodeStatementHash(hash)} /* ${type} */ \n` + : `${this._getDefaultMethodIdentifier(id)}(${hash}); /* ${type} */ \n`; } } @@ -51,6 +54,16 @@ class Injector { return `c_mod${web3Utils.keccak256(id).slice(2,10)}` } + // Way to get hash on the stack with viaIR (which seems to ignore abi.encode builtin) + // Tested with v0.8.17, v0.8.24 + _getAbiEncodeStatementHash(hash){ + return `abi.encode(${hash}); ` + } + + _getAbiEncodeStatementVar(hash){ + return `abi.encode(c__${hash}); ` + } + _getInjectionComponents(contract, injectionPoint, id, type){ const { start, end } = this._split(contract, injectionPoint); const hash = this._getHash(id) @@ -73,7 +86,10 @@ class Injector { _getDefaultMethodDefinition(id){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getDefaultMethodIdentifier(id); - return `\nfunction ${method}(bytes8 c__${hash}) internal pure {}\n`; + + return (this.viaIR) + ? `` + : `\nfunction ${method}(bytes8 c__${hash}) internal pure {}\n`; } /** @@ -85,7 +101,11 @@ class Injector { _getFileScopedHashMethodDefinition(id, contract){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getDefaultMethodIdentifier(id); - return `\nfunction ${method}(bytes8 c__${hash}) pure {}\n`; + const abi = this._getAbiEncodeStatementVar(hash); + + return (this.viaIR) + ? `\nfunction ${method}(bytes8 c__${hash}) pure { ${abi} }\n` + : `\nfunction ${method}(bytes8 c__${hash}) pure {}\n`; } /** @@ -97,7 +117,11 @@ class Injector { _getTrueMethodDefinition(id){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getTrueMethodIdentifier(id); - return `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ return true; }\n`; + const abi = this._getAbiEncodeStatementVar(hash); + + return (this.viaIR) + ? `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ ${abi} return true; }\n` + : `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ return true; }\n`; } /** @@ -110,7 +134,11 @@ class Injector { _getFileScopeTrueMethodDefinition(id){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getTrueMethodIdentifier(id); - return `function ${method}(bytes8 c__${hash}) pure returns (bool){ return true; }\n`; + const abi = this._getAbiEncodeStatementVar(hash); + + return (this.viaIR) + ? `function ${method}(bytes8 c__${hash}) pure returns (bool){ ${abi} return true; }\n` + : `function ${method}(bytes8 c__${hash}) pure returns (bool){ return true; }\n`; } /** @@ -122,7 +150,11 @@ class Injector { _getFalseMethodDefinition(id){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getFalseMethodIdentifier(id); - return `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ return false; }\n`; + const abi = this._getAbiEncodeStatementVar(hash); + + return (this.viaIR) + ? `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ ${abi} return false; }\n` + : `function ${method}(bytes8 c__${hash}) internal pure returns (bool){ return false; }\n`; } /** @@ -135,7 +167,11 @@ class Injector { _getFileScopedFalseMethodDefinition(id){ const hash = web3Utils.keccak256(id).slice(2,10); const method = this._getFalseMethodIdentifier(id); - return `function ${method}(bytes8 c__${hash}) pure returns (bool){ return false; }\n`; + const abi = this._getAbiEncodeStatementVar(hash); + + return (this.viaIR) + ? `function ${method}(bytes8 c__${hash}) pure returns (bool){ ${abi} return false; }\n` + : `function ${method}(bytes8 c__${hash}) pure returns (bool){ return false; }\n`; } _getModifierDefinitions(contractId, instrumentation){ diff --git a/lib/instrumenter.js b/lib/instrumenter.js index 68bcfe0..4ae909a 100644 --- a/lib/instrumenter.js +++ b/lib/instrumenter.js @@ -14,7 +14,7 @@ class Instrumenter { constructor(config={}){ this.instrumentationData = {}; - this.injector = new Injector(); + this.injector = new Injector(config.viaIR); this.modifierWhitelist = config.modifierWhitelist || []; this.enabled = { statements: (config.measureStatementCoverage === false) ? false : true, diff --git a/package.json b/package.json index 299e164..e93460a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "scripts": { "test:unit": "./scripts/unit.sh", "test:integration": "./scripts/integration.sh", - "test:ci": "./scripts/ci.sh" + "test:ci": "./scripts/ci.sh", + "test:uint:viaIR": "VIA_IR=true ./scripts/unit.sh", + "test:integration:viaIR": "VIA_IR=true ./scripts/integration.sh", + "test:ci:viaIR": "VIA_IR=true ./scripts/ci.sh" }, "homepage": "https://github.com/sc-forks/solidity-coverage", "repository": { diff --git a/plugins/hardhat.plugin.js b/plugins/hardhat.plugin.js index e11a58a..ab8805f 100644 --- a/plugins/hardhat.plugin.js +++ b/plugins/hardhat.plugin.js @@ -54,11 +54,14 @@ subtask(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE).setAction(async (_, } // Unset useLiteralContent due to solc metadata size restriction settings.metadata.useLiteralContent = false; - // Override optimizer settings for all compilers - settings.optimizer.enabled = false; - // This is fixes a stack too deep bug in ABIEncoderV2 - // Experimental because not sure this works as expected across versions.... + // Beginning with v0.8.7, we let the optimizer run if viaIR is true and + // instrument using `abi.encode(bytes8 covHash)`. Otherwise turn the optimizer off. + if (!settings.viaIR) settings.optimizer.enabled = false; + + // This sometimes fixed a stack-too-deep bug in ABIEncoderV2 for coverage plugin versions up to 0.8.6 + // Although issue should be fixed in 0.8.7, am leaving this option in because it may still be necessary + // to configure optimizer details in some cases. if (configureYulOptimizer) { if (optimizerDetails === undefined) { settings.optimizer.details = { diff --git a/plugins/resources/nomiclabs.utils.js b/plugins/resources/nomiclabs.utils.js index 2966d08..110199b 100644 --- a/plugins/resources/nomiclabs.utils.js +++ b/plugins/resources/nomiclabs.utils.js @@ -36,6 +36,10 @@ function normalizeConfig(config, args={}){ ? sources = path.join(config.paths.sources, args.sources) : sources = config.paths.sources; + if (config.solidity && config.solidity.compilers.length) { + config.viaIR = isUsingViaIR(config.solidity); + } + config.workingDir = config.paths.root; config.contractsDir = sources; config.testDir = config.paths.tests; @@ -55,6 +59,23 @@ function normalizeConfig(config, args={}){ return config; } +function isUsingViaIR(solidity) { + + for (compiler of solidity.compilers) { + if (compiler.settings && compiler.settings.viaIR) { + return true; + } + } + if (solidity.overrides) { + for (key of Object.keys(solidity.overrides)){ + if (solidity.overrides[key].settings && solidity.overrides[key].settings.viaIR) { + return true; + } + } + } + return false; +} + async function setupHardhatNetwork(env, api, ui){ const hardhatPackage = require('hardhat/package.json'); const { createProvider } = require("hardhat/internal/core/providers/construction"); diff --git a/plugins/resources/plugin.utils.js b/plugins/resources/plugin.utils.js index c722a08..f2e9e89 100644 --- a/plugins/resources/plugin.utils.js +++ b/plugins/resources/plugin.utils.js @@ -227,7 +227,9 @@ function loadSolcoverJS(config={}){ coverageConfig = {}; } - // Truffle writes to coverage config + // viaIR is eval'd in `nomiclab.utils.normalizeConfig` + coverageConfig.viaIR = config.viaIR; + coverageConfig.log = log; coverageConfig.cwd = config.workingDir; coverageConfig.originalContractsDir = config.contractsDir; diff --git a/scripts/ci.sh b/scripts/ci.sh index 84e8d30..849d047 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -1,6 +1,12 @@ #!/usr/bin/env bash -SILENT=true node --max-old-space-size=4096 \ +# Toggles optimizer on/off +VIAR_IR=$VIA_IR + +# Minimize integration test output +SILENT=true + +node --max-old-space-size=4096 \ ./node_modules/.bin/nyc \ --reporter=lcov \ --exclude '**/sc_temp/**' \ diff --git a/scripts/integration.sh b/scripts/integration.sh index c9d080a..ee2112d 100755 --- a/scripts/integration.sh +++ b/scripts/integration.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# Toggles optimizer on/off +VIA_IR=$VIA_IR + node --max-old-space-size=4096 \ ./node_modules/.bin/nyc \ --exclude '**/sc_temp/**' \ diff --git a/scripts/unit.sh b/scripts/unit.sh index e727105..044a566 100755 --- a/scripts/unit.sh +++ b/scripts/unit.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# Toggles optimizer on/off +VIAR_IR=$VIA_IR + node --max-old-space-size=4096 \ ./node_modules/.bin/nyc \ --exclude '**/sc_temp/**' \ diff --git a/scripts/zeppelin.sh b/scripts/zeppelin.sh index 7335361..96418b7 100755 --- a/scripts/zeppelin.sh +++ b/scripts/zeppelin.sh @@ -8,6 +8,7 @@ set -o errexit # Get rid of any caches sudo rm -rf node_modules echo "NVM CURRENT >>>>>" && nvm current +nvm use 18 # Use PR env variables (for forks) or fallback on local if PR not available SED_REGEX="s/git@github.com:/https:\/\/github.com\//" diff --git a/test/integration/standard.js b/test/integration/standard.js index fd4275f..d53ff48 100644 --- a/test/integration/standard.js +++ b/test/integration/standard.js @@ -348,6 +348,31 @@ describe('Hardhat Plugin: standard use cases', function() { verify.lineCoverage(expected); }) + it('detects viaIR when specified in config overrides only', async function(){ + mock.installFullProject('overrides-viaIR'); + mock.hardhatSetupEnv(this); + + await this.env.run("coverage"); + + const expected = [ + { + file: mock.pathToContract(hardhatConfig, 'ContractOverA2.sol'), + pct: 33.33 + }, + { + file: mock.pathToContract(hardhatConfig, 'ContractOverB2.sol'), + pct: 100, + }, + { + file: mock.pathToContract(hardhatConfig, 'ContractOverC2.sol'), + pct: 100, + }, + + ]; + + verify.lineCoverage(expected); + }) + it('locates .coverage_contracts correctly when dir is subfolder', async function(){ mock.installFullProject('contract-subfolders'); mock.hardhatSetupEnv(this); diff --git a/test/sources/projects/contract-subfolders/hardhat.config.js b/test/sources/projects/contract-subfolders/hardhat.config.js index 4e58d0c..a974066 100644 --- a/test/sources/projects/contract-subfolders/hardhat.config.js +++ b/test/sources/projects/contract-subfolders/hardhat.config.js @@ -8,7 +8,13 @@ module.exports={ } }, solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, paths: { sources: './contracts/A' diff --git a/test/sources/projects/hardhat-compile-config/contracts/ContractA1.sol b/test/sources/projects/hardhat-compile-config/contracts/ContractA1.sol index b6a0b09..ad19d2c 100644 --- a/test/sources/projects/hardhat-compile-config/contracts/ContractA1.sol +++ b/test/sources/projects/hardhat-compile-config/contracts/ContractA1.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.5; +pragma solidity >=0.8.0 <0.9.0; contract ContractA { diff --git a/test/sources/projects/hardhat-compile-config/contracts/ContractB1.sol b/test/sources/projects/hardhat-compile-config/contracts/ContractB1.sol index daa42f7..6d5f53d 100644 --- a/test/sources/projects/hardhat-compile-config/contracts/ContractB1.sol +++ b/test/sources/projects/hardhat-compile-config/contracts/ContractB1.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.0; +pragma solidity >=0.8.0 <0.9.0; contract ContractB { diff --git a/test/sources/projects/hardhat-compile-config/contracts/ContractC1.sol b/test/sources/projects/hardhat-compile-config/contracts/ContractC1.sol index 17ddf97..8c24195 100644 --- a/test/sources/projects/hardhat-compile-config/contracts/ContractC1.sol +++ b/test/sources/projects/hardhat-compile-config/contracts/ContractC1.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.6.0; +pragma solidity >=0.8.0 <0.9.0; contract ContractC { diff --git a/test/sources/projects/hardhat-compile-config/hardhat.config.js b/test/sources/projects/hardhat-compile-config/hardhat.config.js index 443e085..2eee95d 100644 --- a/test/sources/projects/hardhat-compile-config/hardhat.config.js +++ b/test/sources/projects/hardhat-compile-config/hardhat.config.js @@ -5,14 +5,20 @@ module.exports={ solidity: { compilers: [ { - version: "0.5.5" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, { - version: "0.5.7" + version: "0.8.19" }, // Make sure optimizer gets disabled { - version: "0.6.7", + version: "0.8.12", settings: { optimizer: { enabled: true, @@ -23,11 +29,13 @@ module.exports={ ], overrides: { "contracts/ContractA.sol": { - version: "0.5.5", + version: "0.8.24", settings: { optimizer: { enabled: true, - runs: 200 + runs: 200, + viaIR: process.env.VIA_IR === "true", + evmVersion: 'paris' } } } diff --git a/test/sources/projects/hardhat-gas-reporter/hardhat.config.js b/test/sources/projects/hardhat-gas-reporter/hardhat.config.js index e42a38a..87417f5 100644 --- a/test/sources/projects/hardhat-gas-reporter/hardhat.config.js +++ b/test/sources/projects/hardhat-gas-reporter/hardhat.config.js @@ -4,7 +4,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/hardhat-mine/hardhat.config.js b/test/sources/projects/hardhat-mine/hardhat.config.js index 803b099..aac3f87 100644 --- a/test/sources/projects/hardhat-mine/hardhat.config.js +++ b/test/sources/projects/hardhat-mine/hardhat.config.js @@ -4,7 +4,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/hardhat-reset/hardhat.config.js b/test/sources/projects/hardhat-reset/hardhat.config.js index 7954d6c..00428ef 100644 --- a/test/sources/projects/hardhat-reset/hardhat.config.js +++ b/test/sources/projects/hardhat-reset/hardhat.config.js @@ -10,7 +10,13 @@ if (!process.env.ALCHEMY_TOKEN){ module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, networks: { hardhat: { diff --git a/test/sources/projects/import-paths/hardhat.config.js b/test/sources/projects/import-paths/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/import-paths/hardhat.config.js +++ b/test/sources/projects/import-paths/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/libraries/hardhat.config.js b/test/sources/projects/libraries/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/libraries/hardhat.config.js +++ b/test/sources/projects/libraries/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/matrix/hardhat.config.js b/test/sources/projects/matrix/hardhat.config.js index 7c8bb98..983e864 100644 --- a/test/sources/projects/matrix/hardhat.config.js +++ b/test/sources/projects/matrix/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports={ solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/modifiers/contracts/ModifiersA.sol b/test/sources/projects/modifiers/contracts/ModifiersA.sol index 5e00fb9..9c2497e 100644 --- a/test/sources/projects/modifiers/contracts/ModifiersA.sol +++ b/test/sources/projects/modifiers/contracts/ModifiersA.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.6.0; +pragma solidity >=0.8.0 <0.9.0; import "./ModifiersB.sol"; diff --git a/test/sources/projects/modifiers/contracts/ModifiersB.sol b/test/sources/projects/modifiers/contracts/ModifiersB.sol index 8c60738..3d8b3d9 100644 --- a/test/sources/projects/modifiers/contracts/ModifiersB.sol +++ b/test/sources/projects/modifiers/contracts/ModifiersB.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.6.0; +pragma solidity >=0.8.0 <0.9.0; contract ModifiersB { diff --git a/test/sources/projects/modifiers/contracts/ModifiersC.sol b/test/sources/projects/modifiers/contracts/ModifiersC.sol index c5302b1..3d4d171 100644 --- a/test/sources/projects/modifiers/contracts/ModifiersC.sol +++ b/test/sources/projects/modifiers/contracts/ModifiersC.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.6.0; +pragma solidity >=0.8.0 <0.9.0; import "./ModifiersB.sol"; diff --git a/test/sources/projects/modifiers/hardhat.config.js b/test/sources/projects/modifiers/hardhat.config.js index 448b09d..cfc8f8e 100644 --- a/test/sources/projects/modifiers/hardhat.config.js +++ b/test/sources/projects/modifiers/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.6.7" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/multiple-suites/hardhat.config.js b/test/sources/projects/multiple-suites/hardhat.config.js index 9b8f17b..0a601f3 100644 --- a/test/sources/projects/multiple-suites/hardhat.config.js +++ b/test/sources/projects/multiple-suites/hardhat.config.js @@ -8,7 +8,13 @@ module.exports={ } }, solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/no-sources/hardhat.config.js b/test/sources/projects/no-sources/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/no-sources/hardhat.config.js +++ b/test/sources/projects/no-sources/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/overrides-viaIR/.solcover.js b/test/sources/projects/overrides-viaIR/.solcover.js new file mode 100644 index 0000000..71b990c --- /dev/null +++ b/test/sources/projects/overrides-viaIR/.solcover.js @@ -0,0 +1,4 @@ +module.exports = { + "silent": false, + "istanbulReporter": [ "json-summary", "text"] +} diff --git a/test/sources/projects/overrides-viaIR/contracts/ContractOverA2.sol b/test/sources/projects/overrides-viaIR/contracts/ContractOverA2.sol new file mode 100644 index 0000000..ad19d2c --- /dev/null +++ b/test/sources/projects/overrides-viaIR/contracts/ContractOverA2.sol @@ -0,0 +1,17 @@ +pragma solidity >=0.8.0 <0.9.0; + + +contract ContractA { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/sources/projects/overrides-viaIR/contracts/ContractOverB2.sol b/test/sources/projects/overrides-viaIR/contracts/ContractOverB2.sol new file mode 100644 index 0000000..6d5f53d --- /dev/null +++ b/test/sources/projects/overrides-viaIR/contracts/ContractOverB2.sol @@ -0,0 +1,17 @@ +pragma solidity >=0.8.0 <0.9.0; + + +contract ContractB { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/sources/projects/overrides-viaIR/contracts/ContractOverC2.sol b/test/sources/projects/overrides-viaIR/contracts/ContractOverC2.sol new file mode 100644 index 0000000..8c24195 --- /dev/null +++ b/test/sources/projects/overrides-viaIR/contracts/ContractOverC2.sol @@ -0,0 +1,17 @@ +pragma solidity >=0.8.0 <0.9.0; + + +contract ContractC { + uint x; + constructor() public { + } + + function sendFn() public { + x = 5; + } + + function callFn() public pure returns (uint){ + uint y = 5; + return y; + } +} diff --git a/test/sources/projects/overrides-viaIR/hardhat.config.js b/test/sources/projects/overrides-viaIR/hardhat.config.js new file mode 100644 index 0000000..b9c83a1 --- /dev/null +++ b/test/sources/projects/overrides-viaIR/hardhat.config.js @@ -0,0 +1,29 @@ +require("@nomiclabs/hardhat-truffle5"); +require(__dirname + "/../plugins/nomiclabs.plugin"); + +module.exports={ + solidity: { + compilers: [ + { + version: "0.8.17", + }, + { + version: "0.8.19" + }, + ], + overrides: { + "contracts/ContractA.sol": { + version: "0.8.24", + settings: { + optimizer: { + enabled: true, + runs: 200, + viaIR: process.env.VIA_IR === "true", + evmVersion: 'paris' + } + } + } + } + }, + logger: process.env.SILENT ? { log: () => {} } : console, +}; diff --git a/test/sources/projects/overrides-viaIR/test/contract_over_a2.js b/test/sources/projects/overrides-viaIR/test/contract_over_a2.js new file mode 100644 index 0000000..4182d2b --- /dev/null +++ b/test/sources/projects/overrides-viaIR/test/contract_over_a2.js @@ -0,0 +1,11 @@ +const ContractA = artifacts.require("ContractA"); + +contract("contracta", function(accounts) { + let instance; + + before(async () => instance = await ContractA.new()) + + it('sends', async function(){ + await instance.sendFn(); + }); +}); diff --git a/test/sources/projects/overrides-viaIR/test/contract_over_b2.js b/test/sources/projects/overrides-viaIR/test/contract_over_b2.js new file mode 100644 index 0000000..42d8cb8 --- /dev/null +++ b/test/sources/projects/overrides-viaIR/test/contract_over_b2.js @@ -0,0 +1,15 @@ +const ContractB = artifacts.require("ContractB"); + +contract("contractB", function(accounts) { + let instance; + + before(async () => instance = await ContractB.new()) + + it('sends', async function(){ + await instance.sendFn(); + }); + + it('calls', async function(){ + await instance.callFn(); + }) +}); diff --git a/test/sources/projects/overrides-viaIR/test/contract_over_c2.js b/test/sources/projects/overrides-viaIR/test/contract_over_c2.js new file mode 100644 index 0000000..9b3d950 --- /dev/null +++ b/test/sources/projects/overrides-viaIR/test/contract_over_c2.js @@ -0,0 +1,20 @@ +const ContractC = artifacts.require("ContractC"); + +contract("contractc", function(accounts) { + let instance; + + before(async () => instance = await ContractC.new()) + + it('sends', async function(){ + await instance.sendFn(); + }); + + it('calls', async function(){ + await instance.callFn(); + }) + + it('sends', async function(){ + await instance.sendFn(); + }); + +}); diff --git a/test/sources/projects/skipping/hardhat.config.js b/test/sources/projects/skipping/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/skipping/hardhat.config.js +++ b/test/sources/projects/skipping/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/solc-8/hardhat.config.js b/test/sources/projects/solc-8/hardhat.config.js index 049df45..fd24249 100644 --- a/test/sources/projects/solc-8/hardhat.config.js +++ b/test/sources/projects/solc-8/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.21" + version: "0.8.21", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/task-hooks/hardhat.config.js b/test/sources/projects/task-hooks/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/task-hooks/hardhat.config.js +++ b/test/sources/projects/task-hooks/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/ternary-and-logical-or/hardhat.config.js b/test/sources/projects/ternary-and-logical-or/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/ternary-and-logical-or/hardhat.config.js +++ b/test/sources/projects/ternary-and-logical-or/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/test-files/hardhat.config.js b/test/sources/projects/test-files/hardhat.config.js index c417cf8..5be7047 100644 --- a/test/sources/projects/test-files/hardhat.config.js +++ b/test/sources/projects/test-files/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.24", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/sources/projects/tests-folder/hardhat.config.js b/test/sources/projects/tests-folder/hardhat.config.js index c417cf8..cfc8f8e 100644 --- a/test/sources/projects/tests-folder/hardhat.config.js +++ b/test/sources/projects/tests-folder/hardhat.config.js @@ -3,7 +3,13 @@ require(__dirname + "/../plugins/nomiclabs.plugin"); module.exports = { solidity: { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } }, logger: process.env.SILENT ? { log: () => {} } : console, }; diff --git a/test/units/statements.js b/test/units/statements.js index ade1082..678b22d 100644 --- a/test/units/statements.js +++ b/test/units/statements.js @@ -51,8 +51,11 @@ describe('generic statements', () => { util.report(info.solcOutput.errors); }); - // FAILING WITH 0.8.x ... unskip when viaIR work is done - it.skip('should instrument without triggering stack-too-deep', () => { + it('should instrument without triggering stack-too-deep', () => { + // Only compiles if compiler.settings.viaIR = true + // Tests run with optimizer turned on/off to validate both instrumentation techniques + if (!process.env.VIA_IR) return; + const info = util.instrumentAndCompile('statements/stack-too-deep'); util.report(info.solcOutput.errors); }); diff --git a/test/util/integration.js b/test/util/integration.js index be672b7..027802f 100644 --- a/test/util/integration.js +++ b/test/util/integration.js @@ -114,7 +114,13 @@ function getDefaultHardhatConfig() { const config = getDefaultNomicLabsConfig() config.defaultNetwork = HARDHAT_NETWORK_NAME; config.solidity = { - version: "0.8.17" + version: "0.8.17", + settings: { + optimizer: { + enabled: true + }, + viaIR: process.env.VIA_IR === "true" + } } return config; } diff --git a/test/util/util.js b/test/util/util.js index 5bb5c2d..05f44e1 100644 --- a/test/util/util.js +++ b/test/util/util.js @@ -61,7 +61,8 @@ function codeToCompilerInput(code) { sources: { 'test.sol': { content: code } }, settings: { outputSelection: {'*': { '*': [ '*' ] }}, - evmVersion: "paris" + evmVersion: "paris", + viaIR: process.env.VIA_IR === "true" } }); } @@ -89,7 +90,8 @@ function getDiffABIs(sourceName, testFile="test.sol", original="Old", current="N // ============================ // Instrumentation Correctness // ============================ -function instrumentAndCompile(sourceName, api={}) { +function instrumentAndCompile(sourceName, api={ config: {} }) { + api.config.viaIR = process.env.VIA_IR === "true"; const contract = getCode(`${sourceName}.sol`) const instrumenter = new Instrumenter(api.config); const instrumented = instrumenter.instrument(contract, filePath);