Skip to content

Instantly share code, notes, and snippets.

@DanielVF
Created September 9, 2019 17:01
Show Gist options
  • Save DanielVF/a18d51bc7244239ec0568bbc103a7cee to your computer and use it in GitHub Desktop.
Save DanielVF/a18d51bc7244239ec0568bbc103a7cee to your computer and use it in GitHub Desktop.
Pretty print control flow of Etherium debug traces
const fs = require('fs')
const chalk = require('chalk')
const trace = JSON.parse(fs.readFileSync('2019_08_09_mike_fail.json'))
const logs = trace.result.structLogs as TraceLog[]
interface TraceLog {
depth: number
error: string
gas: number,
gasCost: number,
memory: string[],
op: string,
pc: number,
stack: string[],
storage: Record<string, string>
address: string
targetAddress: string,
callDepth: number
}
function targetAddress(log: TraceLog) : string {
return log.stack[log.stack.length - 2].replace(/^000000000000000000000000/, '')
}
function callArgs(log: TraceLog) : string {
if(log.op == "DELEGATECALL"){
const start = parseInt(log.stack[log.stack.length - 3], 16)
const length = parseInt(log.stack[log.stack.length - 4], 16)
return getMemory(log, start, length)
} else {
const start = parseInt(log.stack[log.stack.length - 4], 16)
const length = parseInt(log.stack[log.stack.length - 5], 16)
return getMemory(log, start, length)
}
}
function getMemory(log: TraceLog, start: number, length: number): string {
let out : string[] = []
let remaining = length
let slot = Math.floor(start / 32)
let offset = start - slot * 32
// console.log('READ', start, length, remaining, slot, offset)
while(remaining > 0){
const slotLen = Math.min(32 - offset, remaining)
remaining -= slotLen
// console.log('Slot',slot, offset, 'To read', slotLen, remaining)
if(log.memory[slot] == undefined){
console.log("READ PAST SLOT")
break
}
out.push(log.memory[slot].substr(offset * 2, slotLen * 2))
offset = 0
slot += 1
}
return out.join("")
}
// Build contract address flow
let currentAddress: string = 'START'
const contractAddressStack: string[] = [currentAddress]
logs.forEach(log => {
log.address = currentAddress
log.callDepth = contractAddressStack.length
if (log.op == "CREATE" || log.op == "CREATE2" ) {
currentAddress = 'NEW'
contractAddressStack.push(currentAddress)
}
if (log.op == "DELEGATECALL" || log.op == "STATICCALL" || log.op == "CALL" || log.op == "CALLCODE") {
currentAddress = targetAddress(log)
contractAddressStack.push(currentAddress)
}
if (log.op == "RETURN" || log.op == "REVERT") {
currentAddress = contractAddressStack.pop() as string
}
if (log.op == "CALL" || log.op == "CALLCODE" || log.op == "RETURN" || log.op == "DELEGATECALL" || log.op == "STATICCALL" || log.op == "REVERT") {
// console.log(log)
}
// console.log(log.pc, log.op)
})
// console.log(logs[0])
logs.forEach(log => {
if (log.op == "DELEGATECALL" || log.op == "STATICCALL" || log.op == "CALL" || log.op == "CALLCODE") {
const target = targetAddress(log)
const args = callArgs(log)
let methodSig = "?"
if(args.length > 0){
methodSig = args.substr(0,8)
}
console.log(chalk.red(log.op), target, methodSig)
}
if (log.op == "RETURN" || log.op == "REVERT") {
console.log(chalk.red(log.op) )
}
console.log(`${log.pc}\t${log.op} ${chalk.blue(log.gas)}`)
})
console.log('----')
console.log(contractAddressStack)
logs.forEach(log => {
if (log.op == "CREATE" || log.op == "CREATE2"){
console.log(`${chalk.red(log.op)} ${chalk.blue(log.gas)}` )
}
const openingSpace = ' '.repeat(log.callDepth)
if (log.op == "DELEGATECALL" || log.op == "STATICCALL" || log.op == "CALL" || log.op == "CALLCODE") {
const target = targetAddress(log)
const args = callArgs(log)
let methodSig = "?"
if(args.length > 0){
methodSig = args.substr(0,8)
}
console.log(`${openingSpace}${chalk.red(log.op)} ${target} ${methodSig} ${chalk.blue(log.gas)}\n${openingSpace}${chalk.grey(args)}`)
}
if (log.op == "RETURN" || log.op == "REVERT") {
console.log(`${openingSpace}${chalk.red(log.op)} ${chalk.blue(log.gas)}` )
}
//console.log(log)
})
// curl 'https://www.4byte.directory/api/v1/signatures/?hex_signature=095ea7b3'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment