aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/contracts/src/utils/web3_wrapper.ts46
-rw-r--r--packages/sol-cov/src/revert_trace.ts27
-rw-r--r--packages/sol-cov/src/revert_trace_subprovider.ts6
-rw-r--r--packages/sol-cov/src/trace.ts16
4 files changed, 55 insertions, 40 deletions
diff --git a/packages/contracts/src/utils/web3_wrapper.ts b/packages/contracts/src/utils/web3_wrapper.ts
index b8e8ed8ce..f51ad435b 100644
--- a/packages/contracts/src/utils/web3_wrapper.ts
+++ b/packages/contracts/src/utils/web3_wrapper.ts
@@ -51,29 +51,29 @@ const isCoverageEnabled = env.parseBoolean(EnvVars.SolidityCoverage);
const isProfilerEnabled = env.parseBoolean(EnvVars.SolidityProfiler);
const isRevertTraceEnabled = env.parseBoolean(EnvVars.SolidityRevertTrace);
// TODO(albrow): Include revertTrace checks in the warnings below.
-// if (isCoverageEnabled && isProfilerEnabled) {
-// throw new Error(
-// `Unfortunately for now you can't enable both coverage and profiler at the same time. They both use coverage.json file and there is no way to configure that.`,
-// );
-// }
-// if (isCoverageEnabled) {
-// const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
-// prependSubprovider(provider, coverageSubprovider);
-// }
-// if (isProfilerEnabled) {
-// if (testProvider === ProviderType.Ganache) {
-// logUtils.warn(
-// "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
-// );
-// process.exit(1);
-// }
-// const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
-// logUtils.log(
-// "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
-// );
-// profilerSubprovider.stop();
-// prependSubprovider(provider, profilerSubprovider);
-// }
+if (isCoverageEnabled && isProfilerEnabled) {
+ throw new Error(
+ `Unfortunately for now you can't enable both coverage and profiler at the same time. They both use coverage.json file and there is no way to configure that.`,
+ );
+}
+if (isCoverageEnabled) {
+ const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
+ prependSubprovider(provider, coverageSubprovider);
+}
+if (isProfilerEnabled) {
+ if (testProvider === ProviderType.Ganache) {
+ logUtils.warn(
+ "Gas costs in Ganache traces are incorrect and we don't recommend using it for profiling. Please switch to Geth",
+ );
+ process.exit(1);
+ }
+ const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
+ logUtils.log(
+ "By default profilerSubprovider is stopped so that you don't get noise from setup code. Don't forget to start it before the code you want to profile and stop it afterwards",
+ );
+ profilerSubprovider.stop();
+ prependSubprovider(provider, profilerSubprovider);
+}
if (isRevertTraceEnabled) {
const revertTraceSubprovider = revertTrace.getRevertTraceSubproviderSingleton();
prependSubprovider(provider, revertTraceSubprovider);
diff --git a/packages/sol-cov/src/revert_trace.ts b/packages/sol-cov/src/revert_trace.ts
index 59edf5db4..04d410f0a 100644
--- a/packages/sol-cov/src/revert_trace.ts
+++ b/packages/sol-cov/src/revert_trace.ts
@@ -8,7 +8,7 @@ import { utils } from './utils';
export function getRevertTrace(structLogs: StructLog[], startAddress: string): EvmCallStack {
const evmCallStack: EvmCallStack = [];
- let currentAddress = startAddress;
+ const addressStack = [startAddress];
if (_.isEmpty(structLogs)) {
return [];
}
@@ -16,19 +16,17 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < normalizedStructLogs.length; i++) {
const structLog = normalizedStructLogs[i];
- if (structLog.depth !== evmCallStack.length) {
+ if (structLog.depth !== addressStack.length - 1) {
throw new Error("Malformed trace. Trace depth doesn't match call stack depth");
}
// After that check we have a guarantee that call stack is never empty
// If it would: callStack.length - 1 === structLog.depth === -1
// That means that we can always safely pop from it
- // TODO(albrow): split out isCallLike and isEndOpcode
if (utils.isCallLike(structLog.op)) {
- const evmCallStackEntry = _.last(evmCallStack) as EvmCallStackEntry;
- const prevAddress = _.isUndefined(evmCallStackEntry) ? currentAddress : evmCallStackEntry.address;
+ const currentAddress = _.last(addressStack) as string;
const jumpAddressOffset = 1;
- currentAddress = utils.getAddressFromStackEntry(
+ const newAddress = utils.getAddressFromStackEntry(
structLog.stack[structLog.stack.length - jumpAddressOffset - 1],
);
@@ -40,8 +38,9 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E
// function. We manually check if the call depth had changed to handle that case.
const nextStructLog = normalizedStructLogs[i + 1];
if (nextStructLog.depth !== structLog.depth) {
+ addressStack.push(newAddress);
evmCallStack.push({
- address: prevAddress,
+ address: currentAddress,
structLog,
});
}
@@ -50,6 +49,7 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E
const nextStructLog = normalizedStructLogs[i + 1];
if (_.isUndefined(nextStructLog) || nextStructLog.depth !== structLog.depth) {
evmCallStack.pop();
+ addressStack.pop();
}
if (structLog.op === OpCode.SelfDestruct) {
// After contract execution, we look at all sub-calls to external contracts, and for each one, fetch
@@ -63,7 +63,7 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E
}
} else if (structLog.op === OpCode.Revert) {
evmCallStack.push({
- address: currentAddress,
+ address: _.last(addressStack) as string,
structLog,
});
return evmCallStack;
@@ -73,6 +73,17 @@ export function getRevertTrace(structLogs: StructLog[], startAddress: string): E
"Detected a contract created from within another contract. Sol-cov currently doesn't support that scenario. We'll just skip that trace",
);
return [];
+ } else {
+ if (structLog !== _.last(normalizedStructLogs)) {
+ const nextStructLog = normalizedStructLogs[i + 1];
+ if (nextStructLog.depth === structLog.depth) {
+ continue;
+ } else if (nextStructLog.depth === structLog.depth - 1) {
+ addressStack.pop();
+ } else {
+ throw new Error('Malformed trace. Unexpected call depth change');
+ }
+ }
}
}
if (evmCallStack.length !== 0) {
diff --git a/packages/sol-cov/src/revert_trace_subprovider.ts b/packages/sol-cov/src/revert_trace_subprovider.ts
index ea878058c..aef9c7568 100644
--- a/packages/sol-cov/src/revert_trace_subprovider.ts
+++ b/packages/sol-cov/src/revert_trace_subprovider.ts
@@ -186,6 +186,10 @@ export class RevertTraceSubprovider extends Subprovider {
}
for (const evmCallStackEntry of evmCallStack) {
const isContractCreation = evmCallStackEntry.address === constants.NEW_CONTRACT;
+ if (isContractCreation) {
+ this._logger.error('Contract creation not supported');
+ continue;
+ }
const bytecode = await this._web3Wrapper.getContractCodeAsync(evmCallStackEntry.address);
const contractData = utils.getContractDataIfExists(this._contractsData, bytecode);
if (_.isUndefined(contractData)) {
@@ -223,7 +227,7 @@ export class RevertTraceSubprovider extends Subprovider {
sourceRanges.push(sourceRange);
}
if (sourceRanges.length > 0) {
- this._logger.error('\n\nStack trace:\n');
+ this._logger.error('\n\nStack trace for REVERT:\n');
_.forEach(sourceRanges, sourceRange => {
this._logger.error(
`${sourceRange.fileName}:${sourceRange.location.start.line}:${sourceRange.location.start.column}`,
diff --git a/packages/sol-cov/src/trace.ts b/packages/sol-cov/src/trace.ts
index b43fd19a2..fad2e5e08 100644
--- a/packages/sol-cov/src/trace.ts
+++ b/packages/sol-cov/src/trace.ts
@@ -11,7 +11,7 @@ export interface TraceByContractAddress {
export function getTracesByContractAddress(structLogs: StructLog[], startAddress: string): TraceByContractAddress {
const traceByContractAddress: TraceByContractAddress = {};
let currentTraceSegment = [];
- const callStack = [startAddress];
+ const addressStack = [startAddress];
if (_.isEmpty(structLogs)) {
return traceByContractAddress;
}
@@ -19,7 +19,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < normalizedStructLogs.length; i++) {
const structLog = normalizedStructLogs[i];
- if (structLog.depth !== callStack.length - 1) {
+ if (structLog.depth !== addressStack.length - 1) {
throw new Error("Malformed trace. Trace depth doesn't match call stack depth");
}
// After that check we have a guarantee that call stack is never empty
@@ -28,7 +28,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
currentTraceSegment.push(structLog);
if (utils.isCallLike(structLog.op)) {
- const currentAddress = _.last(callStack) as string;
+ const currentAddress = _.last(addressStack) as string;
const jumpAddressOffset = 1;
const newAddress = utils.getAddressFromStackEntry(
structLog.stack[structLog.stack.length - jumpAddressOffset - 1],
@@ -41,14 +41,14 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
// function. We manually check if the call depth had changed to handle that case.
const nextStructLog = normalizedStructLogs[i + 1];
if (nextStructLog.depth !== structLog.depth) {
- callStack.push(newAddress);
+ addressStack.push(newAddress);
traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
currentTraceSegment,
);
currentTraceSegment = [];
}
} else if (utils.isEndOpcode(structLog.op)) {
- const currentAddress = callStack.pop() as string;
+ const currentAddress = addressStack.pop() as string;
traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
currentTraceSegment,
);
@@ -75,7 +75,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
if (nextStructLog.depth === structLog.depth) {
continue;
} else if (nextStructLog.depth === structLog.depth - 1) {
- const currentAddress = callStack.pop() as string;
+ const currentAddress = addressStack.pop() as string;
traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
currentTraceSegment,
);
@@ -86,11 +86,11 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
}
}
}
- if (callStack.length !== 0) {
+ if (addressStack.length !== 0) {
logUtils.warn('Malformed trace. Call stack non empty at the end');
}
if (currentTraceSegment.length !== 0) {
- const currentAddress = callStack.pop() as string;
+ const currentAddress = addressStack.pop() as string;
traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
currentTraceSegment,
);