Skip to content

Commit c6eea4b

Browse files
authored
Remove ganache-cli related code from API & tests (#849)
1 parent 6739db6 commit c6eea4b

26 files changed

+80
-750
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ npx hardhat coverage [command-options]
4646
| testfiles | `--testfiles "test/registry/*.ts"` | Test file(s) to run. (Globs must be enclosed by quotes and use [globby matching patterns][38])|
4747
| 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/`) |
4848
| solcoverjs | `--solcoverjs ./../.solcover.js` | Relative path from working directory to config. Useful for monorepo packages that share settings. (Path must be "./" prefixed) |
49-
| network | `--network development` | Use network settings defined in the Hardhat config |
5049
| 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] |
5150
| 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]|
5251

@@ -83,11 +82,9 @@ module.exports = {
8382
| onPreCompile[<sup>*</sup>][14] | *Function* | | Hook run *after* filesystem and compiler configuration is applied, *before* the compiler is run. Can be used with the other hooks to be able to generate coverage reports on non-standard / customized directory structures, as well as contracts with absolute import paths. [More...][23] |
8483
| onCompileComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* compilation completes, *before* tests are run. Useful if you have secondary compilation steps or need to modify built artifacts. [More...][23]|
8584
| onTestsComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* the tests complete, *before* Istanbul reports are generated. [More...][23]|
86-
| 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]|
85+
| onIstanbulComplete[<sup>*</sup>][14] | *Function* | | Hook run *after* the Istanbul reports are generated, *before* the coverage task completes. Useful if you need to clean resources up. [More...][23]|
8786
| configureYulOptimizer | *Boolean* | false | (Experimental) Setting to `true` should resolve "stack too deep" compiler errors in large projects using ABIEncoderV2 |
8887
| 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). |
89-
| client | *Object* | `require("ganache-core")` | Ganache only: useful if you need a specific ganache version |
90-
| providerOptions | *Object* | `{ }` | Ganache only: [ganache-core options][1] |
9188

9289

9390
[<sup>*</sup> Advanced use][14]
@@ -143,7 +140,6 @@ $ git clone https://github.com/sc-forks/solidity-coverage.git
143140
$ yarn
144141
```
145142

146-
[1]: https://github.com/trufflesuite/ganache-core#options
147143
[2]: https://istanbul.js.org/docs/advanced/alternative-reporters/
148144
[3]: https://mochajs.org/api/mocha
149145
[4]: https://github.com/sc-forks/solidity-coverage/blob/master/docs/faq.md#running-out-of-gas

docs/advanced.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module.exports = {
2727

2828
The plugin exposes a set of workflow hooks that let you run arbitrary async logic between the main
2929
stages of the coverage generation process. These are useful for tasks like launching secondary
30-
services which need to connect to a running ganache instance (ex: the Oraclize/Provable bridge),
30+
services which need to connect to a running ethereum client instance (ex: the Oraclize/Provable bridge),
3131
or reading data from the compilation artifacts to run special preparatory steps for your tests.
3232

3333
The stages/hooks are (in order of execution):

docs/api.md

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ table below shows how its core methods relate to the stages of a test run:
88
| Test Stage <img width=200/> | API Method <img width=200/> | Description <img width=800/> |
99
|---------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
1010
| compilation | `instrument` | A **pre-compilation** step: Rewrites contracts and generates an instrumentation data map. |
11-
| client launch | `ganache` | A **substitute** step: Launches a ganache client with coverage collection enabled in its VM. As the client runs it will mark line/branch hits on the instrumentation data map. |
11+
| client launch | `attachToHardhatVM` | A **pre-test** step: Enables coverage collection enabled in a HardhatEVM client. As the client runs it will mark line/branch hits on the instrumentation data map. |
1212
| test | `report` | A **post-test** step: Generates a coverage report from the data collected by the VM after tests complete. |
13-
| exit | `finish` | A **substitute** step: Shuts client down |
13+
1414

1515
[3]: https://github.com/gotwarlost/istanbul
1616

@@ -20,8 +20,8 @@ table below shows how its core methods relate to the stages of a test run:
2020
disposable set of contracts/artifacts which coverage must use in lieu of the 'real' (uninstrumented)
2121
contracts.
2222

23-
+ there are two complete [coverage tool/plugin implementations][5] (for Hardhat and Truffle)
24-
which can be used as sources if you're building something similar.
23+
+ there is a complete [coverage tool/plugin implementation][5] for Hardhat
24+
which can be used as a source if you're building something similar.
2525

2626
[5]: https://github.com/sc-forks/solidity-coverage/tree/master/plugins
2727

@@ -31,9 +31,8 @@ which can be used as sources if you're building something similar.
3131
- [API Methods](#api)
3232
* [constructor](#constructor)
3333
* [instrument](#instrument)
34-
* [ganache](#ganache)
34+
* [attachToHardhatVM](#attachToHardhatVM)
3535
* [report](#report)
36-
* [finish](#finish)
3736
* [getInstrumentationData](#getinstrumentationdata)
3837
* [setInstrumentationData](#setinstrumentationdata)
3938
- [Utils Methods](#utils)
@@ -64,13 +63,10 @@ Creates a coverage API instance. Configurable.
6463
| ------ | ---- | ------- | ----------- |
6564
| port | *Number* | 8555 | Port to launch client on |
6665
| silent | *Boolean* | false | Suppress logging output |
67-
| client | *Object* | `require("ganache-core")` | JS Ethereum client |
68-
| providerOptions | *Object* | `{ }` | [ganache-core options][1] |
6966
| skipFiles | *Array* | `[]` | Array of contracts or folders (with paths expressed relative to the `contracts` directory) that should be skipped when doing instrumentation. |
7067
| istanbulFolder | *String* | `./coverage` | Folder location for Istanbul coverage reports. |
7168
| istanbulReporter | *Array* | `['html', 'lcov', 'text', 'json']` | [Istanbul coverage reporters][2] |
7269

73-
[1]: https://github.com/trufflesuite/ganache-core#options
7470
[2]: https://istanbul.js.org/docs/advanced/alternative-reporters/
7571

7672
--------------
@@ -100,33 +96,37 @@ const instrumented = api.instrument(contracts)
10096

10197
--------------
10298

103-
## ganache
99+
## attachToHardhatVM
104100

105-
Enables coverage data collection on an in-process ganache server. By default, this method launches
106-
the server, begins listening on the port specified in the [config](#constructor) (or 8555 if unspecified), and
107-
returns a url string. When `autoLaunchServer` is false, method returns `ganache.server` so you can control
108-
the `server.listen` invocation yourself.
101+
Enables coverage data collection on a HardhatEVM provider. (You will need to create a hardhat provider with the correct VM settings as shown below before invoking this method.)
109102

110103
**Parameters**
111104

112-
- `client` **Object**: (*Optional*) ganache module
113-
- `autoLaunchServer` **Boolean**: (*Optional*)
105+
- `provider` **Object**: Hardhat provider
114106

115-
Returns **Promise** Address of server to connect to, or initialized, unlaunched server
107+
Returns **Promise**
116108

117109
**Example**
118110
```javascript
119-
const client = require('ganache-cli');
111+
const { createProvider } = require("hardhat/internal/core/providers/construction");
112+
const { resolveConfig } = require("hardhat/internal/core/config/config-resolution");
113+
const { HARDHAT_NETWORK_NAME } = require("hardhat/plugins")
120114

121-
const api = new CoverageAPI( { client: client } );
122-
const address = await api.ganache();
115+
const api = new CoverageAPI( { ... } );
116+
const config = resolveConfig("./", {});
123117

124-
> http://127.0.0.1:8555
118+
config.networks[HARDHAT_NETWORK_NAME].allowUnlimitedContractSize = true;
119+
config.networks[HARDHAT_NETWORK_NAME].blockGasLimit = api.gasLimitNumber;
120+
config.networks[HARDHAT_NETWORK_NAME].gas = api.gasLimit;
121+
config.networks[HARDHAT_NETWORK_NAME].gasPrice = api.gasPrice;
122+
config.networks[HARDHAT_NETWORK_NAME].initialBaseFeePerGas = 0;
125123

126-
// Alternatively...
124+
const provider = await createProvider(
125+
config,
126+
HARDHAT_NETWORK_NAME
127+
)
127128

128-
const server = await api.ganache(client, false);
129-
await pify(server.listen)(8545));
129+
await api.attachToHardhatVM(provider);
130130
```
131131

132132
--------------
@@ -148,22 +148,6 @@ await api.report('./coverage_4A3cd2b'); // Default folder name is 'coverage'
148148

149149
-------------
150150

151-
## finish
152-
153-
Shuts down coverage-enabled ganache server instance
154-
155-
Returns **Promise**
156-
157-
**Example**
158-
```javascript
159-
const client = require('ganache-cli');
160-
161-
await api.ganache(client); // Server listening...
162-
await api.finish(); // Server shut down.
163-
```
164-
165-
-------------
166-
167151
## getInstrumentationData
168152

169153
Returns a copy of the hit map created during instrumentation. Useful if you'd like to delegate
@@ -193,7 +177,7 @@ const data = load(data); // Pseudo-code
193177
api.setIntrumentationData(data);
194178

195179
// Client will collect data for the loaded map
196-
const address = await api.ganache(client);
180+
await api.attachToHardhatVM(provider);
197181

198182
// Or to `report` instrumentation data which was collected in a different process.
199183
const data = load(data); // Pseudo-code
@@ -348,8 +332,7 @@ utils.save(instrumented, config.contractsDir, tempContractsDir);
348332

349333
## finish
350334

351-
Deletes temporary folders and shuts the ganache server down. Is tolerant - if folders or ganache
352-
server don't exist it will return silently.
335+
Deletes temporary folders. Is tolerant - if folders don't exist it will return silently.
353336

354337
**Parameters**
355338

lib/api.js

Lines changed: 2 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const fs = require('fs');
44
const path = require('path');
55
const istanbul = require('sc-istanbul');
66
const assert = require('assert');
7-
const detect = require('detect-port');
87
const _ = require('lodash/lang');
98

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

48-
this.server = null;
49-
this.defaultPort = 8555;
50-
this.client = config.client;
51-
this.defaultNetworkName = 'soliditycoverage';
52-
this.port = config.port || this.defaultPort;
53-
this.host = config.host || "127.0.0.1";
54-
this.providerOptions = config.providerOptions || {};
55-
this.autoLaunchServer = config.autoLaunchServer === false ? false : true;
56-
5747
this.skipFiles = config.skipFiles || [];
5848

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

@@ -138,56 +127,6 @@ class API {
138127
this.instrumenter.instrumentationData = _.cloneDeep(data);
139128
}
140129

141-
/**
142-
* Enables coverage collection on in-process ethereum client server, hooking the DataCollector
143-
* to its VM. By default, method will return a url after server has begun listening on the port
144-
* specified in the config. When `autoLaunchServer` is false, method returns`ganache.server` so
145-
* the consumer can control the 'server.listen' invocation themselves.
146-
* @param {Object} client ganache client
147-
* @param {Boolean} autoLaunchServer boolean
148-
* @return {<Promise> (String | Server) } address of server to connect to, or initialized, unlaunched server.
149-
*/
150-
async ganache(client, autoLaunchServer){
151-
// Check for port-in-use
152-
if (await detect(this.port) !== this.port){
153-
throw new Error(this.ui.generate('server-fail', [this.port]))
154-
}
155-
156-
this.collector = new DataCollector(this.instrumenter.instrumentationData);
157-
158-
this.providerOptions.gasLimit =
159-
'gasLimit' in this.providerOptions
160-
? this.providerOptions.gasLimit
161-
: this.gasLimitString;
162-
163-
this.providerOptions.allowUnlimitedContractSize =
164-
'allowUnlimitedContractSize' in this.providerOptions
165-
? this.providerOptions.allowUnlimitedContractSize
166-
: true;
167-
168-
// Attach to vm step of supplied client
169-
try {
170-
if (this.config.forceBackupServer) throw new Error()
171-
await this.attachToGanacheVM(client)
172-
}
173-
174-
// Fallback to ganache-cli)
175-
catch(err) {
176-
const _ganache = require('ganache-cli');
177-
this.ui.report('vm-fail', [_ganache.version]);
178-
await this.attachToGanacheVM(_ganache);
179-
}
180-
181-
if (autoLaunchServer === false || this.autoLaunchServer === false){
182-
return this.server;
183-
}
184-
185-
await pify(this.server.listen)(this.port);
186-
const address = `http://${this.host}:${this.port}`;
187-
this.ui.report('server', [address]);
188-
return address;
189-
}
190-
191130
/**
192131
* Generate coverage / write coverage report / run istanbul
193132
*/
@@ -223,60 +162,16 @@ class API {
223162
})
224163
}
225164

226-
227165
/**
228166
* Removes coverage build artifacts, kills testrpc.
229167
*/
230-
async finish() {
231-
if (this.server && this.server.close){
232-
this.ui.report('finish');
233-
await pify(this.server.close)();
234-
}
235-
}
168+
async finish() { /* Just a stub now - used to shutdown ganache */}
169+
236170
// ------------------------------------------ Utils ----------------------------------------------
237171

238172
// ========
239173
// Provider
240174
// ========
241-
async attachToGanacheVM(client){
242-
const self = this;
243-
244-
// Fallback to client from options
245-
if(!client) client = this.client;
246-
this.server = client.server(this.providerOptions);
247-
248-
this.assertHasBlockchain(this.server.provider);
249-
await this.vmIsResolved(this.server.provider);
250-
251-
const blockchain = this.server.provider.engine.manager.state.blockchain;
252-
const createVM = blockchain.createVMFromStateTrie;
253-
254-
// Attach to VM which ganache has already created for transactions
255-
blockchain.vm.on('step', self.collector.step.bind(self.collector));
256-
257-
// Hijack createVM method which ganache runs for each `eth_call`
258-
blockchain.createVMFromStateTrie = function(state, activatePrecompiles) {
259-
const vm = createVM.apply(blockchain, arguments);
260-
vm.on('step', self.collector.step.bind(self.collector));
261-
return vm;
262-
}
263-
}
264-
265-
assertHasBlockchain(provider){
266-
assert(provider.engine.manager.state.blockchain !== undefined);
267-
assert(provider.engine.manager.state.blockchain.createVMFromStateTrie !== undefined);
268-
}
269-
270-
async vmIsResolved(provider){
271-
return new Promise(resolve => {
272-
const interval = setInterval(() => {
273-
if (provider.engine.manager.state.blockchain.vm !== undefined){
274-
clearInterval(interval);
275-
resolve();
276-
}
277-
});
278-
})
279-
}
280175

281176
// Hardhat
282177
async attachToHardhatVM(provider){

lib/ui.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ class AppUI extends UI {
5656
const w = ":warning:";
5757

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

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

72-
'finish': `${ct} ${c.grey('solidity-coverage cleaning up, shutting down ganache server')}`,
73-
74-
'server': `${ct} ${c.bold('server: ')} ${c.grey(args[0])}`,
75-
7668
'command': `\n${w} ${c.red.bold('solidity-coverage >= 0.7.0 is no longer a shell command.')} ${w}\n` +
7769
`${c.bold('=============================================================')}\n\n` +
7870
`Instead, you should use the plugin produced for your development stack\n` +
@@ -103,10 +95,6 @@ class AppUI extends UI {
10395
'istanbul-fail': `${c.red('Istanbul coverage reports could not be generated. ')}`,
10496

10597
'sources-fail': `${c.red('Cannot locate expected contract sources folder: ')} ${args[0]}`,
106-
107-
'server-fail': `${c.red('Port')} ${args[0]} ${c.red('is already in use.\n')}` +
108-
`${c.red('\tRun: "lsof -i" to find the pid of the process using it.\n')}` +
109-
`${c.red('\tRun: "kill -9 <pid>" to kill it.\n')}`
11098
}
11199

112100
return this._format(kinds[kind])

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
"@solidity-parser/parser": "^0.18.0",
2727
"chalk": "^2.4.2",
2828
"death": "^1.1.0",
29-
"detect-port": "^1.3.0",
3029
"difflib": "^0.2.4",
3130
"fs-extra": "^8.1.0",
3231
"ghost-testrpc": "^0.0.2",
@@ -52,7 +51,6 @@
5251
"decache": "^4.5.1",
5352
"ethereum-waffle": "^3.4.0",
5453
"ethers": "^5.5.3",
55-
"ganache-cli": "6.12.2",
5654
"hardhat": "^2.19.5",
5755
"hardhat-gas-reporter": "^1.0.1",
5856
"nyc": "^14.1.1",

0 commit comments

Comments
 (0)