modularisation

pull/7/head
yann300 9 years ago
parent ee7e8558e3
commit 2846b48268
  1. 2
      src/basicPanel.js
  2. 6
      src/memoryPanel.js
  3. 4
      src/storagePanel.js
  4. 77
      src/traceAnalyser.js
  5. 55
      src/traceCache.js
  6. 274
      src/traceManager.js
  7. 36
      src/traceManagerUtil.js
  8. 25
      src/traceRetriever.js
  9. 66
      src/traceStepManager.js

@ -38,7 +38,7 @@ module.exports = React.createClass({
ret.push(
<tr key={key}>
<td>
{this.props.data[key]}
<pre>{this.props.data[key]}</pre>
</td>
</tr>)
}

@ -50,13 +50,13 @@ module.exports = React.createClass({
ret.push(
<tr key={key}>
<td>
{memSlot.address}
<pre>{memSlot.address}</pre>
</td>
<td>
{memSlot.content.raw}
<pre>{memSlot.content.raw}</pre>
</td>
<td>
{memSlot.content.ascii}
<pre>{memSlot.content.ascii}</pre>
</td>
</tr>)
}

@ -49,10 +49,10 @@ module.exports = React.createClass({
ret.push(
<tr key={key}>
<td>
{key}
<pre>{key}</pre>
</td>
<td>
{data[key]}
<pre>{data[key]}</pre>
</td>
</tr>)
}

@ -0,0 +1,77 @@
'use strict'
function TraceAnalyser (_cache) {
this.traceCache = _cache
this.trace = null
}
TraceAnalyser.prototype.analyse = function (trace, callback) {
this.trace = trace
var currentDepth = 0
var context = {
currentStorageAddress: trace[0].address,
previousStorageAddress: trace[0].address
}
var callStack = []
for (var k in this.trace) {
var step = this.trace[k]
this.buildCalldata(k, step)
this.buildMemory(k, step)
var depth = this.buildDepth(k, step, currentDepth, callStack)
if (depth) {
currentDepth = depth
}
context = this.buildStorage(k, step, context)
}
callback(null, true)
}
TraceAnalyser.prototype.buildCalldata = function (index, step) {
if (step.calldata) {
this.traceCache.pushCallDataChanges(index)
}
}
TraceAnalyser.prototype.buildMemory = function (index, step) {
if (step.memory) {
this.traceCache.pushMemoryChanges(index)
}
}
TraceAnalyser.prototype.buildStorage = function (index, step, context) {
if (step.address) {
// new context
context.currentStorageAddress = step.address
this.traceCache.pushStoreChanges(index, context.currentStorageAddress)
} else if (step.inst === 'SSTORE') {
this.traceCache.pushStoreChanges(index, context.currentStorageAddress, step.stack[step.stack.length - 1], step.stack[step.stack.length - 2])
} else if (!step.address && step.depth) {
// returned from context
context.currentStorageAddress = context.previousStorageAddress
this.traceCache.pushStoreChanges(index, context.currentStorageAddress)
}
return context
}
TraceAnalyser.prototype.buildDepth = function (index, step, currentDepth, callStack) {
if (step.depth === undefined) return
if (step.depth > currentDepth) {
if (index === 0) {
callStack.push('0x' + step.address) // new context
} else {
// getting the address from the stack
var callTrace = this.trace[index - 1]
var address = callTrace.stack[callTrace.stack.length - 2]
callStack.push(address) // new context
}
} else if (step.depth < currentDepth) {
callStack.pop() // returning from context
}
this.traceCache.pushCallStack(index, {
stack: callStack.slice(0),
depth: step.depth
})
this.traceCache.pushDepthChanges(index)
return step.depth
}
module.exports = TraceAnalyser

@ -0,0 +1,55 @@
'use strict'
function TraceCache () {
this.init()
}
TraceCache.prototype.init = function () {
// ...Changes contains index in the vmtrace of the corresponding changes
this.depthChanges = []
this.memoryChanges = []
this.callDataChanges = []
this.storageChanges = []
this.sstore = {} // all sstore occurence in the trace
this.callStack = {} // contains all callStack by vmtrace index (we need to rebuild it, callstack is not included in the vmtrace)
}
TraceCache.prototype.pushCallDataChanges = function (value) {
this.callDataChanges.push(value)
}
TraceCache.prototype.pushMemoryChanges = function (value) {
this.memoryChanges.push(value)
}
TraceCache.prototype.pushDepthChanges = function (value) {
this.depthChanges.push(value)
}
TraceCache.prototype.pushCallStack = function (index, callStack) {
this.callStack[index] = callStack
}
TraceCache.prototype.pushStoreChanges = function (index, address, key, value) {
this.sstore[index] = {
'address': address,
'key': key,
'value': value
}
this.storageChanges.push(index)
}
TraceCache.prototype.rebuildStorage = function (address, storage, index) {
for (var k in this.storageChanges) {
var changesIndex = this.storageChanges[k]
if (changesIndex > index) {
return storage
}
var sstore = this.sstore[changesIndex]
if (sstore.address === address && sstore.key) {
storage[sstore.key] = sstore.value
}
}
return storage
}
module.exports = TraceCache

@ -1,21 +1,18 @@
'use strict'
var TraceAnalyser = require('./traceAnalyser')
var TraceRetriever = require('./traceRetriever')
var TraceCache = require('./traceCache')
var TraceStepManager = require('./traceStepManager')
var traceManagerUtil = require('./traceManagerUtil')
function TraceManager (_web3) {
this.web3 = _web3
this.isLoading = false
this.trace = null
// vmtrace changes section
this.depthChanges = []
this.callStack = {}
this.memoryChanges = []
this.callDataChanges = []
// storage section
this.storageChanges = []
this.vmTraceIndexByStorageChange = {}
this.vmTraceChangesRef = []
this.storages = {}
this.traceCache = new TraceCache()
this.traceAnalyser = new TraceAnalyser(this.traceCache)
this.traceRetriever = new TraceRetriever(_web3)
this.traceStepManager = new TraceStepManager(this.traceAnalyser)
}
// init section
@ -24,111 +21,26 @@ TraceManager.prototype.resolveTrace = function (blockNumber, txNumber, callback)
this.init()
if (!this.web3) callback(false)
var self = this
this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) {
if (!error) {
self.computeTrace(result)
callback(true)
} else {
this.traceRetriever.getTrace(blockNumber, parseInt(txNumber), function (error, result) {
self.trace = result
if (error) {
console.log(error)
callback(false)
} else {
self.traceAnalyser.analyse(result, function (error, result) {
if (error) {
console.log(error)
callback(false)
} else {
callback(true)
}
})
}
this.isLoading = false
})
}
TraceManager.prototype.init = function () {
this.trace = null
this.depthChanges = []
this.memoryChanges = []
this.callDataChanges = []
this.storageChanges = []
this.vmTraceIndexByStorageChange = {}
this.vmTraceChangesRef = []
this.callStack = {}
}
TraceManager.prototype.computeTrace = function (trace) {
this.trace = trace
var currentDepth = 0
var currentStorageAddress
var callStack = []
for (var k in this.trace) {
var step = this.trace[k]
this.buildCalldata(k, step)
this.buildMemory(k, step)
currentStorageAddress = this.buildStorage(k, step, currentStorageAddress)
var depth = this.buildDepth(k, step, currentDepth, callStack)
if (depth) {
currentDepth = depth
}
}
}
// compute trace section
TraceManager.prototype.buildCalldata = function (index, step) {
if (step.calldata) {
this.callDataChanges.push(index)
}
}
TraceManager.prototype.buildMemory = function (index, step) {
if (step.memory) {
this.memoryChanges.push(index)
}
}
TraceManager.prototype.buildStorage = function (index, step, currentAddress) {
var change = false
if (step.address) {
// new context
this.storageChanges.push({ address: step.address, changes: [] })
change = true
} else if (step.inst === 'SSTORE') {
this.storageChanges[this.storageChanges.length - 1].changes.push(
{
'key': step.stack[step.stack.length - 1],
'value': step.stack[step.stack.length - 2]
})
change = true
} else if (!step.address && step.depth) {
// returned from context
var address = this.storageChanges[this.storageChanges.length - 2].address
this.storageChanges.push({ address: address, changes: [] })
change = true
}
if (change) {
this.vmTraceIndexByStorageChange[index] = {
context: this.storageChanges.length - 1,
changes: this.storageChanges[this.storageChanges.length - 1].changes.length - 1
}
this.vmTraceChangesRef.push(index)
}
return currentAddress
}
TraceManager.prototype.buildDepth = function (index, step, currentDepth, callStack) {
if (step.depth === undefined) return
if (step.depth > currentDepth) {
if (index === 0) {
callStack.push('0x' + step.address) // new context
} else {
// getting the address from the stack
var callTrace = this.trace[index - 1]
var address = callTrace.stack[callTrace.stack.length - 2]
callStack.push(address) // new context
}
} else if (step.depth < currentDepth) {
callStack.pop() // returning from context
}
this.callStack[index] = {
stack: callStack.slice(0),
depth: step.depth,
address: step.address
}
this.depthChanges.push(index)
return step.depth
this.traceCache.init()
}
// API section
@ -138,39 +50,31 @@ TraceManager.prototype.getLength = function (callback) {
}
TraceManager.prototype.getStorageAt = function (stepIndex, blockNumber, txIndex, callback) {
var stoChange = this.findLowerBound(stepIndex, this.vmTraceChangesRef)
if (!stoChange) {
callback('cannot rebuild storage', null)
}
var stoChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.storageChanges)
var changeRefs = this.vmTraceIndexByStorageChange[stoChange]
var address = this.storageChanges[changeRefs.context].address
var address = this.traceCache.sstore[stoChange].address
var self = this
this.retrieveStorage(address, blockNumber, txIndex, function (storage) {
for (var k = 0; k < changeRefs.context; k++) {
var context = self.storageChanges[k]
if (context.address === address) {
for (var i = 0; i < context.changes.length; i++) {
if (i > changeRefs.changes) break
var change = context.changes[i]
storage[change.key] = change.value
}
}
this.traceRetriever.getStorage(blockNumber, txIndex, address, function (error, result) {
if (error) {
console.log(error)
callback(error, null)
} else {
var storage = self.traceCache.rebuildStorage(address, result, stepIndex)
callback(null, storage)
}
callback(null, storage)
})
}
TraceManager.prototype.getCallDataAt = function (stepIndex, callback) {
var callDataChange = this.findLowerBound(stepIndex, this.callDataChanges)
var callDataChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.callDataChanges)
if (!callDataChange) return callback('no calldata found', null)
callback(null, [this.trace[callDataChange].calldata])
}
TraceManager.prototype.getCallStackAt = function (stepIndex, callback) {
var callStackChange = this.findLowerBound(stepIndex, this.depthChanges)
var callStackChange = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges)
if (!callStackChange) return callback('no callstack found', null)
callback(null, this.callStack[callStackChange].stack)
callback(null, this.traceCache.callStack[callStackChange].stack)
}
TraceManager.prototype.getStackAt = function (stepIndex, callback) {
@ -185,7 +89,7 @@ TraceManager.prototype.getStackAt = function (stepIndex, callback) {
}
TraceManager.prototype.getLastDepthIndexChangeSince = function (stepIndex, callback) {
var depthIndex = this.findLowerBound(stepIndex, this.depthChanges)
var depthIndex = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.depthChanges)
callback(null, depthIndex)
}
@ -195,13 +99,13 @@ TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex, callback
if (error) {
callback(error, null)
} else {
callback(null, self.resolveAddress(addressIndex))
callback(null, traceManagerUtil.resolveCalledAddress(addressIndex, self.trace))
}
})
}
TraceManager.prototype.getMemoryAt = function (stepIndex, callback) {
var lastChanges = this.findLowerBound(stepIndex, this.memoryChanges)
var lastChanges = traceManagerUtil.findLowerBound(stepIndex, this.traceCache.memoryChanges)
if (!lastChanges) return callback('no memory found', null)
callback(null, this.trace[lastChanges].memory)
}
@ -227,114 +131,20 @@ TraceManager.prototype.getRemainingGas = function (stepIndex, callback) {
}
// step section
TraceManager.prototype.isCallInstruction = function (index) {
var state = this.trace[index]
return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL'
}
TraceManager.prototype.isReturnInstruction = function (index) {
var state = this.trace[index]
return state.instname === 'RETURN'
}
TraceManager.prototype.findStepOverBack = function (currentStep) {
if (this.isReturnInstruction(currentStep - 1)) {
return this.findStepOutBack(currentStep)
} else {
return currentStep - 1
}
return this.traceStepManager.findStepOverBack(currentStep)
}
TraceManager.prototype.findStepOverForward = function (currentStep) {
if (this.isCallInstruction(currentStep)) {
return this.findStepOutForward(currentStep)
} else {
return currentStep + 1
}
return this.traceStepManager.findStepOverForward(currentStep)
}
TraceManager.prototype.findStepOutBack = function (currentStep) {
var i = currentStep - 1
var depth = 0
while (--i >= 0) {
if (this.isCallInstruction(i)) {
if (depth === 0) {
break
} else {
depth--
}
} else if (this.isReturnInstruction(i)) {
depth++
}
}
return i
return this.traceStepManager.findStepOutBack(currentStep)
}
TraceManager.prototype.findStepOutForward = function (currentStep) {
var i = currentStep
var depth = 0
while (++i < this.trace.length) {
if (this.isReturnInstruction(i)) {
if (depth === 0) {
break
} else {
depth--
}
} else if (this.isCallInstruction(i)) {
depth++
}
}
return i + 1
}
// util section
TraceManager.prototype.findLowerBound = function (target, changes) {
if (changes.length === 1) {
if (changes[0] > target) {
// we only a closest maximum, returning 0
return null
} else {
return changes[0]
}
}
var middle = Math.floor(changes.length / 2)
if (changes[middle] > target) {
return this.findLowerBound(target, changes.slice(0, middle))
} else if (changes[middle] < target) {
return this.findLowerBound(target, changes.slice(middle, changes.length))
} else {
return changes[middle]
}
}
TraceManager.prototype.resolveAddress = function (vmTraceIndex) {
var address = this.trace[vmTraceIndex].address
if (vmTraceIndex > 0) {
var stack = this.trace[vmTraceIndex - 1].stack // callcode, delegatecall, ...
address = stack[stack.length - 2]
}
return address
}
// retrieve the storage of an account just after the execution of tx
TraceManager.prototype.retrieveStorage = function (address, blockNumber, txIndex, callBack) {
if (this.storages[address]) {
callBack(this.storages[address])
}
var self = this
if (blockNumber !== null && txIndex !== null) {
this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) {
if (error) {
console.log(error)
} else {
self.storages[address] = result
callBack(result)
}
})
} else {
console.log('blockNumber/txIndex are not defined')
}
return this.traceStepManager.findStepOutForward(currentStep)
}
module.exports = TraceManager

@ -0,0 +1,36 @@
module.exports = {
// util section
findLowerBound: function (target, changes) {
if (changes.length === 0) {
return undefined
}
if (changes.length === 1) {
if (changes[0] > target) {
// we only a closest maximum, returning O
return 0
} else {
return changes[0]
}
}
var middle = Math.floor(changes.length / 2)
if (changes[middle] > target) {
return this.findLowerBound(target, changes.slice(0, middle))
} else if (changes[middle] < target) {
return this.findLowerBound(target, changes.slice(middle, changes.length))
} else {
return changes[middle]
}
},
resolveCalledAddress: function (vmTraceIndex, trace) {
var address = trace[vmTraceIndex].address
if (vmTraceIndex > 0) {
var stack = trace[vmTraceIndex - 1].stack // callcode, delegatecall, ...
address = stack[stack.length - 2]
}
return address
}
}

@ -0,0 +1,25 @@
'use strict'
function TraceRetriever (_web3) {
this.web3 = _web3
this.storages = {} // contains all intial storage (by addresses)
}
TraceRetriever.prototype.getTrace = function (blockNumber, txNumber, callback) {
this.web3.debug.trace(blockNumber, parseInt(txNumber), function (error, result) {
callback(error, result)
})
}
TraceRetriever.prototype.getStorage = function (blockNumber, txIndex, address, callback) {
if (this.storages[address]) {
callback(null, this.storages[address])
} else {
var self = this
this.web3.debug.storageAt(blockNumber, txIndex, address, function (error, result) {
self.storages[address] = result
callback(error, result)
})
}
}
module.exports = TraceRetriever

@ -0,0 +1,66 @@
'use strict'
function TraceStepManager (_traceAnalyser) {
this.traceAnalyser = _traceAnalyser
}
TraceStepManager.prototype.isCallInstruction = function (index) {
var state = this.traceAnalyser.trace[index]
return state.instname === 'CALL' || state.instname === 'CALLCODE' || state.instname === 'CREATE' || state.instname === 'DELEGATECALL'
}
TraceStepManager.prototype.isReturnInstruction = function (index) {
var state = this.traceAnalyser.trace[index]
return state.instname === 'RETURN'
}
TraceStepManager.prototype.findStepOverBack = function (currentStep) {
if (this.isReturnInstruction(currentStep - 1)) {
return this.findStepOutBack(currentStep)
} else {
return currentStep - 1
}
}
TraceStepManager.prototype.findStepOverForward = function (currentStep) {
if (this.isCallInstruction(currentStep)) {
return this.findStepOutForward(currentStep)
} else {
return currentStep + 1
}
}
TraceStepManager.prototype.findStepOutBack = function (currentStep) {
var i = currentStep - 1
var depth = 0
while (--i >= 0) {
if (this.isCallInstruction(i)) {
if (depth === 0) {
break
} else {
depth--
}
} else if (this.isReturnInstruction(i)) {
depth++
}
}
return i
}
TraceStepManager.prototype.findStepOutForward = function (currentStep) {
var i = currentStep
var depth = 0
while (++i < this.traceAnalyser.length) {
if (this.isReturnInstruction(i)) {
if (depth === 0) {
break
} else {
depth--
}
} else if (this.isCallInstruction(i)) {
depth++
}
}
return i + 1
}
module.exports = TraceStepManager
Loading…
Cancel
Save