Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Remove ganache-cli related code from API & tests
  • Loading branch information
cgewecke committed Feb 4, 2024
commit 73ea1afa27ff56835a87a0c4483a7d1b7fe943a3
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ npx hardhat coverage [command-options]
| testfiles | `--testfiles "test/registry/*.ts"` | Test file(s) to run. (Globs must be enclosed by quotes and use [globby matching patterns][38])|
| sources | `--sources myFolder` or `--sources myFile.sol` | Path to *single* folder or file to target for coverage. Path is relative to Hardhat's `paths.sources` (usually `contracts/`) |
| solcoverjs | `--solcoverjs ./../.solcover.js` | Relative path from working directory to config. Useful for monorepo packages that share settings. (Path must be "./" prefixed) |
| network | `--network development` | Use network settings defined in the Hardhat config |
| temp[<sup>*</sup>][14] | `--temp build` | :warning: **Caution** :warning: Path to a *disposable* folder to store compilation artifacts in. Useful when your test setup scripts include hard-coded paths to a build directory. [More...][14] |
| matrix | `--matrix` | Generate a JSON object that maps which mocha tests hit which lines of code. (Useful as an input for some fuzzing, mutation testing and fault-localization algorithms.) [More...][39]|

Expand Down Expand Up @@ -86,8 +85,6 @@ module.exports = {
| onIstanbulComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* the Istanbul reports are generated, *before* the ganache server is shut down. Useful if you need to clean resources up. [More...][23]|
| configureYulOptimizer | *Boolean* | false | (Experimental) Setting to `true` should resolve "stack too deep" compiler errors in large projects using ABIEncoderV2 |
| solcOptimizerDetails | *Object* | `undefined` |(Experimental) Must be used in combination with `configureYulOptimizer`. Allows you configure solc's [optimizer details][1001]. Useful if the default remedy for stack-too-deep errors doesn't work in your case (See FAQ below). |
| client | *Object* | `require("ganache-core")` | Ganache only: useful if you need a specific ganache version |
| providerOptions | *Object* | `{ }` | Ganache only: [ganache-core options][1] |


[<sup>*</sup> Advanced use][14]
Expand Down
109 changes: 2 additions & 107 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const fs = require('fs');
const path = require('path');
const istanbul = require('sc-istanbul');
const assert = require('assert');
const detect = require('detect-port');
const _ = require('lodash/lang');

const ConfigValidator = require('./validator');
Expand Down Expand Up @@ -45,20 +44,10 @@ class API {
this.onIstanbulComplete = config.onIstanbulComplete || this.defaultHook;
this.onPreCompile = config.onPreCompile || this.defaultHook;

this.server = null;
this.defaultPort = 8555;
this.client = config.client;
this.defaultNetworkName = 'soliditycoverage';
this.port = config.port || this.defaultPort;
this.host = config.host || "127.0.0.1";
this.providerOptions = config.providerOptions || {};
this.autoLaunchServer = config.autoLaunchServer === false ? false : true;

this.skipFiles = config.skipFiles || [];

this.log = config.log || console.log;
this.gasLimit = 0xffffffffff // default "gas sent" with transactions
this.gasLimitString = "0x1fffffffffffff"; // block gas limit for ganache (higher than "gas sent")
this.gasLimitNumber = 0x1fffffffffffff; // block gas limit for Hardhat
this.gasPrice = 0x01;

Expand Down Expand Up @@ -138,56 +127,6 @@ class API {
this.instrumenter.instrumentationData = _.cloneDeep(data);
}

/**
* Enables coverage collection on in-process ethereum client server, hooking the DataCollector
* to its VM. By default, method will return a url after server has begun listening on the port
* specified in the config. When `autoLaunchServer` is false, method returns`ganache.server` so
* the consumer can control the 'server.listen' invocation themselves.
* @param {Object} client ganache client
* @param {Boolean} autoLaunchServer boolean
* @return {<Promise> (String | Server) } address of server to connect to, or initialized, unlaunched server.
*/
async ganache(client, autoLaunchServer){
// Check for port-in-use
if (await detect(this.port) !== this.port){
throw new Error(this.ui.generate('server-fail', [this.port]))
}

this.collector = new DataCollector(this.instrumenter.instrumentationData);

this.providerOptions.gasLimit =
'gasLimit' in this.providerOptions
? this.providerOptions.gasLimit
: this.gasLimitString;

this.providerOptions.allowUnlimitedContractSize =
'allowUnlimitedContractSize' in this.providerOptions
? this.providerOptions.allowUnlimitedContractSize
: true;

// Attach to vm step of supplied client
try {
if (this.config.forceBackupServer) throw new Error()
await this.attachToGanacheVM(client)
}

// Fallback to ganache-cli)
catch(err) {
const _ganache = require('ganache-cli');
this.ui.report('vm-fail', [_ganache.version]);
await this.attachToGanacheVM(_ganache);
}

if (autoLaunchServer === false || this.autoLaunchServer === false){
return this.server;
}

await pify(this.server.listen)(this.port);
const address = `http://${this.host}:${this.port}`;
this.ui.report('server', [address]);
return address;
}

/**
* Generate coverage / write coverage report / run istanbul
*/
Expand Down Expand Up @@ -223,60 +162,16 @@ class API {
})
}


/**
* Removes coverage build artifacts, kills testrpc.
*/
async finish() {
if (this.server && this.server.close){
this.ui.report('finish');
await pify(this.server.close)();
}
}
async finish() { /* Just a stub now - used to shutdown ganache */}

// ------------------------------------------ Utils ----------------------------------------------

// ========
// Provider
// ========
async attachToGanacheVM(client){
const self = this;

// Fallback to client from options
if(!client) client = this.client;
this.server = client.server(this.providerOptions);

this.assertHasBlockchain(this.server.provider);
await this.vmIsResolved(this.server.provider);

const blockchain = this.server.provider.engine.manager.state.blockchain;
const createVM = blockchain.createVMFromStateTrie;

// Attach to VM which ganache has already created for transactions
blockchain.vm.on('step', self.collector.step.bind(self.collector));

// Hijack createVM method which ganache runs for each `eth_call`
blockchain.createVMFromStateTrie = function(state, activatePrecompiles) {
const vm = createVM.apply(blockchain, arguments);
vm.on('step', self.collector.step.bind(self.collector));
return vm;
}
}

assertHasBlockchain(provider){
assert(provider.engine.manager.state.blockchain !== undefined);
assert(provider.engine.manager.state.blockchain.createVMFromStateTrie !== undefined);
}

async vmIsResolved(provider){
return new Promise(resolve => {
const interval = setInterval(() => {
if (provider.engine.manager.state.blockchain.vm !== undefined){
clearInterval(interval);
resolve();
}
});
})
}

// Hardhat
async attachToHardhatVM(provider){
Expand Down
12 changes: 0 additions & 12 deletions lib/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ class AppUI extends UI {
const w = ":warning:";

const kinds = {
'vm-fail': `${w} ${c.red('There was a problem attaching to the ganache VM.')}\n` +
`${w} ${c.red('For help, see the "client" & "providerOptions" syntax in solidity-coverage docs.')}\n`+
`${w} ${c.red(`Using ganache-cli (v${args[0]}) instead.`)}\n`,


'instr-start': `\n${c.bold('Instrumenting for coverage...')}` +
`\n${c.bold('=============================')}\n`,
Expand All @@ -69,10 +65,6 @@ class AppUI extends UI {
'istanbul': `${ct} ${c.grey('Istanbul reports written to')} ./coverage/ ` +
`${c.grey('and')} ./coverage.json`,

'finish': `${ct} ${c.grey('solidity-coverage cleaning up, shutting down ganache server')}`,

'server': `${ct} ${c.bold('server: ')} ${c.grey(args[0])}`,

'command': `\n${w} ${c.red.bold('solidity-coverage >= 0.7.0 is no longer a shell command.')} ${w}\n` +
`${c.bold('=============================================================')}\n\n` +
`Instead, you should use the plugin produced for your development stack\n` +
Expand Down Expand Up @@ -103,10 +95,6 @@ class AppUI extends UI {
'istanbul-fail': `${c.red('Istanbul coverage reports could not be generated. ')}`,

'sources-fail': `${c.red('Cannot locate expected contract sources folder: ')} ${args[0]}`,

'server-fail': `${c.red('Port')} ${args[0]} ${c.red('is already in use.\n')}` +
`${c.red('\tRun: "lsof -i" to find the pid of the process using it.\n')}` +
`${c.red('\tRun: "kill -9 <pid>" to kill it.\n')}`
}

return this._format(kinds[kind])
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
"decache": "^4.5.1",
"ethereum-waffle": "^3.4.0",
"ethers": "^5.5.3",
"ganache-cli": "6.12.2",
"hardhat": "^2.19.5",
"hardhat-gas-reporter": "^1.0.1",
"nyc": "^14.1.1",
Expand Down
46 changes: 15 additions & 31 deletions plugins/hardhat.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ task("coverage", "Generates a code coverage report for tests")
let ui;
let api;
let config;
let client;
let address;
let failedTests = 0;

Expand Down Expand Up @@ -201,36 +200,21 @@ task("coverage", "Generates a code coverage report for tests")
// ==============
let network = await nomiclabsUtils.setupHardhatNetwork(env, api, ui);

if (network.isHardhatEVM){
accounts = await utils.getAccountsHardhat(network.provider);
nodeInfo = await utils.getNodeInfoHardhat(network.provider);

// Note: this only works if the reset block number is before any transactions have fired on the fork.
// e.g you cannot fork at block 1, send some txs (blocks 2,3,4) and reset to block 2
env.network.provider.on(HARDHAT_NETWORK_RESET_EVENT, async () => {
await api.attachToHardhatVM(env.network.provider);
});

await api.attachToHardhatVM(network.provider);

ui.report('hardhat-network', [
nodeInfo.split('/')[1],
env.network.name,
]);
} else {
client = api.client || require('ganache-cli');
address = await api.ganache(client);
const accountsRequest = await utils.getAccountsGanache(api.server.provider);
const nodeInfoRequest = await utils.getNodeInfoGanache(api.server.provider);

ui.report('ganache-network', [
nodeInfoRequest.result.split('/')[1],
env.network.name,
api.port
]);

accounts = accountsRequest.result;
}
accounts = await utils.getAccountsHardhat(network.provider);
nodeInfo = await utils.getNodeInfoHardhat(network.provider);

// Note: this only works if the reset block number is before any transactions have fired on the fork.
// e.g you cannot fork at block 1, send some txs (blocks 2,3,4) and reset to block 2
env.network.provider.on(HARDHAT_NETWORK_RESET_EVENT, async () => {
await api.attachToHardhatVM(env.network.provider);
});

await api.attachToHardhatVM(network.provider);

ui.report('hardhat-network', [
nodeInfo.split('/')[1],
env.network.name,
]);

// Set default account (if not already configured)
nomiclabsUtils.setNetworkFrom(network.config, accounts);
Expand Down
14 changes: 0 additions & 14 deletions plugins/resources/nomiclabs.ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ class PluginUI extends UI {

'instr-skipped': `${ds} ${c.grey(args[0])}`,

'versions': `${ct} ${c.bold('ganache-core')}: ${args[0]}\n` +
`${ct} ${c.bold('solidity-coverage')}: v${args[1]}`,

'hardhat-versions': `\n${c.bold('Version')}` +
`\n${c.bold('=======')}\n` +
`${ct} ${c.bold('solidity-coverage')}: v${args[0]}`,
Expand All @@ -57,17 +54,6 @@ class PluginUI extends UI {
`${ct} ${c.bold('HardhatEVM')}: v${args[0]}\n` +
`${ct} ${c.bold('network')}: ${args[1]}\n`,

'ganache-network': `\n${c.bold('Network Info')}` +
`\n${c.bold('============')}\n` +
`${ct} ${c.bold('port')}: ${args[1]}\n` +
`${ct} ${c.bold('network')}: ${args[0]}\n`,

'port-clash': `${w} ${c.red("The 'port' values in your config's network url ")}` +
`${c.red("and .solcover.js are different. Using network's: ")} ${c.bold(args[0])}.\n`,

'port-clash-hardhat': `${w} ${c.red("The 'port' values in your Hardhat network's url ")}` +
`${c.red("and .solcover.js are different. Using Hardhat's: ")} ${c.bold(args[0])}.\n`,

}

this._write(kinds[kind]);
Expand Down
31 changes: 0 additions & 31 deletions plugins/resources/plugin.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,35 +262,6 @@ async function getNodeInfoHardhat(provider){
return provider.send("web3_clientVersion", [])
}

async function getAccountsGanache(provider){
const payload = {
jsonrpc: "2.0",
method: "eth_accounts",
params: [],
id: 1
};
return ganacheRequest(provider, payload)
}

async function getNodeInfoGanache(provider){
const payload = {
jsonrpc: "2.0",
method: "web3_clientVersion",
params: [],
id: 1
};
return ganacheRequest(provider, payload)
}

async function ganacheRequest(provider, payload){
return new Promise((resolve, reject) => {
provider.sendAsync(payload, function(err, res){
if (err) return reject(err)
resolve(res);
})
});
}

// ==========================
// Finishing / Cleanup
// ==========================
Expand Down Expand Up @@ -330,6 +301,4 @@ module.exports = {
setupTempFolders,
getAccountsHardhat,
getNodeInfoHardhat,
getAccountsGanache,
getNodeInfoGanache
}
27 changes: 0 additions & 27 deletions test/integration/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const fs = require('fs');
const path = require('path')
const pify = require('pify')
const shell = require('shelljs');
const ganache = require('ganache-cli')

const verify = require('./../util/verifiers')
const mock = require('./../util/integration');
Expand Down Expand Up @@ -64,32 +63,6 @@ describe('Hardhat Plugin: error cases', function() {
}
});

it('tries to launch with a port already in use', async function(){
const taskArgs = {
network: "development"
}

const server = ganache.server();

mock.install('Simple', 'simple.js', solcoverConfig);
mock.hardhatSetupEnv(this);

await pify(server.listen)(8545);

try {
await this.env.run("coverage", taskArgs);
assert.fail();
} catch(err){
assert(
err.message.includes('already in use') &&
err.message.includes('lsof'),
`Should error on port-in-use with advice: ${err.message}`
)
}

await pify(server.close)();
});

it('tries to launch with a non-existent network', async function(){
const taskArgs = {
network: "does-not-exist"
Expand Down
Loading