|
|
|
@ -3,6 +3,7 @@ const fs = require('fs'); |
|
|
|
|
const path = require('path'); |
|
|
|
|
const istanbul = require('istanbul'); |
|
|
|
|
const util = require('util'); |
|
|
|
|
const assert = require('assert'); |
|
|
|
|
|
|
|
|
|
const Instrumenter = require('./instrumenter'); |
|
|
|
|
const Coverage = require('./coverage'); |
|
|
|
@ -113,15 +114,31 @@ class App { |
|
|
|
|
* |
|
|
|
|
* TODO: generalize provider options setting for non-ganache clients.. |
|
|
|
|
*/ |
|
|
|
|
provider(client){ |
|
|
|
|
if(!this.client) this.client = client; |
|
|
|
|
async provider(client){ |
|
|
|
|
let retry = false; |
|
|
|
|
|
|
|
|
|
if(!this.client) this.client = client; // Prefer client from options
|
|
|
|
|
|
|
|
|
|
this.collector = new DataCollector(this.instrumenter.instrumentationData); |
|
|
|
|
|
|
|
|
|
this.providerOptions.gasLimit = this.gasLimitString; |
|
|
|
|
this.providerOptions.allowUnlimitedContractSize = true; |
|
|
|
|
this.providerOptions.logger = { log: this.collector.step.bind(this.collector) }; |
|
|
|
|
|
|
|
|
|
// Try to launch provider and attach to vm step of
|
|
|
|
|
// either plugin's ganache or a provider passed via options
|
|
|
|
|
try { |
|
|
|
|
this.provider = await this.attachToVM(); |
|
|
|
|
} catch(err){ |
|
|
|
|
retry = true; |
|
|
|
|
this.ui.report('vm-fail', []) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fallback to ganache-core-sc (eq: ganache-core 2.7.0)
|
|
|
|
|
if (retry){ |
|
|
|
|
this.providerOptions.logger = { log: this.collector.step.bind(this.collector) }; |
|
|
|
|
this.client = require('ganache-core-sc'); |
|
|
|
|
this.provider = this.client.provider(this.providerOptions); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return this.provider; |
|
|
|
|
} |
|
|
|
@ -176,6 +193,50 @@ class App { |
|
|
|
|
} |
|
|
|
|
// ------------------------------------------ Utils ----------------------------------------------
|
|
|
|
|
|
|
|
|
|
// ========
|
|
|
|
|
// Provider
|
|
|
|
|
// ========
|
|
|
|
|
async attachToVM(){ |
|
|
|
|
const self = this; |
|
|
|
|
const provider = this.client.provider(this.providerOptions); |
|
|
|
|
|
|
|
|
|
this.assertHasBlockchain(provider); |
|
|
|
|
|
|
|
|
|
await this.vmIsResolved(provider); |
|
|
|
|
|
|
|
|
|
const blockchain = provider.engine.manager.state.blockchain; |
|
|
|
|
const createVM = blockchain.createVMFromStateTrie; |
|
|
|
|
|
|
|
|
|
// Attach to VM which ganache has already instantiated
|
|
|
|
|
// and which it uses to execute eth_send
|
|
|
|
|
blockchain.vm.on('step', self.collector.step.bind(self.collector)); |
|
|
|
|
|
|
|
|
|
// Attach/hijack createVM method which ganache uses to run eth_calls
|
|
|
|
|
blockchain.createVMFromStateTrie = function(state, activatePrecompiles) { |
|
|
|
|
const vm = createVM.apply(blockchain, arguments); |
|
|
|
|
vm.on('step', self.collector.step.bind(self.collector)); |
|
|
|
|
return vm; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return provider; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ========
|
|
|
|
|
// File I/O
|
|
|
|
|
// ========
|
|
|
|
|