From 974575b695108dd70f4b165f6789f71c3647c2b1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 14 May 2018 20:01:18 +0200 Subject: Make sol-cov work with truffle and other artifact adapters --- packages/sol-cov/src/coverage_subprovider.ts | 38 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index 08efeaa24..f421a17fd 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -1,10 +1,13 @@ import { Callback, ErrorCallback, NextCallback, Subprovider } from '@0xproject/subproviders'; import { BlockParam, CallData, JSONRPCRequestPayload, TransactionTrace, TxData } from '@0xproject/types'; +import * as fs from 'fs'; import * as _ from 'lodash'; import { Lock } from 'semaphore-async-await'; +import { AbstractArtifactAdapter } from './artifact_adapters/abstract'; import { constants } from './constants'; import { CoverageManager } from './coverage_manager'; +import { getTracesByContractAddress } from './trace'; import { TraceInfoExistingContract, TraceInfoNewContract } from './types'; interface MaybeFakeTxData extends TxData { @@ -26,15 +29,15 @@ export class CoverageSubprovider extends Subprovider { private _defaultFromAddress: string; /** * Instantiates a CoverageSubprovider instance - * @param artifactsPath Path to the smart contract artifacts - * @param sourcesPath Path to the smart contract source files + * @param artifactAdapter Adapter for used artifacts format (0x, truffle, giveth, etc.) * @param defaultFromAddress default from address to use when sending transactions + * @param verbose If true, we will log any unknown transactions. Otherwise we will ignore them */ - constructor(artifactsPath: string, sourcesPath: string, defaultFromAddress: string) { + constructor(artifactAdapter: AbstractArtifactAdapter, defaultFromAddress: string, verbose: boolean = true) { super(); this._lock = new Lock(); this._defaultFromAddress = defaultFromAddress; - this._coverageManager = new CoverageManager(artifactsPath, sourcesPath, this._getContractCodeAsync.bind(this)); + this._coverageManager = new CoverageManager(artifactAdapter, this._getContractCodeAsync.bind(this), verbose); } /** * Write the test coverage results to a file in Istanbul format. @@ -119,8 +122,10 @@ export class CoverageSubprovider extends Subprovider { }; const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const trace: TransactionTrace = jsonRPCResponsePayload.result; - const coveredPcs = _.map(trace.structLogs, log => log.pc); if (address === constants.NEW_CONTRACT) { + // TODO handle calls to external contracts and contract creations from within the constructor + const structLogsOnDepth0 = _.filter(trace.structLogs, { depth: 0 }); + const coveredPcs = _.map(structLogsOnDepth0, log => log.pc); const traceInfo: TraceInfoNewContract = { coveredPcs, txHash, @@ -129,15 +134,20 @@ export class CoverageSubprovider extends Subprovider { }; this._coverageManager.appendTraceInfo(traceInfo); } else { - payload = { method: 'eth_getCode', params: [address, 'latest'] }; - const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; - const traceInfo: TraceInfoExistingContract = { - coveredPcs, - txHash, - address, - runtimeBytecode, - }; - this._coverageManager.appendTraceInfo(traceInfo); + const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); + for (const subcallAddress of _.keys(tracesByContractAddress)) { + payload = { method: 'eth_getCode', params: [subcallAddress, 'latest'] }; + const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; + const traceForThatSubcall = tracesByContractAddress[subcallAddress]; + const coveredPcs = _.map(traceForThatSubcall, log => log.pc); + const traceInfo: TraceInfoExistingContract = { + coveredPcs, + txHash, + address: subcallAddress, + runtimeBytecode, + }; + this._coverageManager.appendTraceInfo(traceInfo); + } } } private async _recordCallTraceAsync(callData: Partial, blockNumber: BlockParam): Promise { -- cgit v1.2.3 From 1ff34bd0f4084d2f9dfd6f07447bb63684ac51ac Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 15 May 2018 15:14:36 +0200 Subject: Remove web3Factory.create and remove dev-tools dependency on sol-cov --- packages/sol-cov/src/coverage_subprovider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index f421a17fd..addad5e8f 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -118,7 +118,7 @@ export class CoverageSubprovider extends Subprovider { private async _recordTxTraceAsync(address: string, data: string | undefined, txHash: string): Promise { let payload = { method: 'debug_traceTransaction', - params: [txHash, { disableMemory: true, disableStack: true, disableStorage: true }], // TODO For now testrpc just ignores those parameters https://github.com/trufflesuite/ganache-cli/issues/489 + params: [txHash, { disableMemory: true, disableStack: false, disableStorage: true }], }; const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const trace: TransactionTrace = jsonRPCResponsePayload.result; -- cgit v1.2.3 From 253bada6432bb4727de2e9d21658cd2c7a2c01b7 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Mon, 21 May 2018 17:30:38 -0700 Subject: Fix import paths --- packages/sol-cov/src/coverage_subprovider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index addad5e8f..1e050080f 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -4,7 +4,7 @@ import * as fs from 'fs'; import * as _ from 'lodash'; import { Lock } from 'semaphore-async-await'; -import { AbstractArtifactAdapter } from './artifact_adapters/abstract'; +import { AbstractArtifactAdapter } from './artifact_adapters/abstract_artifact_adapter'; import { constants } from './constants'; import { CoverageManager } from './coverage_manager'; import { getTracesByContractAddress } from './trace'; -- cgit v1.2.3 From 0c53d276f8f4725feeae48fc3534ab63db8fcafb Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 May 2018 11:10:03 -0700 Subject: Use BlockParamLiteral.Latest --- packages/sol-cov/src/coverage_subprovider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index 1e050080f..3fd45bbd1 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -8,7 +8,7 @@ import { AbstractArtifactAdapter } from './artifact_adapters/abstract_artifact_a import { constants } from './constants'; import { CoverageManager } from './coverage_manager'; import { getTracesByContractAddress } from './trace'; -import { TraceInfoExistingContract, TraceInfoNewContract } from './types'; +import { BlockParamLiteral, TraceInfoExistingContract, TraceInfoNewContract } from './types'; interface MaybeFakeTxData extends TxData { isFakeTransaction?: boolean; @@ -89,7 +89,7 @@ export class CoverageSubprovider extends Subprovider { } else { const payload = { method: 'eth_getBlockByNumber', - params: ['latest', true], + params: [BlockParamLiteral.Latest, true], }; const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const transactions = jsonRPCResponsePayload.result.transactions; @@ -136,7 +136,7 @@ export class CoverageSubprovider extends Subprovider { } else { const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); for (const subcallAddress of _.keys(tracesByContractAddress)) { - payload = { method: 'eth_getCode', params: [subcallAddress, 'latest'] }; + payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] }; const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; const traceForThatSubcall = tracesByContractAddress[subcallAddress]; const coveredPcs = _.map(traceForThatSubcall, log => log.pc); @@ -178,7 +178,7 @@ export class CoverageSubprovider extends Subprovider { private async _getContractCodeAsync(address: string): Promise { const payload = { method: 'eth_getCode', - params: [address, 'latest'], + params: [address, BlockParamLiteral.Latest], }; const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const contractCode: string = jsonRPCResponsePayload.result; -- cgit v1.2.3 From 447b305e3c50145696be715bc6f43523b0770220 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 May 2018 11:18:09 -0700 Subject: Suppport subcalls in constructor --- packages/sol-cov/src/coverage_subprovider.ts | 36 ++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index 3fd45bbd1..45b479c0e 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -123,16 +123,32 @@ export class CoverageSubprovider extends Subprovider { const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const trace: TransactionTrace = jsonRPCResponsePayload.result; if (address === constants.NEW_CONTRACT) { - // TODO handle calls to external contracts and contract creations from within the constructor - const structLogsOnDepth0 = _.filter(trace.structLogs, { depth: 0 }); - const coveredPcs = _.map(structLogsOnDepth0, log => log.pc); - const traceInfo: TraceInfoNewContract = { - coveredPcs, - txHash, - address: address as 'NEW_CONTRACT', - bytecode: data as string, - }; - this._coverageManager.appendTraceInfo(traceInfo); + const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); + for (const subcallAddress of _.keys(tracesByContractAddress)) { + let traceInfo: TraceInfoNewContract | TraceInfoExistingContract; + if (subcallAddress === 'NEW_CONTRACT') { + const traceForThatSubcall = tracesByContractAddress[subcallAddress]; + const coveredPcs = _.map(traceForThatSubcall, log => log.pc); + traceInfo = { + coveredPcs, + txHash, + address: address as 'NEW_CONTRACT', + bytecode: data as string, + }; + } else { + payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] }; + const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; + const traceForThatSubcall = tracesByContractAddress[subcallAddress]; + const coveredPcs = _.map(traceForThatSubcall, log => log.pc); + traceInfo = { + coveredPcs, + txHash, + address: subcallAddress, + runtimeBytecode, + }; + } + this._coverageManager.appendTraceInfo(traceInfo); + } } else { const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); for (const subcallAddress of _.keys(tracesByContractAddress)) { -- cgit v1.2.3 From ebc750d5bf95da76424da81550a88e6b74de8c36 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 22 May 2018 17:41:48 -0700 Subject: Address feedback --- packages/sol-cov/src/coverage_subprovider.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'packages/sol-cov/src/coverage_subprovider.ts') diff --git a/packages/sol-cov/src/coverage_subprovider.ts b/packages/sol-cov/src/coverage_subprovider.ts index 45b479c0e..438339a3f 100644 --- a/packages/sol-cov/src/coverage_subprovider.ts +++ b/packages/sol-cov/src/coverage_subprovider.ts @@ -31,13 +31,13 @@ export class CoverageSubprovider extends Subprovider { * Instantiates a CoverageSubprovider instance * @param artifactAdapter Adapter for used artifacts format (0x, truffle, giveth, etc.) * @param defaultFromAddress default from address to use when sending transactions - * @param verbose If true, we will log any unknown transactions. Otherwise we will ignore them + * @param isVerbose If true, we will log any unknown transactions. Otherwise we will ignore them */ - constructor(artifactAdapter: AbstractArtifactAdapter, defaultFromAddress: string, verbose: boolean = true) { + constructor(artifactAdapter: AbstractArtifactAdapter, defaultFromAddress: string, isVerbose: boolean = true) { super(); this._lock = new Lock(); this._defaultFromAddress = defaultFromAddress; - this._coverageManager = new CoverageManager(artifactAdapter, this._getContractCodeAsync.bind(this), verbose); + this._coverageManager = new CoverageManager(artifactAdapter, this._getContractCodeAsync.bind(this), isVerbose); } /** * Write the test coverage results to a file in Istanbul format. @@ -120,11 +120,12 @@ export class CoverageSubprovider extends Subprovider { method: 'debug_traceTransaction', params: [txHash, { disableMemory: true, disableStack: false, disableStorage: true }], }; - const jsonRPCResponsePayload = await this.emitPayloadAsync(payload); + let jsonRPCResponsePayload = await this.emitPayloadAsync(payload); const trace: TransactionTrace = jsonRPCResponsePayload.result; + const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); + const subcallAddresses = _.keys(tracesByContractAddress); if (address === constants.NEW_CONTRACT) { - const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); - for (const subcallAddress of _.keys(tracesByContractAddress)) { + for (const subcallAddress of subcallAddresses) { let traceInfo: TraceInfoNewContract | TraceInfoExistingContract; if (subcallAddress === 'NEW_CONTRACT') { const traceForThatSubcall = tracesByContractAddress[subcallAddress]; @@ -132,12 +133,13 @@ export class CoverageSubprovider extends Subprovider { traceInfo = { coveredPcs, txHash, - address: address as 'NEW_CONTRACT', + address: constants.NEW_CONTRACT, bytecode: data as string, }; } else { payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] }; - const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; + jsonRPCResponsePayload = await this.emitPayloadAsync(payload); + const runtimeBytecode = jsonRPCResponsePayload.result; const traceForThatSubcall = tracesByContractAddress[subcallAddress]; const coveredPcs = _.map(traceForThatSubcall, log => log.pc); traceInfo = { @@ -150,10 +152,10 @@ export class CoverageSubprovider extends Subprovider { this._coverageManager.appendTraceInfo(traceInfo); } } else { - const tracesByContractAddress = getTracesByContractAddress(trace.structLogs, address); - for (const subcallAddress of _.keys(tracesByContractAddress)) { + for (const subcallAddress of subcallAddresses) { payload = { method: 'eth_getCode', params: [subcallAddress, BlockParamLiteral.Latest] }; - const runtimeBytecode = (await this.emitPayloadAsync(payload)).result; + jsonRPCResponsePayload = await this.emitPayloadAsync(payload); + const runtimeBytecode = jsonRPCResponsePayload.result; const traceForThatSubcall = tracesByContractAddress[subcallAddress]; const coveredPcs = _.map(traceForThatSubcall, log => log.pc); const traceInfo: TraceInfoExistingContract = { -- cgit v1.2.3