traceManager and traceStepManager updated

pull/697/head
aniket-engg 4 years ago committed by Aniket
parent d2161740a8
commit 80b87ef2b2
  1. 432
      libs/remix-debug/src/trace/traceManager.ts
  2. 77
      libs/remix-debug/src/trace/traceStepManager.ts

@ -7,269 +7,277 @@ const traceHelper = require('./traceHelper')
const remixLib = require('@remix-project/remix-lib')
const util = remixLib.util
function TraceManager (options) {
this.web3 = options.web3
this.isLoading = false
this.trace = null
this.traceCache = new TraceCache()
this.traceAnalyser = new TraceAnalyser(this.traceCache)
this.traceStepManager = new TraceStepManager(this.traceAnalyser)
this.tx
}
// init section
TraceManager.prototype.resolveTrace = async function (tx) {
this.tx = tx
this.init()
if (!this.web3) throw new Error('web3 not loaded')
this.isLoading = true
try {
const result = await this.getTrace(tx.hash)
if (result.structLogs.length > 0) {
this.trace = result.structLogs
export class TraceManager {
web3
isLoading: boolean
trace
traceCache
traceAnalyser
traceStepManager
tx
constructor (options) {
this.web3 = options.web3
this.isLoading = false
this.trace = null
this.traceCache = new TraceCache()
this.traceAnalyser = new TraceAnalyser(this.traceCache)
this.traceStepManager = new TraceStepManager(this.traceAnalyser)
}
this.traceAnalyser.analyse(result.structLogs, tx)
// init section
async resolveTrace (tx) {
this.tx = tx
this.init()
if (!this.web3) throw new Error('web3 not loaded')
this.isLoading = true
try {
const result = await this.getTrace(tx.hash)
if (result['structLogs'].length > 0) {
this.trace = result['structLogs']
this.traceAnalyser.analyse(result['structLogs'], tx)
this.isLoading = false
return true
}
var mes = tx.hash + ' is not a contract invocation or contract creation.'
console.log(mes)
this.isLoading = false
throw new Error(mes)
} catch (error) {
console.log(error)
this.isLoading = false
return true
throw new Error(error)
}
var mes = tx.hash + ' is not a contract invocation or contract creation.'
console.log(mes)
this.isLoading = false
throw new Error(mes)
} catch (error) {
console.log(error)
this.isLoading = false
throw new Error(error)
}
}
TraceManager.prototype.getTrace = function (txHash) {
return new Promise((resolve, reject) => {
const options = {
disableStorage: true,
disableMemory: false,
disableStack: false,
fullStorage: false
}
this.web3.debug.traceTransaction(txHash, options, function (error, result) {
if (error) return reject(error)
resolve(result)
getTrace (txHash) {
return new Promise((resolve, reject) => {
const options = {
disableStorage: true,
disableMemory: false,
disableStack: false,
fullStorage: false
}
this.web3.debug.traceTransaction(txHash, options, function (error, result) {
if (error) return reject(error)
resolve(result)
})
})
})
}
TraceManager.prototype.init = function () {
this.trace = null
this.traceCache.init()
}
// API section
TraceManager.prototype.inRange = function (step) {
return this.isLoaded() && step >= 0 && step < this.trace.length
}
TraceManager.prototype.isLoaded = function () {
return !this.isLoading && this.trace !== null
}
}
TraceManager.prototype.getLength = function (callback) {
if (!this.trace) {
callback('no trace available', null)
} else {
callback(null, this.trace.length)
init () {
this.trace = null
this.traceCache.init()
}
}
TraceManager.prototype.accumulateStorageChanges = function (index, address, storageOrigin) {
return this.traceCache.accumulateStorageChanges(index, address, storageOrigin)
}
// API section
inRange (step) {
return this.isLoaded() && step >= 0 && step < this.trace.length
}
TraceManager.prototype.getAddresses = function () {
return this.traceCache.addresses
}
isLoaded () {
return !this.isLoading && this.trace !== null
}
TraceManager.prototype.getCallDataAt = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getLength (callback) {
if (!this.trace) {
callback('no trace available', null)
} else {
callback(null, this.trace.length)
}
}
const callDataChange = util.findLowerBoundValue(stepIndex, this.traceCache.callDataChanges)
if (callDataChange === null) {
throw new Error('no calldata found')
accumulateStorageChanges (index, address, storageOrigin) {
return this.traceCache.accumulateStorageChanges(index, address, storageOrigin)
}
return [this.traceCache.callsData[callDataChange]]
}
TraceManager.prototype.buildCallPath = async function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getAddresses () {
return this.traceCache.addresses
}
const callsPath = util.buildCallPath(stepIndex, this.traceCache.callsTree.call)
if (callsPath === null) throw new Error('no call path built')
return callsPath
}
TraceManager.prototype.getCallStackAt = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getCallDataAt (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
const callDataChange = util.findLowerBoundValue(stepIndex, this.traceCache.callDataChanges)
if (callDataChange === null) {
throw new Error('no calldata found')
}
return [this.traceCache.callsData[callDataChange]]
}
const call = util.findCall(stepIndex, this.traceCache.callsTree.call)
if (call === null) {
throw new Error('no callstack found')
async buildCallPath (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
const callsPath = util.buildCallPath(stepIndex, this.traceCache.callsTree.call)
if (callsPath === null) throw new Error('no call path built')
return callsPath
}
return call.callStack
}
TraceManager.prototype.getStackAt = function (stepIndex) {
this.checkRequestedStep(stepIndex)
if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
let stack = this.trace[stepIndex].stack.slice(0)
stack.reverse()
return stack
} else {
throw new Error('no stack found')
getCallStackAt (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
const call = util.findCall(stepIndex, this.traceCache.callsTree.call)
if (call === null) {
throw new Error('no callstack found')
}
return call.callStack
}
}
TraceManager.prototype.getLastCallChangeSince = function (stepIndex) {
try {
getStackAt (stepIndex) {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
let stack = this.trace[stepIndex].stack.slice(0)
stack.reverse()
return stack
} else {
throw new Error('no stack found')
}
}
const callChange = util.findCall(stepIndex, this.traceCache.callsTree.call)
if (callChange === null) {
return 0
}
return callChange
}
getLastCallChangeSince (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
const resp = this.getLastCallChangeSince(stepIndex)
if (!resp) {
throw new Error('unable to get current called address. ' + stepIndex + ' does not match with a CALL')
const callChange = util.findCall(stepIndex, this.traceCache.callsTree.call)
if (callChange === null) {
return 0
}
return resp.address
} catch (error) {
throw new Error(error)
return callChange
}
}
TraceManager.prototype.getContractCreationCode = function (token) {
if (!this.traceCache.contractCreation[token]) {
throw new Error('no contract creation named ' + token)
getCurrentCalledAddressAt (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
const resp = this.getLastCallChangeSince(stepIndex)
if (!resp) {
throw new Error('unable to get current called address. ' + stepIndex + ' does not match with a CALL')
}
return resp.address
} catch (error) {
throw new Error(error)
}
}
return this.traceCache.contractCreation[token]
}
TraceManager.prototype.getMemoryAt = function (stepIndex) {
this.checkRequestedStep(stepIndex)
const lastChanges = util.findLowerBoundValue(stepIndex, this.traceCache.memoryChanges)
if (lastChanges === null) {
throw new Error('no memory found')
getContractCreationCode (token) {
if (!this.traceCache.contractCreation[token]) {
throw new Error('no contract creation named ' + token)
}
return this.traceCache.contractCreation[token]
}
return this.trace[lastChanges].memory
}
TraceManager.prototype.getCurrentPC = function (stepIndex) {
try {
getMemoryAt (stepIndex) {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
const lastChanges = util.findLowerBoundValue(stepIndex, this.traceCache.memoryChanges)
if (lastChanges === null) {
throw new Error('no memory found')
}
return this.trace[lastChanges].memory
}
return this.trace[stepIndex].pc
}
TraceManager.prototype.getReturnValue = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getCurrentPC (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
return this.trace[stepIndex].pc
}
if (!this.traceCache.returnValues[stepIndex]) {
throw new Error('current step is not a return step')
getReturnValue (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
if (!this.traceCache.returnValues[stepIndex]) {
throw new Error('current step is not a return step')
}
return this.traceCache.returnValues[stepIndex]
}
return this.traceCache.returnValues[stepIndex]
}
TraceManager.prototype.getCurrentStep = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getCurrentStep (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
return this.traceCache.steps[stepIndex]
}
return this.traceCache.steps[stepIndex]
}
TraceManager.prototype.getMemExpand = function (stepIndex) {
return (this.getStepProperty(stepIndex, 'memexpand') || '')
}
getMemExpand (stepIndex) {
return (this.getStepProperty(stepIndex, 'memexpand') || '')
}
TraceManager.prototype.getStepCost = function (stepIndex) {
return this.getStepProperty(stepIndex, 'gasCost')
}
getStepCost (stepIndex) {
return this.getStepProperty(stepIndex, 'gasCost')
}
TraceManager.prototype.getRemainingGas = function (stepIndex) {
return this.getStepProperty(stepIndex, 'gas')
}
getRemainingGas (stepIndex) {
return this.getStepProperty(stepIndex, 'gas')
}
TraceManager.prototype.getStepProperty = function (stepIndex, property) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
getStepProperty (stepIndex, property) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
throw new Error(check)
}
return this.trace[stepIndex][property]
}
return this.trace[stepIndex][property]
}
TraceManager.prototype.isCreationStep = function (stepIndex) {
return traceHelper.isCreateInstruction(this.trace[stepIndex])
}
isCreationStep (stepIndex) {
return traceHelper.isCreateInstruction(this.trace[stepIndex])
}
// step section
TraceManager.prototype.findStepOverBack = function (currentStep) {
return this.traceStepManager.findStepOverBack(currentStep)
}
// step section
findStepOverBack (currentStep) {
return this.traceStepManager.findStepOverBack(currentStep)
}
TraceManager.prototype.findStepOverForward = function (currentStep) {
return this.traceStepManager.findStepOverForward(currentStep)
}
findStepOverForward (currentStep) {
return this.traceStepManager.findStepOverForward(currentStep)
}
TraceManager.prototype.findNextCall = function (currentStep) {
return this.traceStepManager.findNextCall(currentStep)
}
findNextCall (currentStep) {
return this.traceStepManager.findNextCall(currentStep)
}
TraceManager.prototype.findStepOut = function (currentStep) {
return this.traceStepManager.findStepOut(currentStep)
}
findStepOut (currentStep) {
return this.traceStepManager.findStepOut(currentStep)
}
TraceManager.prototype.checkRequestedStep = function (stepIndex) {
if (!this.trace) {
throw new Error('trace not loaded')
} else if (stepIndex >= this.trace.length) {
throw new Error('trace smaller than requested')
checkRequestedStep (stepIndex) {
if (!this.trace) {
throw new Error('trace not loaded')
} else if (stepIndex >= this.trace.length) {
throw new Error('trace smaller than requested')
}
}
}
TraceManager.prototype.waterfall = function (calls, stepindex, cb) {
let ret = []
let retError = null
for (var call in calls) {
calls[call].apply(this, [stepindex, function (error, result) {
retError = error
ret.push({ error: error, value: result })
}])
waterfall (calls, stepindex, cb) {
let ret = []
let retError = null
for (var call in calls) {
calls[call].apply(this, [stepindex, function (error, result) {
retError = error
ret.push({ error: error, value: result })
}])
}
cb(retError, ret)
}
cb(retError, ret)
}
module.exports = TraceManager

@ -4,52 +4,55 @@ const traceHelper = require('./traceHelper')
const remixLib = require('@remix-project/remix-lib')
const util = remixLib.util
function TraceStepManager (_traceAnalyser) {
this.traceAnalyser = _traceAnalyser
}
export class TraceStepManager {
TraceStepManager.prototype.isCallInstruction = function (index) {
const state = this.traceAnalyser.trace[index]
return traceHelper.isCallInstruction(state) && !traceHelper.isCallToPrecompiledContract(index, this.traceAnalyser.trace)
}
traceAnalyser
TraceStepManager.prototype.isReturnInstruction = function (index) {
const state = this.traceAnalyser.trace[index]
return traceHelper.isReturnInstruction(state)
}
constructor (_traceAnalyser) {
this.traceAnalyser = _traceAnalyser
}
TraceStepManager.prototype.findStepOverBack = function (currentStep) {
if (this.isReturnInstruction(currentStep)) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
return call.start > 0 ? call.start - 1 : 0
isCallInstruction (index) {
const state = this.traceAnalyser.trace[index]
return traceHelper.isCallInstruction(state) && !traceHelper.isCallToPrecompiledContract(index, this.traceAnalyser.trace)
}
return currentStep > 0 ? currentStep - 1 : 0
}
TraceStepManager.prototype.findStepOverForward = function (currentStep) {
if (this.isCallInstruction(currentStep)) {
const call = util.findCall(currentStep + 1, this.traceAnalyser.traceCache.callsTree.call)
return call.return + 1 < this.traceAnalyser.trace.length ? call.return + 1 : this.traceAnalyser.trace.length - 1
isReturnInstruction (index) {
const state = this.traceAnalyser.trace[index]
return traceHelper.isReturnInstruction(state)
}
findStepOverBack (currentStep) {
if (this.isReturnInstruction(currentStep)) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
return call.start > 0 ? call.start - 1 : 0
}
return currentStep > 0 ? currentStep - 1 : 0
}
return this.traceAnalyser.trace.length >= currentStep + 1 ? currentStep + 1 : currentStep
}
TraceStepManager.prototype.findNextCall = function (currentStep) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
const subCalls = Object.keys(call.calls)
if (subCalls.length) {
var callStart = util.findLowerBound(currentStep, subCalls) + 1
if (subCalls.length > callStart) {
return subCalls[callStart] - 1
findStepOverForward (currentStep) {
if (this.isCallInstruction(currentStep)) {
const call = util.findCall(currentStep + 1, this.traceAnalyser.traceCache.callsTree.call)
return call.return + 1 < this.traceAnalyser.trace.length ? call.return + 1 : this.traceAnalyser.trace.length - 1
}
return this.traceAnalyser.trace.length >= currentStep + 1 ? currentStep + 1 : currentStep
}
findNextCall (currentStep) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
const subCalls = Object.keys(call.calls)
if (subCalls.length) {
var callStart = util.findLowerBound(currentStep, subCalls) + 1
if (subCalls.length > callStart) {
return parseInt(subCalls[callStart]) - 1
}
return currentStep
}
return currentStep
}
return currentStep
}
TraceStepManager.prototype.findStepOut = function (currentStep) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
return call.return
findStepOut (currentStep) {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
return call.return
}
}
module.exports = TraceStepManager

Loading…
Cancel
Save