diff --git a/src/solidity/localDecoder.js b/src/solidity/localDecoder.js index 28f3a8de41..40dd531310 100644 --- a/src/solidity/localDecoder.js +++ b/src/solidity/localDecoder.js @@ -1,6 +1,6 @@ 'use strict' -function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storage, currentSourceLocation) { +function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, currentSourceLocation) { var scope = internalTreeCall.findScope(vmtraceIndex) if (!scope) { var error = { 'message': 'Can\'t display locals. reason: compilation result might not have been provided' } @@ -17,7 +17,7 @@ function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storage, name = '<' + anonymousIncr + '>' anonymousIncr++ } - locals[name] = variable.type.decodeFromStack(variable.stackDepth, stack, memory, storage) + locals[name] = variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver) } } return locals diff --git a/src/solidity/stateDecoder.js b/src/solidity/stateDecoder.js index cbc3bccc7f..3cd5995a83 100644 --- a/src/solidity/stateDecoder.js +++ b/src/solidity/stateDecoder.js @@ -5,14 +5,14 @@ var decodeInfo = require('./decodeInfo') * decode the contract state storage * * @param {Array} storage location - location of all state variables - * @param {Map} storageContent - storage + * @param {Object} storageResolver - resolve storage queries * @return {Map} - decoded state variable */ -async function decodeState (stateVars, storageContent) { +async function decodeState (stateVars, storageResolver) { var ret = {} for (var k in stateVars) { var stateVar = stateVars[k] - ret[stateVar.name] = await stateVar.type.decodeFromStorage(stateVar.storagelocation, storageContent) + ret[stateVar.name] = await stateVar.type.decodeFromStorage(stateVar.storagelocation, storageResolver) } return ret } diff --git a/src/solidity/types/ArrayType.js b/src/solidity/types/ArrayType.js index d98af3c98b..4c08b0d2c6 100644 --- a/src/solidity/types/ArrayType.js +++ b/src/solidity/types/ArrayType.js @@ -24,10 +24,10 @@ class ArrayType extends RefType { this.arraySize = arraySize } - async decodeFromStorage (location, storageContent) { + async decodeFromStorage (location, storageResolver) { var ret = [] var size = null - var slotValue = await util.extractHexValue(location, storageContent, this.storageBytes) + var slotValue = await util.extractHexValue(location, storageResolver, this.storageBytes) var currentLocation = { offset: 0, slot: location.slot @@ -40,7 +40,7 @@ class ArrayType extends RefType { } var k = util.toBN(0) for (; k.lt(size) && k.ltn(300); k.iaddn(1)) { - var item = await this.underlyingType.decodeFromStorage(currentLocation, storageContent) + var item = await this.underlyingType.decodeFromStorage(currentLocation, storageResolver) ret.push(item) if (this.underlyingType.storageSlots === 1 && location.offset + this.underlyingType.storageBytes <= 32) { currentLocation.offset += this.underlyingType.storageBytes diff --git a/src/solidity/types/DynamicByteArray.js b/src/solidity/types/DynamicByteArray.js index a1ec0ddd56..045695a877 100644 --- a/src/solidity/types/DynamicByteArray.js +++ b/src/solidity/types/DynamicByteArray.js @@ -9,19 +9,19 @@ class DynamicByteArray extends RefType { super(1, 32, 'bytes', location) } - async decodeFromStorage (location, storageContent) { - var value = await util.extractHexValue(location, storageContent, this.storageBytes) + async decodeFromStorage (location, storageResolver) { + var value = await util.extractHexValue(location, storageResolver, this.storageBytes) var bn = new BN(value, 16) if (bn.testn(0)) { var length = bn.div(new BN(2)) var dataPos = new BN(helper.sha3(location.slot).replace('0x', ''), 16) var ret = '' - var currentSlot = await util.readFromStorage(dataPos, storageContent) + var currentSlot = await util.readFromStorage(dataPos, storageResolver) while (length.gt(ret.length) && ret.length < 32000) { currentSlot = currentSlot.replace('0x', '') ret += currentSlot dataPos = dataPos.add(new BN(1)) - currentSlot = await util.readFromStorage(dataPos, storageContent) + currentSlot = await util.readFromStorage(dataPos, storageResolver) } return { value: '0x' + ret.replace(/(00)+$/, ''), diff --git a/src/solidity/types/Mapping.js b/src/solidity/types/Mapping.js index 2de91c8529..e61df47201 100644 --- a/src/solidity/types/Mapping.js +++ b/src/solidity/types/Mapping.js @@ -6,7 +6,7 @@ class Mapping extends RefType { super(1, 32, 'mapping', 'storage') } - async decodeFromStorage (location, storageContent) { + async decodeFromStorage (location, storageResolver) { return { value: '', length: '0x', diff --git a/src/solidity/types/RefType.js b/src/solidity/types/RefType.js index 443a713490..7865438737 100644 --- a/src/solidity/types/RefType.js +++ b/src/solidity/types/RefType.js @@ -16,23 +16,20 @@ class RefType { * @param {Int} stackDepth - position of the type in the stack * @param {Array} stack - stack * @param {String} - memory - * @param {Object} - storage + * @param {Object} - storageResolver * @return {Object} decoded value */ - async decodeFromStack (stackDepth, stack, memory, storage) { + async decodeFromStack (stackDepth, stack, memory, storageResolver) { if (stack.length - 1 < stackDepth) { return { error: '', type: this.typeName } } - if (!storage) { - storage = {} // TODO this is a fallback, should manage properly locals store in storage - } var offset = stack[stack.length - 1 - stackDepth] if (this.isInStorage()) { offset = util.toBN(offset) - return await this.decodeFromStorage({ offset: 0, slot: offset }, storage) + return await this.decodeFromStorage({ offset: 0, slot: offset }, storageResolver) } else if (this.isInMemory()) { offset = parseInt(offset, 16) return this.decodeFromMemoryInternal(offset, memory) diff --git a/src/solidity/types/StringType.js b/src/solidity/types/StringType.js index 4843d6cc36..8d4fd40fc7 100644 --- a/src/solidity/types/StringType.js +++ b/src/solidity/types/StringType.js @@ -7,8 +7,8 @@ class StringType extends DynamicBytes { this.typeName = 'string' } - async decodeFromStorage (location, storageContent) { - var decoded = await super.decodeFromStorage(location, storageContent) + async decodeFromStorage (location, storageResolver) { + var decoded = await super.decodeFromStorage(location, storageResolver) return format(decoded) } diff --git a/src/solidity/types/Struct.js b/src/solidity/types/Struct.js index 984bd36cf7..013c6e2baa 100644 --- a/src/solidity/types/Struct.js +++ b/src/solidity/types/Struct.js @@ -8,14 +8,14 @@ class Struct extends RefType { this.members = memberDetails.members } - async decodeFromStorage (location, storageContent) { + async decodeFromStorage (location, storageResolver) { var ret = {} this.members.map(async (item, i) => { var globalLocation = { offset: location.offset + item.storagelocation.offset, slot: util.add(location.slot, item.storagelocation.slot) } - ret[item.name] = await item.type.decodeFromStorage(globalLocation, storageContent) + ret[item.name] = await item.type.decodeFromStorage(globalLocation, storageResolver) }) return { value: ret, diff --git a/src/solidity/types/ValueType.js b/src/solidity/types/ValueType.js index 46fbec2b01..fc7efd4fb1 100644 --- a/src/solidity/types/ValueType.js +++ b/src/solidity/types/ValueType.js @@ -13,11 +13,11 @@ class ValueType { * decode the type with the @arg location from the storage * * @param {Object} location - containing offset and slot - * @param {Object} storageContent - storageContent (storage) + * @param {Object} storageResolver - resolve storage queries * @return {Object} - decoded value */ - async decodeFromStorage (location, storageContent) { - var value = await util.extractHexValue(location, storageContent, this.storageBytes) + async decodeFromStorage (location, storageResolver) { + var value = await util.extractHexValue(location, storageResolver, this.storageBytes) return { value: this.decodeValue(value), type: this.typeName diff --git a/src/solidity/types/util.js b/src/solidity/types/util.js index bf08265f3c..6c6f1761a9 100644 --- a/src/solidity/types/util.js +++ b/src/solidity/types/util.js @@ -21,24 +21,26 @@ function decodeIntFromHex (value, byteLength, signed) { return bigNumber.toString(10) } -async function readFromStorage (slot, storageContent) { - var ret +function readFromStorage (slot, storageResolver) { var hexSlot = ethutil.bufferToHex(slot) return new Promise((resolve, reject) => { - if (storageContent[hexSlot] !== undefined) { - ret = storageContent[hexSlot].replace(/^0x/, '') - } else { - hexSlot = ethutil.bufferToHex(ethutil.setLengthLeft(slot, 32)) - if (storageContent[hexSlot] !== undefined) { - ret = storageContent[hexSlot].replace(/^0x/, '') + storageResolver.storageSlot(hexSlot, (error, slot) => { + if (error) { + return reject(error) } else { - ret = '000000000000000000000000000000000000000000000000000000000000000' + if (!slot) { + slot = { + key: slot, + value: '' + } + } + slot.value = slot.value.replace('0x', '') + if (slot.value.length < 64) { + slot.value = (new Array(64 - slot.value.length + 1).join('0')) + slot.value + } + return resolve(slot.value) } - } - if (ret.length < 64) { - ret = (new Array(64 - ret.length + 1).join('0')) + ret - } - return resolve(ret) + }) }) } @@ -58,11 +60,11 @@ function extractHexByteSlice (slotValue, byteLength, offsetFromLSB) { * @returns a hex encoded storage content at the given @arg location. it does not have Ox prefix but always has the full length. * * @param {Object} location - object containing the slot and offset of the data to extract. - * @param {Object} storageContent - full storage mapping. + * @param {Object} storageResolver - storage resolver * @param {Int} byteLength - Length of the byte slice to extract */ -async function extractHexValue (location, storageContent, byteLength) { - var slotvalue = await readFromStorage(location.slot, storageContent) +async function extractHexValue (location, storageResolver, byteLength) { + var slotvalue = await readFromStorage(location.slot, storageResolver) return extractHexByteSlice(slotvalue, byteLength, location.offset) } diff --git a/src/ui/SolidityLocals.js b/src/ui/SolidityLocals.js index 4c47e8a0a6..6e93a3e045 100644 --- a/src/ui/SolidityLocals.js +++ b/src/ui/SolidityLocals.js @@ -6,9 +6,10 @@ var yo = require('yo-yo') class SolidityLocals { - constructor (_parent, _traceManager, internalTreeCall) { + constructor (_parent, _traceManager, _internalTreeCall, _storageResolver) { this.parent = _parent - this.internalTreeCall = internalTreeCall + this.internalTreeCall = _internalTreeCall + this.storageResolver = _storageResolver this.traceManager = _traceManager this.basicPanel = new DropdownPanel('Solidity Locals', { json: true, @@ -40,12 +41,8 @@ class SolidityLocals { var stack = result[0].value var memory = result[1].value try { - this.traceManager.getStorageAt(this.parent.currentStepIndex, this.parent.tx, (error, storage) => { - if (!error) { - var locals = localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, storage, sourceLocation) - this.basicPanel.update(locals) - } - }) + var locals = localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, this.storageResolver, sourceLocation) + this.basicPanel.update(locals) } catch (e) { warningDiv.innerHTML = e.message } diff --git a/src/ui/SolidityState.js b/src/ui/SolidityState.js index 1f6b0f8ecf..8b95a97547 100644 --- a/src/ui/SolidityState.js +++ b/src/ui/SolidityState.js @@ -4,7 +4,8 @@ var stateDecoder = require('../solidity/stateDecoder') var solidityTypeFormatter = require('./SolidityTypeFormatter') var yo = require('yo-yo') -function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) { +function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy, _storageResolver) { + this.storageResolver = _storageResolver this.parent = _parent this.traceManager = _traceManager this.codeManager = _codeManager @@ -42,7 +43,7 @@ SolidityState.prototype.init = function () { return } - self.traceManager.getStorageAt(index, this.parent.tx, function (error, storage) { + self.traceManager.getCurrentCalledAddressAt(self.parent.currentStepIndex, (error, result) => { if (error) { self.basicPanel.update({}) console.log(error) @@ -52,7 +53,7 @@ SolidityState.prototype.init = function () { self.basicPanel.update({}) console.log(error) } else { - stateDecoder.decodeState(stateVars, storage).then((result) => { + stateDecoder.decodeState(stateVars, self.storageResolver).then((result) => { if (!result.error) { self.basicPanel.update(result) } diff --git a/src/ui/VmDebugger.js b/src/ui/VmDebugger.js index c43abcede8..10d755d7ce 100644 --- a/src/ui/VmDebugger.js +++ b/src/ui/VmDebugger.js @@ -10,18 +10,20 @@ var StepDetail = require('./StepDetail') var DropdownPanel = require('./DropdownPanel') var SolidityState = require('./SolidityState') var SolidityLocals = require('./SolidityLocals') +var StorageResolver = require('../storage/storageResolver.js') var yo = require('yo-yo') function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _callTree) { + var storageResolver = new StorageResolver(_parent, _traceManager) this.asmCode = new CodeListView(_parent, _codeManager) this.stackPanel = new StackPanel(_parent, _traceManager) - this.storagePanel = new StoragePanel(_parent, _traceManager) + this.storagePanel = new StoragePanel(_parent, _traceManager, storageResolver) this.memoryPanel = new MemoryPanel(_parent, _traceManager) this.calldataPanel = new CalldataPanel(_parent, _traceManager) this.callstackPanel = new CallstackPanel(_parent, _traceManager) this.stepDetail = new StepDetail(_parent, _traceManager) - this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy) - this.solidityLocals = new SolidityLocals(_parent, _traceManager, _callTree) + this.solidityState = new SolidityState(_parent, _traceManager, _codeManager, _solidityProxy, storageResolver) + this.solidityLocals = new SolidityLocals(_parent, _traceManager, _callTree, storageResolver) /* Return values - */ this.returnValuesPanel = new DropdownPanel('Return Value', {json: true}) @@ -38,7 +40,7 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _call }) /* Return values - */ - this.fullStoragesChangesPanel = new FullStoragesChangesPanel(_parent, _traceManager) + this.fullStoragesChangesPanel = new FullStoragesChangesPanel(_parent, _traceManager, storageResolver) this.view var self = this