diff --git a/src/basicPanel.js b/src/basicPanel.js
index 7ce113cacc..a1e02a6189 100644
--- a/src/basicPanel.js
+++ b/src/basicPanel.js
@@ -38,7 +38,7 @@ module.exports = React.createClass({
ret.push(
- {this.props.data[key]}
+ {this.props.data[key]}
|
)
}
diff --git a/src/memoryPanel.js b/src/memoryPanel.js
index 8dbfb066b3..1724b32a07 100644
--- a/src/memoryPanel.js
+++ b/src/memoryPanel.js
@@ -50,13 +50,13 @@ module.exports = React.createClass({
ret.push(
- {memSlot.address}
+ {memSlot.address}
|
- {memSlot.content.raw}
+ {memSlot.content.raw}
|
- {memSlot.content.ascii}
+ {memSlot.content.ascii}
|
)
}
diff --git a/src/storagePanel.js b/src/storagePanel.js
index d6799b72ec..b5eac32de7 100644
--- a/src/storagePanel.js
+++ b/src/storagePanel.js
@@ -49,10 +49,10 @@ module.exports = React.createClass({
ret.push(
- {key}
+ {key}
|
- {data[key]}
+ {data[key]}
|
)
}
diff --git a/src/traceAnalyser.js b/src/traceAnalyser.js
new file mode 100644
index 0000000000..d79368c1ba
--- /dev/null
+++ b/src/traceAnalyser.js
@@ -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
diff --git a/src/traceCache.js b/src/traceCache.js
new file mode 100644
index 0000000000..d7cb3e9a3a
--- /dev/null
+++ b/src/traceCache.js
@@ -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
diff --git a/src/traceManager.js b/src/traceManager.js
index ab0f4cc843..c53e66b81e 100644
--- a/src/traceManager.js
+++ b/src/traceManager.js
@@ -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
diff --git a/src/traceManagerUtil.js b/src/traceManagerUtil.js
new file mode 100644
index 0000000000..3231efa5af
--- /dev/null
+++ b/src/traceManagerUtil.js
@@ -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
+ }
+
+}
diff --git a/src/traceRetriever.js b/src/traceRetriever.js
new file mode 100644
index 0000000000..238510b66b
--- /dev/null
+++ b/src/traceRetriever.js
@@ -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
diff --git a/src/traceStepManager.js b/src/traceStepManager.js
new file mode 100644
index 0000000000..40d9afc098
--- /dev/null
+++ b/src/traceStepManager.js
@@ -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