aboutsummaryrefslogtreecommitdiffstats
path: root/packages/sol-cov/src/trace.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/sol-cov/src/trace.ts')
-rw-r--r--packages/sol-cov/src/trace.ts34
1 files changed, 21 insertions, 13 deletions
diff --git a/packages/sol-cov/src/trace.ts b/packages/sol-cov/src/trace.ts
index 4d106e355..cb5410909 100644
--- a/packages/sol-cov/src/trace.ts
+++ b/packages/sol-cov/src/trace.ts
@@ -8,6 +8,10 @@ export interface TraceByContractAddress {
[contractAddress: string]: StructLog[];
}
+function getAddressFromStackEntry(stackEntry: string): string {
+ return addressUtils.padZeros(new BigNumber(addHexPrefix(stackEntry)).toString(16));
+}
+
export function getTracesByContractAddress(structLogs: StructLog[], startAddress: string): TraceByContractAddress {
const traceByContractAddress: TraceByContractAddress = {};
let currentTraceSegment = [];
@@ -16,26 +20,32 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
for (let i = 0; i < structLogs.length; i++) {
const structLog = structLogs[i];
if (structLog.depth !== callStack.length - 1) {
- throw new Error("Malformed trace. trace depth doesn't match call stack depth");
+ 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
currentTraceSegment.push(structLog);
- if (_.includes([OpCode.CallCode, OpCode.StaticCall, OpCode.Call, OpCode.DelegateCall], structLog.op)) {
+ const isCallLike = _.includes(
+ [OpCode.CallCode, OpCode.StaticCall, OpCode.Call, OpCode.DelegateCall],
+ structLog.op,
+ );
+ const isEndOpcode = _.includes(
+ [OpCode.Return, OpCode.Stop, OpCode.Revert, OpCode.Invalid, OpCode.SelfDestruct],
+ structLog.op,
+ );
+ if (isCallLike) {
const currentAddress = _.last(callStack) as string;
const jumpAddressOffset = 1;
- const newAddress = addressUtils.padZeros(
- new BigNumber(addHexPrefix(structLog.stack[structLog.stack.length - jumpAddressOffset - 1])).toString(
- 16,
- ),
+ const newAddress = getAddressFromStackEntry(
+ structLog.stack[structLog.stack.length - jumpAddressOffset - 1],
);
if (structLog === _.last(structLogs)) {
- throw new Error('CALL-like opcode can not be the last one');
+ throw new Error('Malformed trace. CALL-like opcode can not be the last one');
}
// Sometimes calls don't change the execution context (current address). When we do a transfer to an
- // externally owned account - it does the call and immidiately returns because there is no fallback
+ // externally owned account - it does the call and immediately returns because there is no fallback
// function. We manually check if the call depth had changed to handle that case.
const nextStructLog = structLogs[i + 1];
if (nextStructLog.depth !== structLog.depth) {
@@ -45,9 +55,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
);
currentTraceSegment = [];
}
- } else if (
- _.includes([OpCode.Return, OpCode.Stop, OpCode.Revert, OpCode.Invalid, OpCode.SelfDestruct], structLog.op)
- ) {
+ } else if (isEndOpcode) {
const currentAddress = callStack.pop() as string;
traceByContractAddress[currentAddress] = (traceByContractAddress[currentAddress] || []).concat(
currentTraceSegment,
@@ -81,7 +89,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
);
currentTraceSegment = [];
} else {
- throw new Error('Shit broke');
+ throw new Error('Malformed trace. Unexpected call depth change');
}
}
}
@@ -90,7 +98,7 @@ export function getTracesByContractAddress(structLogs: StructLog[], startAddress
throw new Error('Malformed trace. Call stack non empty at the end');
}
if (currentTraceSegment.length !== 0) {
- throw new Error('Malformed trace. currentTraceSegment non empty at the end');
+ throw new Error('Malformed trace. Current trace segment non empty at the end');
}
return traceByContractAddress;
}