Merge pull request #62 from ethereum/refactor_remix_debug2c_2

remove callbacks from more methods
pull/380/head
yann300 4 years ago committed by GitHub
commit e339feca5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      libs/remix-debug/src/Ethdebugger.js
  2. 82
      libs/remix-debug/src/debugger/VmDebugger.js
  3. 23
      libs/remix-debug/src/debugger/solidityLocals.js
  4. 9
      libs/remix-debug/src/debugger/stepManager.js
  5. 33
      libs/remix-debug/src/solidity-decoder/astHelper.js
  6. 80
      libs/remix-debug/src/solidity-decoder/internalCallTree.js
  7. 38
      libs/remix-debug/src/solidity-decoder/solidityProxy.js
  8. 5
      libs/remix-debug/src/solidity-decoder/types/Bool.js
  9. 12
      libs/remix-debug/src/solidity-decoder/types/Enum.js
  10. 6
      libs/remix-debug/src/solidity-decoder/types/util.js
  11. 4
      libs/remix-debug/src/storage/mappingPreimages.js
  12. 116
      libs/remix-debug/src/storage/storageResolver.js
  13. 51
      libs/remix-debug/src/storage/storageViewer.js
  14. 24
      libs/remix-debug/test/debugger.js
  15. 18
      libs/remix-debug/test/decoder/localsTests/helper.js
  16. 32
      libs/remix-lib/src/code/codeManager.js
  17. 48
      libs/remix-lib/src/sourceLocationTracker.js
  18. 86
      libs/remix-lib/src/trace/traceManager.js
  19. 155
      libs/remix-lib/test/traceManager.js

@ -90,8 +90,23 @@ Ethdebugger.prototype.extractLocalsAt = function (step, callback) {
Ethdebugger.prototype.decodeLocalsAt = function (step, sourceLocation, callback) {
const self = this
this.traceManager.waterfall([
this.traceManager.getStackAt,
this.traceManager.getMemoryAt,
function getStackAt (stepIndex, callback) {
try {
const result = self.traceManager.getStackAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
},
function getMemoryAt (stepIndex, callback) {
try {
const result = self.traceManager.getMemoryAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
},
function getCurrentCalledAddressAt (stepIndex, next) {
try {
const address = self.traceManager.getCurrentCalledAddressAt(stepIndex)

@ -60,23 +60,23 @@ class VmDebuggerLogic {
this.event.trigger('functionsStackUpdate', [this._callTree.retrieveFunctionsStack(index)])
this._traceManager.getCallDataAt(index, (error, calldata) => {
if (error) {
// console.log(error)
this.event.trigger('traceManagerCallDataUpdate', [{}])
} else if (this.stepManager.currentStepIndex === index) {
try {
const calldata = this._traceManager.getCallDataAt(index)
if (this.stepManager.currentStepIndex === index) {
this.event.trigger('traceManagerCallDataUpdate', [calldata])
}
})
} catch (error) {
this.event.trigger('traceManagerCallDataUpdate', [{}])
}
this._traceManager.getMemoryAt(index, (error, memory) => {
if (error) {
// console.log(error)
this.event.trigger('traceManagerMemoryUpdate', [{}])
} else if (this.stepManager.currentStepIndex === index) {
try {
const memory = this._traceManager.getMemoryAt(index)
if (this.stepManager.currentStepIndex === index) {
this.event.trigger('traceManagerMemoryUpdate', [ui.formatMemory(memory, 16)])
}
})
} catch (error) {
this.event.trigger('traceManagerMemoryUpdate', [{}])
}
try {
const callstack = this._traceManager.getCallStackAt(index)
@ -87,14 +87,14 @@ class VmDebuggerLogic {
this.event.trigger('traceManagerCallStackUpdate', [{}])
}
this._traceManager.getStackAt(index, (error, callstack) => {
if (error) {
// console.log(error)
this.event.trigger('traceManagerStackUpdate', [{}])
} else if (this.stepManager.currentStepIndex === index) {
try {
const callstack = this._traceManager.getStackAt(index)
if (this.stepManager.currentStepIndex === index) {
this.event.trigger('traceManagerStackUpdate', [callstack])
}
})
} catch (error) {
this.event.trigger('traceManagerStackUpdate', [{}])
}
try {
const address = this._traceManager.getCurrentCalledAddressAt(index)
@ -102,21 +102,24 @@ class VmDebuggerLogic {
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
storageViewer.storageRange((error, storage) => {
if (error) {
this.event.trigger('traceManagerStorageUpdate', [{}])
} else if (this.stepManager.currentStepIndex === index) {
storageViewer.storageRange().then((storage) => {
if (this.stepManager.currentStepIndex === index) {
var header = storageViewer.isComplete(address) ? '[Completely Loaded]' : '[Partially Loaded]'
this.event.trigger('traceManagerStorageUpdate', [storage, header])
}
}).catch((_error) => {
this.event.trigger('traceManagerStorageUpdate', [{}])
})
} catch (error) {
console.log(error)
this.event.trigger('traceManagerStorageUpdate', [{}])
}
this._traceManager.getCurrentStep(index, (error, step) => {
this.event.trigger('traceCurrentStepUpdate', [error, step])
})
try {
const step = this._traceManager.getCurrentStep(index)
this.event.trigger('traceCurrentStepUpdate', [null, step])
} catch (error) {
this.event.trigger('traceCurrentStepUpdate', [error])
}
try {
const addmem = this._traceManager.getMemExpand(index)
@ -146,13 +149,14 @@ class VmDebuggerLogic {
this.event.trigger('traceRemainingGasUpdate', [error])
}
this._traceManager.getReturnValue(index, (error, returnValue) => {
if (error) {
this.event.trigger('traceReturnValueUpdate', [[error]])
} else if (this.stepManager.currentStepIndex === index) {
try {
const returnValue = this._traceManager.getReturnValue(index)
if (this.stepManager.currentStepIndex === index) {
this.event.trigger('traceReturnValueUpdate', [[returnValue]])
}
})
} catch (error) {
this.event.trigger('traceReturnValueUpdate', [[error]])
}
})
}
@ -161,11 +165,9 @@ class VmDebuggerLogic {
this.traceLength = 0
this.debugger.event.register('newTraceLoaded', (length) => {
this._traceManager.getAddresses((error, addresses) => {
if (error) return
this.event.trigger('traceAddressesUpdate', [addresses])
this.addresses = addresses
})
const addresses = this._traceManager.getAddresses()
this.event.trigger('traceAddressesUpdate', [addresses])
this.addresses = addresses
this._traceManager.getLength((error, length) => {
if (error) return
@ -186,11 +188,9 @@ class VmDebuggerLogic {
for (var k in this.addresses) {
var address = this.addresses[k]
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
storageViewer.storageRange((error, result) => {
if (!error) {
storageJSON[address] = result
this.event.trigger('traceStorageUpdate', [storageJSON])
}
storageViewer.storageRange().then((result) => {
storageJSON[address] = result
this.event.trigger('traceStorageUpdate', [storageJSON])
})
}
})

@ -30,13 +30,28 @@ class DebuggerSolidityLocals {
}
decode (sourceLocation) {
const self = this
this.event.trigger('solidityLocalsMessage', [''])
this.traceManager.waterfall([
this.traceManager.getStackAt,
this.traceManager.getMemoryAt,
(stepIndex, next) => {
function getStackAt (stepIndex, callback) {
try {
const address = this.traceManager.getCurrentCalledAddressAt(stepIndex)
const result = self.traceManager.getStackAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
},
function getMemoryAt (stepIndex, callback) {
try {
const result = self.traceManager.getMemoryAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
},
function getCurrentCalledAddressAt (stepIndex, next) {
try {
const address = self.traceManager.getCurrentCalledAddressAt(stepIndex)
next(null, address)
} catch (error) {
next(error)

@ -41,11 +41,7 @@ class DebuggerStepManager {
if (index < 0) return
if (this.currentStepIndex !== index) return
this.traceManager.buildCallPath(index, (error, callsPath) => {
if (error) {
console.log(error)
return this.event.trigger('revertWarning', [''])
}
this.traceManager.buildCallPath(index).then((callsPath) => {
this.currentCall = callsPath[callsPath.length - 1]
if (this.currentCall.reverted) {
let revertedReason = this.currentCall.outofgas ? 'outofgas' : ''
@ -59,6 +55,9 @@ class DebuggerStepManager {
this.event.trigger('revertWarning', ['parenthasthrown'])
}
this.event.trigger('revertWarning', [''])
}).catch((error) => {
console.log(error)
this.event.trigger('revertWarning', [''])
})
})
}

@ -51,27 +51,24 @@ function extractStateDefinitions (contractName, sourcesList, contracts) {
contracts = extractContractDefinitions(sourcesList)
}
const node = contracts.contractsByName[contractName]
if (node) {
const stateItems = []
const stateVar = []
const baseContracts = getLinearizedBaseContracts(node.id, contracts.contractsById)
baseContracts.reverse()
for (let k in baseContracts) {
const ctr = baseContracts[k]
for (let i in ctr.children) {
const item = ctr.children[i]
stateItems.push(item)
if (item.name === 'VariableDeclaration') {
stateVar.push(item)
}
if (!node) {
return null
}
const stateItems = []
const stateVar = []
const baseContracts = getLinearizedBaseContracts(node.id, contracts.contractsById)
baseContracts.reverse()
for (let k in baseContracts) {
const ctr = baseContracts[k]
for (let i in ctr.children) {
const item = ctr.children[i]
stateItems.push(item)
if (item.name === 'VariableDeclaration') {
stateVar.push(item)
}
}
return {
stateDefinitions: stateItems,
stateVariables: stateVar
}
}
return null
return {stateDefinitions: stateItems, stateVariables: stateVar}
}
/**

@ -224,26 +224,27 @@ function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLoc
// we check if the current vm trace step target a new ast node of type VariableDeclaration
// that way we know that there is a new local variable from here.
if (variableDeclaration && !tree.scopes[scopeId].locals[variableDeclaration.attributes.name]) {
tree.traceManager.getStackAt(step, (error, stack) => {
try {
const stack = tree.traceManager.getStackAt(step)
// the stack length at this point is where the value of the new local variable will be stored.
// so, either this is the direct value, or the offset in memory. That depends on the type.
if (!error) {
tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached
if (!error && variableDeclaration.attributes.name !== '') {
var states = tree.solidityProxy.extractStatesDefinitions()
var location = typesUtil.extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
tree.solidityProxy.contractNameAt(step).then((contractName) => {
if (variableDeclaration.attributes.name !== '') {
var states = tree.solidityProxy.extractStatesDefinitions()
var location = typesUtil.extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = {
name: variableDeclaration.attributes.name,
type: decodeInfo.parseType(variableDeclaration.attributes.type, states, contractName, location),
stackDepth: stack.length,
sourceLocation: sourceLocation
}
tree.scopes[scopeId].locals[variableDeclaration.attributes.name] = {
name: variableDeclaration.attributes.name,
type: decodeInfo.parseType(variableDeclaration.attributes.type, states, contractName, location),
stackDepth: stack.length,
sourceLocation: sourceLocation
}
})
}
})
}
})
} catch (error) {
console.log(error)
}
}
// we check here if we are at the beginning inside a new function.
// if that is the case, we have to add to locals tree the inputs and output params
@ -253,34 +254,35 @@ function includeVariableDeclaration (tree, step, sourceLocation, scopeId, newLoc
const functionDefinitionAndInputs = {functionDefinition, inputs: []}
// means: the previous location was a function definition && JUMPDEST
// => we are at the beginning of the function and input/output are setup
tree.solidityProxy.contractNameAt(step, (error, contractName) => { // cached
if (!error) {
tree.traceManager.getStackAt(step, (error, stack) => {
if (!error) {
var states = tree.solidityProxy.extractStatesDefinitions()
if (functionDefinition.children && functionDefinition.children.length) {
let inputs
let outputs
for (const element of functionDefinition.children) {
if (element.name === 'ParameterList') {
if (!inputs) inputs = element
else {
outputs = element
break
}
}
}
// input params
if (inputs) {
functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractName, previousSourceLocation, stack.length, inputs.children.length, -1)
tree.solidityProxy.contractNameAt(step).then((contractName) => { // cached
try {
const stack = tree.traceManager.getStackAt(step)
var states = tree.solidityProxy.extractStatesDefinitions()
if (functionDefinition.children && functionDefinition.children.length) {
let inputs
let outputs
for (const element of functionDefinition.children) {
if (element.name === 'ParameterList') {
if (!inputs) inputs = element
else {
outputs = element
break
}
// output params
if (outputs) addParams(outputs, tree, scopeId, states, contractName, previousSourceLocation, stack.length, 0, 1)
}
}
})
// input params
if (inputs) {
functionDefinitionAndInputs.inputs = addParams(inputs, tree, scopeId, states, contractName, previousSourceLocation, stack.length, inputs.children.length, -1)
}
// output params
if (outputs) addParams(outputs, tree, scopeId, states, contractName, previousSourceLocation, stack.length, 0, 1)
}
} catch (error) {
console.log(error)
}
})
tree.functionDefinitionsByScope[scopeId] = functionDefinitionAndInputs
}
}

@ -39,26 +39,25 @@ class SolidityProxy {
* @param {Int} vmTraceIndex - index in the vm trave where to resolve the executed contract name
* @param {Function} cb - callback returns (error, contractName)
*/
contractNameAt (vmTraceIndex, cb) {
try {
const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex)
if (this.cache.contractNameByAddress[address]) {
cb(null, this.cache.contractNameByAddress[address])
} else {
contractNameAt (vmTraceIndex) {
return new Promise((resolve, reject) => {
try {
const address = this.traceManager.getCurrentCalledAddressAt(vmTraceIndex)
if (this.cache.contractNameByAddress[address]) {
return resolve(this.cache.contractNameByAddress[address])
}
this.codeManager.getCode(address, (error, code) => {
if (error) {
cb(error)
} else {
const contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.cache.contractNameByAddress[address] = contractName
cb(null, contractName)
return reject(error)
}
const contractName = contractNameFromCode(this.contracts, code.bytecode, address)
this.cache.contractNameByAddress[address] = contractName
resolve(contractName)
})
} catch (error) {
reject(error)
}
} catch (error) {
cb(error)
}
})
}
/**
@ -98,12 +97,9 @@ class SolidityProxy {
*/
extractStateVariablesAt (vmtraceIndex) {
return new Promise((resolve, reject) => {
this.contractNameAt(vmtraceIndex, (error, contractName) => {
if (error) {
return reject(error)
}
return resolve(this.extractStateVariables(contractName))
})
this.contractNameAt(vmtraceIndex).then((contractName) => {
resolve(this.extractStateVariables(contractName))
}).catch(reject)
})
}

@ -10,10 +10,9 @@ class Bool extends ValueType {
decodeValue (value) {
if (!value) {
return false
} else {
value = util.extractHexByteSlice(value, this.storageBytes, 0)
return value !== '00'
}
value = util.extractHexByteSlice(value, this.storageBytes, 0)
return value !== '00'
}
}

@ -16,14 +16,12 @@ class Enum extends ValueType {
decodeValue (value) {
if (!value) {
return this.enumDef.children[0].attributes.name
} else {
value = parseInt(value, 16)
if (this.enumDef.children.length > value) {
return this.enumDef.children[value].attributes.name
} else {
return 'INVALID_ENUM<' + value + '>'
}
}
value = parseInt(value, 16)
if (this.enumDef.children.length > value) {
return this.enumDef.children[value].attributes.name
}
return 'INVALID_ENUM<' + value + '>'
}
}

@ -100,9 +100,8 @@ function extractLocation (type) {
let match = type.match(/( storage ref| storage pointer| memory| calldata)?$/)
if (match[1] !== '') {
return match[1].trim()
} else {
return null
}
return null
}
function extractLocationFromAstVariable (node) {
@ -110,9 +109,8 @@ function extractLocationFromAstVariable (node) {
return node.attributes.storageLocation
} else if (node.attributes.stateVariable) {
return 'storage'
} else {
return 'default' // local variables => storage, function parameters & return values => memory, state => storage
}
return 'default' // local variables => storage, function parameters & return values => memory, state => storage
}
function normalizeHex (hex) {

@ -13,7 +13,7 @@ module.exports = {
* @param {Function} callback - calback
* @return {Map} - solidity mapping location (e.g { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... })
*/
async function decodeMappingsKeys (web3, storage, corrections, callback) {
async function decodeMappingsKeys (web3, storage, corrections) {
const ret = {}
if (!corrections.length) corrections.push({offset: 0, slot: 0})
for (let hashedLoc in storage) {
@ -38,7 +38,7 @@ async function decodeMappingsKeys (web3, storage, corrections, callback) {
ret[mappingSlot][mappingKey] = preimage
}
}
callback(null, ret)
return ret
}
/**

@ -25,8 +25,8 @@ class StorageResolver {
* @param {String} - address - lookup address
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value}
*/
storageRange (tx, stepIndex, address, callback) {
this.storageRangeInternal(this, this.zeroSlot, tx, stepIndex, address, callback)
storageRange (tx, stepIndex, address) {
return this.storageRangeInternal(this, this.zeroSlot, tx, stepIndex, address)
}
/**
@ -39,22 +39,16 @@ class StorageResolver {
* @param {Array} corrections - used in case the calculated sha3 has been modifyed before SSTORE (notably used for struct in mapping).
* @return {Function} - callback
*/
initialPreimagesMappings (tx, stepIndex, address, corrections, callback) {
if (this.preimagesMappingByAddress[address]) {
return callback(null, this.preimagesMappingByAddress[address])
}
this.storageRange(tx, stepIndex, address, (error, storage) => {
if (error) {
return callback(error)
initialPreimagesMappings (tx, stepIndex, address, corrections) {
return new Promise((resolve, reject) => {
if (this.preimagesMappingByAddress[address]) {
return resolve(this.preimagesMappingByAddress[address])
}
mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections, (error, mappings) => {
if (error) {
callback(error)
} else {
this.preimagesMappingByAddress[address] = mappings
callback(null, mappings)
}
})
this.storageRange(tx, stepIndex, address).then((storage) => {
const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storage, corrections)
this.preimagesMappingByAddress[address] = mappings
resolve(mappings)
}).catch(reject)
})
}
@ -67,13 +61,11 @@ class StorageResolver {
* @param {String} - address - lookup address
* @param {Function} - callback - {key, hashedKey, value} -
*/
storageSlot (slot, tx, stepIndex, address, callback) {
this.storageRangeInternal(this, slot, tx, stepIndex, address, (error, storage) => {
if (error) {
callback(error)
} else {
callback(null, storage[slot] !== undefined ? storage[slot] : null)
}
storageSlot (slot, tx, stepIndex, address) {
return new Promise((resolve, reject) => {
this.storageRangeInternal(this, slot, tx, stepIndex, address).then((storage) => {
resolve(storage[slot] !== undefined ? storage[slot] : null)
}).catch(reject)
})
}
@ -93,26 +85,26 @@ class StorageResolver {
* even if the next 1000 items are not in the cache.
* - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots.
*/
storageRangeInternal (self, slotKey, tx, stepIndex, address, callback) {
var cached = this.fromCache(self, address)
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000...
return callback(null, cached.storage)
}
this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize, (error, storage, nextKey) => {
if (error) {
return callback(error)
storageRangeInternal (self, slotKey, tx, stepIndex, address) {
return new Promise((resolve, reject) => {
var cached = this.fromCache(self, address)
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000...
return resolve(cached.storage)
}
if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency)
storage[slotKey] = {
key: slotKey,
value: self.zeroSlot
this.storageRangeWeb3Call(tx, address, slotKey, self.maxSize).then((result) => {
const [storage, nextKey] = result
if (!storage[slotKey] && slotKey !== self.zeroSlot) { // we don't cache the zero slot (could lead to inconsistency)
storage[slotKey] = {
key: slotKey,
value: self.zeroSlot
}
}
}
self.toCache(self, address, storage)
if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
self.storageByAddress[address].complete = true
}
callback(null, storage)
self.toCache(self, address, storage)
if (slotKey === self.zeroSlot && !nextKey) { // only working if keys are sorted !!
self.storageByAddress[address].complete = true
}
return resolve(storage)
}).catch(reject)
})
}
@ -142,25 +134,27 @@ class StorageResolver {
self.storageByAddress[address].storage = Object.assign(self.storageByAddress[address].storage || {}, storage)
}
storageRangeWeb3Call (tx, address, start, maxSize, callback) {
if (traceHelper.isContractCreation(address)) {
callback(null, {}, null)
} else {
this.web3.debug.storageRangeAt(
tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex,
address,
start,
maxSize,
(error, result) => {
if (error) {
callback(error)
} else if (result.storage) {
callback(null, result.storage, result.nextKey)
} else {
callback('the storage has not been provided')
}
})
}
storageRangeWeb3Call (tx, address, start, maxSize) {
return new Promise((resolve, reject) => {
if (traceHelper.isContractCreation(address)) {
resolve([{}, null])
} else {
this.web3.debug.storageRangeAt(
tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex,
address,
start,
maxSize,
(error, result) => {
if (error) {
reject(error)
} else if (result.storage) {
resolve([result.storage, result.nextKey])
} else {
reject('the storage has not been provided')
}
})
}
})
}
}

@ -15,13 +15,7 @@ class StorageViewer {
this.web3 = this.storageResolver.web3
this.initialMappingsLocationPromise = null
this.currentMappingsLocationPromise = null
_traceManager.accumulateStorageChanges(this.context.stepIndex, this.context.address, {}, (error, storageChanges) => {
if (!error) {
this.storageChanges = storageChanges
} else {
console.log(error)
}
})
this.storageChanges = _traceManager.accumulateStorageChanges(this.context.stepIndex, this.context.address, {})
}
/**
@ -30,13 +24,11 @@ class StorageViewer {
*
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value}
*/
storageRange (callback) {
this.storageResolver.storageRange(this.context.tx, this.context.stepIndex, this.context.address, (error, storage) => {
if (error) {
callback(error)
} else {
callback(null, Object.assign({}, storage, this.storageChanges))
}
storageRange () {
return new Promise((resolve, reject) => {
this.storageResolver.storageRange(this.context.tx, this.context.stepIndex, this.context.address).then((storage) => {
resolve(Object.assign({}, storage, this.storageChanges))
}).catch(reject)
})
}
@ -50,13 +42,9 @@ class StorageViewer {
if (this.storageChanges[hashed]) {
return callback(null, this.storageChanges[hashed])
}
this.storageResolver.storageSlot(hashed, this.context.tx, this.context.stepIndex, this.context.address, (error, storage) => {
if (error) {
callback(error)
} else {
callback(null, storage)
}
})
this.storageResolver.storageSlot(hashed, this.context.tx, this.context.stepIndex, this.context.address).then((storage) => {
callback(null, storage)
}).catch(callback)
}
/**
@ -76,15 +64,7 @@ class StorageViewer {
*/
async initialMappingsLocation (corrections) {
if (!this.initialMappingsLocationPromise) {
this.initialMappingsLocationPromise = new Promise((resolve, reject) => {
this.storageResolver.initialPreimagesMappings(this.context.tx, this.context.stepIndex, this.context.address, corrections, (error, initialMappingsLocation) => {
if (error) {
reject(error)
} else {
resolve(initialMappingsLocation)
}
})
})
this.initialMappingsLocationPromise = this.storageResolver.initialPreimagesMappings(this.context.tx, this.context.stepIndex, this.context.address, corrections)
}
return this.initialMappingsLocationPromise
}
@ -118,14 +98,9 @@ class StorageViewer {
if (this.mappingsLocationChanges) {
return callback(null, this.mappingsLocationChanges)
}
mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections, (error, mappings) => {
if (!error) {
this.mappingsLocationChanges = mappings
return callback(null, this.mappingsLocationChanges)
} else {
callback(error)
}
})
const mappings = mappingPreimages.decodeMappingsKeys(this.web3, storageChanges, corrections)
this.mappingsLocationChanges = mappings
return callback(null, this.mappingsLocationChanges)
}
}

@ -193,23 +193,27 @@ function testDebugging (debugManager) {
// stack
tape('traceManager.getStackAt 4', (t) => {
t.plan(1)
debugManager.traceManager.getStackAt(4, (error, callstack) => {
if (error) return t.end(error)
t.equal(JSON.stringify(callstack), JSON.stringify([ '0x0000000000000000000000000000000000000000000000000000000000000000' ]))
})
try {
const callstack = debugManager.traceManager.getStackAt(4)
t.equal(JSON.stringify(callstack), JSON.stringify(['0x0000000000000000000000000000000000000000000000000000000000000000']))
} catch (error) {
return t.end(error)
}
})
tape('traceManager.getStackAt 41', (t) => {
t.plan(1)
debugManager.traceManager.getStackAt(41, (error, callstack) => {
if (error) return t.end(error)
try {
const callstack = debugManager.traceManager.getStackAt(41)
t.equal(JSON.stringify(callstack), JSON.stringify([
'0x0000000000000000000000000000000000000000000000000000000000000080',
'0x0000000000000000000000000000000000000000000000000000000000000020',
'0x0000000000000000000000000000000000000000000000000000000000000080',
'0x00000000000000000000000000000000000000000000000000000000000000e0',
'0x00000000000000000000000000000000000000000000000000000000000000e0']))
})
} catch (error) {
return t.end(error)
}
})
// storage
@ -220,9 +224,11 @@ function testDebugging (debugManager) {
const address = debugManager.traceManager.getCurrentCalledAddressAt(38)
console.log(address)
var storageView = debugManager.storageViewAt(196, address)
storageView.storageRange((error, storage) => {
if (error) return t.end(error)
storageView.storageRange().then((storage) => {
t.equal(JSON.stringify(storage), JSON.stringify({ '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563': { key: '0x0000000000000000000000000000000000000000000000000000000000000000', value: '0x0000000000000000000000004b0897b0513fdc7c541b6d9d7e929c4e5364d2db' } }))
}).catch((error) => {
if (error) return t.end(error)
})
} catch (error) {
return t.end(error)

@ -7,8 +7,22 @@ var localDecoder = require('../../../src/solidity-decoder/localDecoder')
function decodeLocal (st, index, traceManager, callTree, verifier) {
try {
traceManager.waterfall([
traceManager.getStackAt,
traceManager.getMemoryAt],
function getStackAt (stepIndex, callback) {
try {
const result = traceManager.getStackAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
},
function getMemoryAt (stepIndex, callback) {
try {
const result = traceManager.getMemoryAt(stepIndex)
callback(null, result)
} catch (error) {
callback(error)
}
}],
index,
function (error, result) {
if (!error) {

@ -63,12 +63,9 @@ CodeManager.prototype.getCode = function (address, cb) {
if (codes) {
return cb(null, codes)
}
this.traceManager.getContractCreationCode(address, (error, hexCode) => {
if (!error) {
codes = this.codeResolver.cacheExecutingCode(address, hexCode)
cb(null, codes)
}
})
const hexCode = this.traceManager.getContractCreationCode(address)
codes = this.codeResolver.cacheExecutingCode(address, hexCode)
cb(null, codes)
}
/**
@ -82,16 +79,11 @@ CodeManager.prototype.getCode = function (address, cb) {
CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast) {
try {
const address = this.traceManager.getCurrentCalledAddressAt(stepIndex)
this.traceManager.getCurrentPC(stepIndex, (error, pc) => {
if (error) {
console.log(error)
return { error: 'Cannot retrieve current PC for ' + stepIndex }
}
return this.getFunctionFromPC(address, pc, sourceMap, ast)
})
const pc = this.traceManager.getCurrentPC(stepIndex)
return this.getFunctionFromPC(address, pc, sourceMap, ast)
} catch (error) {
console.log(error)
return { error: 'Cannot retrieve current address for ' + stepIndex }
return { error: 'Cannot retrieve current address or PC for ' + stepIndex }
}
}
@ -103,14 +95,14 @@ CodeManager.prototype.getFunctionFromStep = function (stepIndex, sourceMap, ast)
* @param {Function} callback - instruction index
*/
CodeManager.prototype.getInstructionIndex = function (address, step, callback) {
this.traceManager.getCurrentPC(step, (error, pc) => {
if (error) {
console.log(error)
return callback('Cannot retrieve current PC for ' + step, null)
}
try {
const pc = this.traceManager.getCurrentPC(step)
const itemIndex = this.codeResolver.getInstructionIndex(address, pc)
callback(null, itemIndex)
})
} catch (error) {
console.log(error)
return callback('Cannot retrieve current PC for ' + step, null)
}
}
/**

@ -40,19 +40,15 @@ SourceLocationTracker.prototype.getSourceLocationFromInstructionIndex = function
*/
SourceLocationTracker.prototype.getSourceLocationFromVMTraceIndex = function (address, vmtraceStepIndex, contracts) {
return new Promise((resolve, reject) => {
extractSourceMap(this, this.codeManager, address, contracts, (error, sourceMap) => {
if (!error) {
this.codeManager.getInstructionIndex(address, vmtraceStepIndex, (error, index) => {
if (error) {
reject(error)
} else {
resolve(this.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
} else {
reject(error)
}
})
extractSourceMap(this, this.codeManager, address, contracts).then((sourceMap) => {
this.codeManager.getInstructionIndex(address, vmtraceStepIndex, (error, index) => {
if (error) {
reject(error)
} else {
resolve(this.sourceMappingDecoder.atIndex(index, sourceMap))
}
})
}).catch(reject)
})
}
@ -78,21 +74,23 @@ function getSourceMap (address, code, contracts) {
return null
}
function extractSourceMap (self, codeManager, address, contracts, cb) {
if (self.sourceMapByAddress[address]) return cb(null, self.sourceMapByAddress[address])
function extractSourceMap (self, codeManager, address, contracts) {
return new Promise((resolve, reject) => {
if (self.sourceMapByAddress[address]) return resolve(self.sourceMapByAddress[address])
codeManager.getCode(address, (error, result) => {
if (!error) {
const sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap
cb(null, sourceMap)
codeManager.getCode(address, (error, result) => {
if (!error) {
const sourceMap = getSourceMap(address, result.bytecode, contracts)
if (sourceMap) {
if (!helper.isContractCreation(address)) self.sourceMapByAddress[address] = sourceMap
resolve(sourceMap)
} else {
reject('no sourcemap associated with the code ' + address)
}
} else {
cb('no sourcemap associated with the code ' + address)
reject(error)
}
} else {
cb(error)
}
})
})
}

@ -80,35 +80,36 @@ TraceManager.prototype.getLength = function (callback) {
}
}
TraceManager.prototype.accumulateStorageChanges = function (index, address, storageOrigin, callback) {
const storage = this.traceCache.accumulateStorageChanges(index, address, storageOrigin)
callback(null, storage)
TraceManager.prototype.accumulateStorageChanges = function (index, address, storageOrigin) {
return this.traceCache.accumulateStorageChanges(index, address, storageOrigin)
}
TraceManager.prototype.getAddresses = function (callback) {
callback(null, this.traceCache.addresses)
TraceManager.prototype.getAddresses = function () {
return this.traceCache.addresses
}
TraceManager.prototype.getCallDataAt = function (stepIndex, callback) {
TraceManager.prototype.getCallDataAt = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
throw new Error(check)
}
const callDataChange = util.findLowerBoundValue(stepIndex, this.traceCache.callDataChanges)
if (callDataChange === null) return callback('no calldata found', null)
callback(null, [this.traceCache.callsData[callDataChange]])
if (callDataChange === null) {
throw new Error('no calldata found')
}
return [this.traceCache.callsData[callDataChange]]
}
TraceManager.prototype.buildCallPath = function (stepIndex, callback) {
TraceManager.prototype.buildCallPath = async function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
throw new Error(check)
}
const callsPath = util.buildCallPath(stepIndex, this.traceCache.callsTree.call)
if (callsPath === null) return callback('no call path built', null)
callback(null, callsPath)
if (callsPath === null) throw new Error('no call path built')
return callsPath
}
TraceManager.prototype.getCallStackAt = function (stepIndex) {
@ -124,19 +125,14 @@ TraceManager.prototype.getCallStackAt = function (stepIndex) {
return call.callStack
}
TraceManager.prototype.getStackAt = function (stepIndex, callback) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
}
let stack
TraceManager.prototype.getStackAt = function (stepIndex) {
this.checkRequestedStep(stepIndex)
if (this.trace[stepIndex] && this.trace[stepIndex].stack) { // there's always a stack
stack = this.trace[stepIndex].stack.slice(0)
let stack = this.trace[stepIndex].stack.slice(0)
stack.reverse()
callback(null, stack)
return stack
} else {
callback('no stack found', null)
throw new Error('no stack found')
}
}
@ -167,54 +163,50 @@ TraceManager.prototype.getCurrentCalledAddressAt = function (stepIndex) {
}
}
TraceManager.prototype.getContractCreationCode = function (token, callback) {
if (this.traceCache.contractCreation[token]) {
callback(null, this.traceCache.contractCreation[token])
} else {
callback('no contract creation named ' + token, null)
TraceManager.prototype.getContractCreationCode = function (token) {
if (!this.traceCache.contractCreation[token]) {
throw new Error('no contract creation named ' + token)
}
return this.traceCache.contractCreation[token]
}
TraceManager.prototype.getMemoryAt = function (stepIndex, callback) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
}
TraceManager.prototype.getMemoryAt = function (stepIndex) {
this.checkRequestedStep(stepIndex)
const lastChanges = util.findLowerBoundValue(stepIndex, this.traceCache.memoryChanges)
if (lastChanges === null) return callback('no memory found', null)
callback(null, this.trace[lastChanges].memory)
if (lastChanges === null) {
throw new Error('no memory found')
}
return this.trace[lastChanges].memory
}
TraceManager.prototype.getCurrentPC = function (stepIndex, callback) {
TraceManager.prototype.getCurrentPC = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
throw new Error(check)
}
callback(null, this.trace[stepIndex].pc)
return this.trace[stepIndex].pc
}
TraceManager.prototype.getReturnValue = function (stepIndex, callback) {
TraceManager.prototype.getReturnValue = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
throw new Error(check)
}
if (!this.traceCache.returnValues[stepIndex]) {
callback('current step is not a return step')
} else {
callback(null, this.traceCache.returnValues[stepIndex])
throw new Error('current step is not a return step')
}
return this.traceCache.returnValues[stepIndex]
}
TraceManager.prototype.getCurrentStep = function (stepIndex, callback) {
TraceManager.prototype.getCurrentStep = function (stepIndex) {
try {
this.checkRequestedStep(stepIndex)
} catch (check) {
return callback(check, null)
throw new Error(check)
}
callback(null, this.traceCache.steps[stepIndex])
return this.traceCache.steps[stepIndex]
}
TraceManager.prototype.getMemExpand = function (stepIndex) {

@ -55,25 +55,19 @@ tape('TraceManager', function (t) {
})
t.test('TraceManager.accumulateStorageChanges', function (st) {
traceManager.accumulateStorageChanges(110, '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', {}, function (error, result) {
if (error) {
st.fail(error)
} else {
st.ok(result['0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'].value === '0x38')
st.end()
}
})
const result = traceManager.accumulateStorageChanges(110, '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', {})
st.ok(result['0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'].value === '0x38')
st.end()
})
t.test('TraceManager.getCallData', function (st) {
traceManager.getCallDataAt(0, function (error, result) {
if (error) {
st.fail(error)
} else {
st.ok(result[0] === '0x60fe47b10000000000000000000000000000000000000000000000000000000000000038')
st.end()
}
})
try {
const result = traceManager.getCallDataAt(0)
st.ok(result[0] === '0x60fe47b10000000000000000000000000000000000000000000000000000000000000038')
st.end()
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getCallStackAt', function (st) {
@ -96,24 +90,22 @@ tape('TraceManager', function (t) {
t.test('TraceManager.getStackAt', function (st) {
st.plan(3)
traceManager.getStackAt(0, function (error, result) {
try {
const result = traceManager.getStackAt(0)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result.length === 0)
}
})
st.ok(result.length === 0)
} catch (error) {
st.fail(error)
}
traceManager.getStackAt(28, function (error, result) {
try {
const result = traceManager.getStackAt(28)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result.length === 4)
st.ok(result[3] === '0x60fe47b1')
}
})
st.ok(result.length === 4)
st.ok(result[3] === '0x60fe47b1')
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getLastCallChangeSince', function (st) {
@ -175,61 +167,56 @@ tape('TraceManager', function (t) {
})
t.test('TraceManager.getContractCreationCode', function (st) { // contract code has been retrieved from the memory
traceManager.getContractCreationCode('(Contract Creation - Step 63)', function (error, result) {
try {
const result = traceManager.getContractCreationCode('(Contract Creation - Step 63)')
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result === '0x60606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055505b50600a80603b6000396000f360606040526008565b00000000000000000000000000000000000000000000000000000000000000002d')
st.end()
}
})
st.ok(result === '0x60606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055505b50600a80603b6000396000f360606040526008565b00000000000000000000000000000000000000000000000000000000000000002d')
st.end()
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getMemoryAt', function (st) {
st.plan(3)
traceManager.getMemoryAt(0, function (error, result) {
try {
const result = traceManager.getMemoryAt(0)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result.length === 0)
}
})
st.ok(result.length === 0)
} catch (error) {
st.fail(error)
}
traceManager.getMemoryAt(34, function (error, result) {
try {
const result = traceManager.getMemoryAt(34)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result.length === 3)
st.ok(result[2] === '0000000000000000000000000000000000000000000000000000000000000060')
}
})
st.ok(result.length === 3)
st.ok(result[2] === '0000000000000000000000000000000000000000000000000000000000000060')
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getCurrentPC', function (st) {
traceManager.getCurrentPC(13, function (error, result) {
try {
const result = traceManager.getCurrentPC(13)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result === '65')
st.end()
}
})
st.ok(result === '65')
st.end()
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getCurrentStep', function (st) {
traceManager.getCurrentStep(66, function (error, result) {
try {
const result = traceManager.getCurrentStep(66)
console.log(result)
if (error) {
st.fail(error)
} else {
st.ok(result === 2)
st.end()
}
})
st.ok(result === 2)
st.end()
} catch (error) {
st.fail(error)
}
})
t.test('TraceManager.getMemExpand', function (st) {
@ -287,25 +274,19 @@ tape('TraceManager', function (t) {
})
t.test('TraceManager.getAddresses', function (st) {
traceManager.getAddresses(function (error, result) {
if (error) {
st.fail(error)
} else {
st.ok(result[0] === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5')
st.ok(result[1] === '(Contract Creation - Step 63)')
st.end()
}
})
const result = traceManager.getAddresses()
st.ok(result[0] === '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5')
st.ok(result[1] === '(Contract Creation - Step 63)')
st.end()
})
t.test('TraceManager.getReturnValue', function (st) {
traceManager.getReturnValue(108, function (error, result) {
if (error) {
st.fail(error)
} else {
st.ok(result[0] === '0x60606040526008565b0000000000000000000000000000000000000000000000')
st.end()
}
})
try {
const result = traceManager.getReturnValue(108)
st.ok(result[0] === '0x60606040526008565b0000000000000000000000000000000000000000000000')
st.end()
} catch (error) {
st.fail(error)
}
})
})

Loading…
Cancel
Save