Commit 21218bf3 authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #214 from ethereum/storageResolver

Storage resolver
parents 734bd145 31dd3f8e
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",
"babel-preset-es2015": "^6.24.0", "babel-preset-es2015": "^6.24.0",
"babel-plugin-transform-object-assign": "^6.22.0",
"babelify": "^7.3.0", "babelify": "^7.3.0",
"browserify": "^13.0.1", "browserify": "^13.0.1",
"ethereum-common": "0.0.18", "ethereum-common": "0.0.18",
...@@ -92,7 +93,7 @@ ...@@ -92,7 +93,7 @@
"noRuntime": true, "noRuntime": true,
"wrapAwait": true "wrapAwait": true
} }
}] }], "transform-object-assign"
] ]
}], }],
["yo-yoify"], ["yo-yoify"],
......
'use strict' 'use strict'
var ethutil = require('ethereumjs-util')
module.exports = { module.exports = {
/* /*
ints: IntArray ints: IntArray
...@@ -115,7 +117,19 @@ module.exports = { ...@@ -115,7 +117,19 @@ module.exports = {
*/ */
findCall: findCall, findCall: findCall,
buildCallPath: buildCallPath buildCallPath: buildCallPath,
/**
* sha3 the given @arg value (left pad to 32 bytes)
*
* @param {String} value - value to sha3
* @return {Object} - return sha3ied value
*/
sha3_256: function (value) {
var ret = ethutil.bufferToHex(ethutil.setLengthLeft(value, 32))
ret = ethutil.sha3(ret)
return ethutil.bufferToHex(ret)
}
} }
/** /**
......
'use strict' 'use strict'
function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storage, currentSourceLocation) { async function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storageResolver, currentSourceLocation) {
var scope = internalTreeCall.findScope(vmtraceIndex) var scope = internalTreeCall.findScope(vmtraceIndex)
if (!scope) { if (!scope) {
var error = { 'message': 'Can\'t display locals. reason: compilation result might not have been provided' } var error = { 'message': 'Can\'t display locals. reason: compilation result might not have been provided' }
...@@ -10,14 +10,19 @@ function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storage, ...@@ -10,14 +10,19 @@ function solidityLocals (vmtraceIndex, internalTreeCall, stack, memory, storage,
memory = formatMemory(memory) memory = formatMemory(memory)
var anonymousIncr = 1 var anonymousIncr = 1
for (var local in scope.locals) { for (var local in scope.locals) {
let variable = scope.locals[local] var variable = scope.locals[local]
if (variable.stackDepth < stack.length && variable.sourceLocation.start <= currentSourceLocation.start) { if (variable.stackDepth < stack.length && variable.sourceLocation.start <= currentSourceLocation.start) {
var name = variable.name var name = variable.name
if (name === '') { if (name === '') {
name = '<' + anonymousIncr + '>' name = '<' + anonymousIncr + '>'
anonymousIncr++ anonymousIncr++
} }
locals[name] = variable.type.decodeFromStack(variable.stackDepth, stack, memory, storage) try {
locals[name] = await variable.type.decodeFromStack(variable.stackDepth, stack, memory, storageResolver)
} catch (e) {
console.log(e)
locals[name] = '<decoding failed - ' + e.message + '>'
}
} }
} }
return locals return locals
......
...@@ -5,14 +5,19 @@ var decodeInfo = require('./decodeInfo') ...@@ -5,14 +5,19 @@ var decodeInfo = require('./decodeInfo')
* decode the contract state storage * decode the contract state storage
* *
* @param {Array} storage location - location of all state variables * @param {Array} storage location - location of all state variables
* @param {Map} storageContent - storage * @param {Object} storageResolver - resolve storage queries
* @return {Map} - decoded state variable * @return {Map} - decoded state variable
*/ */
function decodeState (stateVars, storageContent) { async function decodeState (stateVars, storageResolver) {
var ret = {} var ret = {}
for (var k in stateVars) { for (var k in stateVars) {
var stateVar = stateVars[k] var stateVar = stateVars[k]
ret[stateVar.name] = stateVar.type.decodeFromStorage(stateVar.storagelocation, storageContent) try {
ret[stateVar.name] = await stateVar.type.decodeFromStorage(stateVar.storagelocation, storageResolver)
} catch (e) {
console.log(e)
ret[stateVar.name] = '<decoding failed - ' + e.message + '>'
}
} }
return ret return ret
} }
...@@ -40,14 +45,18 @@ function extractStateVariables (contractName, sourcesList) { ...@@ -40,14 +45,18 @@ function extractStateVariables (contractName, sourcesList) {
/** /**
* return the state of the given @a contractName as a json object * return the state of the given @a contractName as a json object
* *
* @param {Map} storageContent - contract storage * @param {Object} storageResolver - resolve storage queries
* @param {astList} astList - AST nodes of all the sources * @param {astList} astList - AST nodes of all the sources
* @param {String} contractName - contract for which state var should be resolved * @param {String} contractName - contract for which state var should be resolved
* @return {Map} - return the state of the contract * @return {Map} - return the state of the contract
*/ */
function solidityState (storageContent, astList, contractName) { async function solidityState (storageResolver, astList, contractName) {
var stateVars = extractStateVariables(contractName, astList) var stateVars = extractStateVariables(contractName, astList)
return decodeState(stateVars, storageContent) try {
return await decodeState(stateVars, storageResolver)
} catch (e) {
return '<decoding failed - ' + e.message + '>'
}
} }
module.exports = { module.exports = {
......
'use strict' 'use strict'
var util = require('./util') var util = require('./util')
var helper = require('../../helpers/util')
var BN = require('ethereumjs-util').BN var BN = require('ethereumjs-util').BN
var RefType = require('./RefType') var RefType = require('./RefType')
...@@ -23,23 +24,39 @@ class ArrayType extends RefType { ...@@ -23,23 +24,39 @@ class ArrayType extends RefType {
this.arraySize = arraySize this.arraySize = arraySize
} }
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
var ret = [] var ret = []
var size = null var size = null
var slotValue = util.extractHexValue(location, storageContent, this.storageBytes) var slotValue
try {
slotValue = await util.extractHexValue(location, storageResolver, this.storageBytes)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
var currentLocation = { var currentLocation = {
offset: 0, offset: 0,
slot: location.slot slot: location.slot
} }
if (this.arraySize === 'dynamic') { if (this.arraySize === 'dynamic') {
size = util.toBN('0x' + slotValue) size = util.toBN('0x' + slotValue)
currentLocation.slot = util.sha3(location.slot) currentLocation.slot = helper.sha3_256(location.slot)
} else { } else {
size = new BN(this.arraySize) size = new BN(this.arraySize)
} }
var k = util.toBN(0) var k = util.toBN(0)
for (; k.lt(size) && k.ltn(300); k.iaddn(1)) { for (; k.lt(size) && k.ltn(300); k.iaddn(1)) {
ret.push(this.underlyingType.decodeFromStorage(currentLocation, storageContent)) try {
ret.push(await this.underlyingType.decodeFromStorage(currentLocation, storageResolver))
} catch (e) {
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
if (this.underlyingType.storageSlots === 1 && location.offset + this.underlyingType.storageBytes <= 32) { if (this.underlyingType.storageSlots === 1 && location.offset + this.underlyingType.storageBytes <= 32) {
currentLocation.offset += this.underlyingType.storageBytes currentLocation.offset += this.underlyingType.storageBytes
if (currentLocation.offset + this.underlyingType.storageBytes > 32) { if (currentLocation.offset + this.underlyingType.storageBytes > 32) {
......
'use strict' 'use strict'
var util = require('./util') var util = require('./util')
var helper = require('../../helpers/util')
var BN = require('ethereumjs-util').BN var BN = require('ethereumjs-util').BN
var RefType = require('./RefType') var RefType = require('./RefType')
...@@ -8,19 +9,45 @@ class DynamicByteArray extends RefType { ...@@ -8,19 +9,45 @@ class DynamicByteArray extends RefType {
super(1, 32, 'bytes', location) super(1, 32, 'bytes', location)
} }
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
var value = util.extractHexValue(location, storageContent, this.storageBytes) var value = '0x0'
try {
value = await util.extractHexValue(location, storageResolver, this.storageBytes)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
var bn = new BN(value, 16) var bn = new BN(value, 16)
if (bn.testn(0)) { if (bn.testn(0)) {
var length = bn.div(new BN(2)) var length = bn.div(new BN(2))
var dataPos = new BN(util.sha3(location.slot).replace('0x', ''), 16) var dataPos = new BN(helper.sha3_256(location.slot).replace('0x', ''), 16)
var ret = '' var ret = ''
var currentSlot = util.readFromStorage(dataPos, storageContent) var currentSlot = '0x'
try {
currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
while (length.gt(ret.length) && ret.length < 32000) { while (length.gt(ret.length) && ret.length < 32000) {
currentSlot = currentSlot.replace('0x', '') currentSlot = currentSlot.replace('0x', '')
ret += currentSlot ret += currentSlot
dataPos = dataPos.add(new BN(1)) dataPos = dataPos.add(new BN(1))
currentSlot = util.readFromStorage(dataPos, storageContent) try {
currentSlot = await util.readFromStorage(dataPos, storageResolver)
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
} }
return { return {
value: '0x' + ret.replace(/(00)+$/, ''), value: '0x' + ret.replace(/(00)+$/, ''),
......
...@@ -6,7 +6,7 @@ class Mapping extends RefType { ...@@ -6,7 +6,7 @@ class Mapping extends RefType {
super(1, 32, 'mapping', 'storage') super(1, 32, 'mapping', 'storage')
} }
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
return { return {
value: '<not implemented>', value: '<not implemented>',
length: '0x', length: '0x',
......
...@@ -16,23 +16,28 @@ class RefType { ...@@ -16,23 +16,28 @@ class RefType {
* @param {Int} stackDepth - position of the type in the stack * @param {Int} stackDepth - position of the type in the stack
* @param {Array} stack - stack * @param {Array} stack - stack
* @param {String} - memory * @param {String} - memory
* @param {Object} - storage * @param {Object} - storageResolver
* @return {Object} decoded value * @return {Object} decoded value
*/ */
decodeFromStack (stackDepth, stack, memory, storage) { async decodeFromStack (stackDepth, stack, memory, storageResolver) {
if (stack.length - 1 < stackDepth) { if (stack.length - 1 < stackDepth) {
return { return {
error: '<decoding failed - stack underflow ' + stackDepth + '>', error: '<decoding failed - stack underflow ' + stackDepth + '>',
type: this.typeName 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] var offset = stack[stack.length - 1 - stackDepth]
if (this.isInStorage()) { if (this.isInStorage()) {
offset = util.toBN(offset) offset = util.toBN(offset)
return this.decodeFromStorage({ offset: 0, slot: offset }, storage) try {
return await this.decodeFromStorage({ offset: 0, slot: offset }, storageResolver)
} catch (e) {
console.log(e)
return {
error: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
}
} else if (this.isInMemory()) { } else if (this.isInMemory()) {
offset = parseInt(offset, 16) offset = parseInt(offset, 16)
return this.decodeFromMemoryInternal(offset, memory) return this.decodeFromMemoryInternal(offset, memory)
......
...@@ -7,13 +7,24 @@ class StringType extends DynamicBytes { ...@@ -7,13 +7,24 @@ class StringType extends DynamicBytes {
this.typeName = 'string' this.typeName = 'string'
} }
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
var decoded = super.decodeFromStorage(location, storageContent) var decoded = '0x'
try {
decoded = await super.decodeFromStorage(location, storageResolver)
} catch (e) {
console.log(e)
return '<decoding failed - ' + e.message + '>'
}
return format(decoded) return format(decoded)
} }
decodeFromStack (stackDepth, stack, memory) { async decodeFromStack (stackDepth, stack, memory) {
return super.decodeFromStack(stackDepth, stack, memory) try {
return await super.decodeFromStack(stackDepth, stack, memory)
} catch (e) {
console.log(e)
return '<decoding failed - ' + e.message + '>'
}
} }
decodeFromMemoryInternal (offset, memory) { decodeFromMemoryInternal (offset, memory) {
......
...@@ -8,15 +8,21 @@ class Struct extends RefType { ...@@ -8,15 +8,21 @@ class Struct extends RefType {
this.members = memberDetails.members this.members = memberDetails.members
} }
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
var ret = {} var ret = {}
this.members.map(function (item, i) { for (var k in this.members) {
var item = this.members[k]
var globalLocation = { var globalLocation = {
offset: location.offset + item.storagelocation.offset, offset: location.offset + item.storagelocation.offset,
slot: util.add(location.slot, item.storagelocation.slot) slot: util.add(location.slot, item.storagelocation.slot)
} }
ret[item.name] = item.type.decodeFromStorage(globalLocation, storageContent) try {
}) ret[item.name] = await item.type.decodeFromStorage(globalLocation, storageResolver)
} catch (e) {
console.log(e)
ret[item.name] = '<decoding failed - ' + e.message + '>'
}
}
return { return {
value: ret, value: ret,
type: this.typeName type: this.typeName
......
...@@ -13,14 +13,22 @@ class ValueType { ...@@ -13,14 +13,22 @@ class ValueType {
* decode the type with the @arg location from the storage * decode the type with the @arg location from the storage
* *
* @param {Object} location - containing offset and slot * @param {Object} location - containing offset and slot
* @param {Object} storageContent - storageContent (storage) * @param {Object} storageResolver - resolve storage queries
* @return {Object} - decoded value * @return {Object} - decoded value
*/ */
decodeFromStorage (location, storageContent) { async decodeFromStorage (location, storageResolver) {
var value = util.extractHexValue(location, storageContent, this.storageBytes) try {
return { var value = await util.extractHexValue(location, storageResolver, this.storageBytes)
value: this.decodeValue(value), return {
type: this.typeName value: this.decodeValue(value),
type: this.typeName
}
} catch (e) {
console.log(e)
return {
value: '<decoding failed - ' + e.message + '>',
type: this.typeName
}
} }
} }
...@@ -32,7 +40,7 @@ class ValueType { ...@@ -32,7 +40,7 @@ class ValueType {
* @param {String} - memory * @param {String} - memory
* @return {Object} - decoded value * @return {Object} - decoded value
*/ */
decodeFromStack (stackDepth, stack, memory) { async decodeFromStack (stackDepth, stack, memory) {
var value var value
if (stackDepth >= stack.length) { if (stackDepth >= stack.length) {
value = this.decodeValue('') value = this.decodeValue('')
......
...@@ -4,23 +4,15 @@ var BN = require('ethereumjs-util').BN ...@@ -4,23 +4,15 @@ var BN = require('ethereumjs-util').BN
module.exports = { module.exports = {
readFromStorage: readFromStorage, readFromStorage: readFromStorage,
decodeInt: decodeInt,
decodeIntFromHex: decodeIntFromHex, decodeIntFromHex: decodeIntFromHex,
extractHexValue: extractHexValue, extractHexValue: extractHexValue,
extractHexByteSlice: extractHexByteSlice, extractHexByteSlice: extractHexByteSlice,
sha3: sha3,
toBN: toBN, toBN: toBN,
add: add, add: add,
extractLocation: extractLocation, extractLocation: extractLocation,
removeLocation: removeLocation removeLocation: removeLocation
} }
function decodeInt (location, storageContent, byteLength, signed) {
var slotvalue = readFromStorage(location.slot, storageContent)
var value = extractHexByteSlice(slotvalue, byteLength, location.offset)
return decodeIntFromHex(value, byteLength, signed)
}
function decodeIntFromHex (value, byteLength, signed) { function decodeIntFromHex (value, byteLength, signed) {
var bigNumber = new BN(value, 16) var bigNumber = new BN(value, 16)
if (signed) { if (signed) {
...@@ -29,23 +21,23 @@ function decodeIntFromHex (value, byteLength, signed) { ...@@ -29,23 +21,23 @@ function decodeIntFromHex (value, byteLength, signed) {
return bigNumber.toString(10) return bigNumber.toString(10)
} }
function readFromStorage (slot, storageContent) { function readFromStorage (slot, storageResolver) {
var ret var hexSlot = '0x' + normalizeHex(ethutil.bufferToHex(slot))
var hexSlot = ethutil.bufferToHex(slot) return new Promise((resolve, reject) => {
if (storageContent[hexSlot] !== undefined) { storageResolver.storageSlot(hexSlot, (error, slot) => {
ret = storageContent[hexSlot].replace(/^0x/, '') if (error) {
} else { return reject(error)
hexSlot = ethutil.bufferToHex(ethutil.setLengthLeft(slot, 32)) } else {
if (storageContent[hexSlot] !== undefined) { if (!slot) {
ret = storageContent[hexSlot].replace(/^0x/, '') slot = {
} else { key: slot,
ret = '000000000000000000000000000000000000000000000000000000000000000' value: ''
} }
} }
if (ret.length < 64) { return resolve(normalizeHex(slot.value))
ret = (new Array(64 - ret.length + 1).join('0')) + ret }
} })
return ret })
} }
/** /**
...@@ -64,20 +56,20 @@ function extractHexByteSlice (slotValue, byteLength, offsetFromLSB) { ...@@ -64,20 +56,20 @@ 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. * @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} 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 * @param {Int} byteLength - Length of the byte slice to extract
*/ */
function extractHexValue (location, storageContent, byteLength) { async function extractHexValue (location, storageResolver, byteLength) {
var slotvalue = readFromStorage(location.slot, storageContent) var slotvalue
try {
slotvalue = await readFromStorage(location.slot, storageResolver)
} catch (e) {
console.log(e)
return '0x'
}
return extractHexByteSlice(slotvalue, byteLength, location.offset) return extractHexByteSlice(slotvalue, byteLength, location.offset)
} }
function sha3 (slot) {
var remoteSlot = ethutil.bufferToHex(ethutil.setLengthLeft(slot, 32))
var key = ethutil.sha3(remoteSlot)
return ethutil.bufferToHex(key)
}
function toBN (value) { function toBN (value) {
if (value instanceof BN) { if (value instanceof BN) {
return value return value
...@@ -106,3 +98,11 @@ function extractLocation (type) { ...@@ -106,3 +98,11 @@ function extractLocation (type) {
return null return null
} }
} }
function normalizeHex (hex) {
hex = hex.replace('0x', '')
if (hex.length < 64) {
return (new Array(64 - hex.length + 1).join('0')) + hex
}
return hex
}
'use strict'
var traceHelper = require('../helpers/traceHelper')
var util = require('../helpers/global')
class StorageResolver {
constructor () {
this.storageByAddress = {}
this.maxSize = 100
}
/**
* returns the storage for the given context (address and vm trace index)
* returns the range 0x0 => this.maxSize
*
* @param {Object} - tx - transaction
* @param {Int} - stepIndex - Index of the stop in the vm trace
* @param {String} - address - lookup address
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value}
*/
storageRange (tx, stepIndex, address, callback) {
storageRangeInternal(this, zeroSlot, tx, stepIndex, address, callback)
}
/**
* return a slot value for the given context (address and vm trace index)
*
* @param {String} - slot - slot key
* @param {Object} - tx - transaction
* @param {Int} - stepIndex - Index of the stop in the vm trace
* @param {String} - address - lookup address
* @param {Function} - callback - {key, hashedKey, value} -
*/
storageSlot (slot, tx, stepIndex, address, callback) {
storageRangeInternal(this, slot, tx, stepIndex, address, function (error, storage) {
if (error) {
callback(error)
} else {
callback(null, storage[slot] !== undefined ? storage[slot] : null)
}
})
}
/**
* return True if the storage at @arg address is complete
*
* @param {String} address - contract address
* @return {Bool} - return True if the storage at @arg address is complete
*/
isComplete (address) {
return this.storageByAddress[address] && this.storageByAddress[address].complete
}
}
/**
* retrieve the storage and ensure at least @arg slot is cached.
* - If @arg slot is already cached, the storage will be returned from the cache
* 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.
*/
function storageRangeInternal (self, slotKey, tx, stepIndex, address, callback) {
var cached = 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)
}
storageRangeWeb3Call(tx, address, slotKey, self.maxSize, (error, storage, complete) => {
if (error) {
return callback(error)
}
if (!storage[slotKey]) {
storage[slotKey] = {
key: slotKey,
value: zeroSlot
}
}
toCache(self, address, storage)
if (slotKey === zeroSlot && Object.keys(storage).length < self.maxSize) { // only working if keys are sorted !!
self.storageByAddress[address].complete = true
}
callback(null, storage)
})
}
var zeroSlot = '0x0000000000000000000000000000000000000000000000000000000000000000'
/**
* retrieve the storage from the cache. if @arg slot is defined, return only the desired slot, if not return the entire known storage
*
* @param {String} address - contract address
* @return {String} - either the entire known storage or a single value
*/
function fromCache (self, address) {
if (!self.storageByAddress[address]) {
return null
}
return self.storageByAddress[address]
}
/**
* store the result of `storageRangeAtInternal`
*
* @param {String} address - contract address
* @param {Object} storage - result of `storageRangeAtInternal`, contains {key, hashedKey, value}
*/
function toCache (self, address, storage) {
if (!self.storageByAddress[address]) {
self.storageByAddress[address] = {}
}
self.storageByAddress[address].storage = Object.assign(self.storageByAddress[address].storage || {}, storage)
}
function storageRangeWeb3Call (tx, address, start, maxSize, callback) {
if (traceHelper.isContractCreation(address)) {
callback(null, {}, true)
} else {
util.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.complete)
} else {
callback('the storage has not been provided')
}
})
}
}
module.exports = StorageResolver
'use strict'
var helper = require('../helpers/util')
class StorageViewer {
constructor (_context, _storageResolver, _traceManager) {
this.context = _context
this.storageResolver = _storageResolver
_traceManager.accumulateStorageChanges(this.context.stepIndex, this.context.address, {}, (error, storageChanges) => {
if (!error) {
this.storageChanges = storageChanges
} else {
console.log(error)
}
})
}
/**
* return the storage for the current context (address and vm trace index)
* by default now returns the range 0 => 1000
*
* @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))
}
})
}
/**
* return a slot value for the current context (address and vm trace index)
* @param {String} - slot - slot key (not hashed key!)
* @param {Function} - callback - {key, hashedKey, value} -
*/
storageSlot (slot, callback) {
var hashed = helper.sha3_256(slot)
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[hashed] !== undefined ? storage[hashed] : null)
}
})
}
/**
* return True if the storage at @arg address is complete
*
* @param {String} address - contract address
* @return {Bool} - return True if the storage at @arg address is complete
*/
isComplete (address) {
return this.storageResolver.isComplete(address)
}
}
module.exports = StorageViewer
'use strict' 'use strict'
var helper = require('../helpers/util')
function TraceCache () { function TraceCache () {
this.init() this.init()
} }
...@@ -84,23 +86,29 @@ TraceCache.prototype.pushStoreChanges = function (index, address, key, value) { ...@@ -84,23 +86,29 @@ TraceCache.prototype.pushStoreChanges = function (index, address, key, value) {
this.sstore[index] = { this.sstore[index] = {
'address': address, 'address': address,
'key': key, 'key': key,
'value': value 'value': value,
'hashedKey': helper.sha3_256(key)
} }
this.storageChanges.push(index) this.storageChanges.push(index)
} }
TraceCache.prototype.rebuildStorage = function (address, storage, index) { TraceCache.prototype.accumulateStorageChanges = function (index, address, storage) {
var ret = Object.assign({}, storage)
for (var k in this.storageChanges) { for (var k in this.storageChanges) {
var changesIndex = this.storageChanges[k] var changesIndex = this.storageChanges[k]
if (changesIndex > index) { if (changesIndex > index) {
return storage return ret
} }
var sstore = this.sstore[changesIndex] var sstore = this.sstore[changesIndex]
if (sstore.address === address && sstore.key) { if (sstore.address === address && sstore.key) {
storage[sstore.key] = sstore.value ret[sstore.hashedKey] = {
hashedKey: sstore.hashedKey,
key: sstore.key,
value: sstore.value
}
} }
} }
return storage return ret
} }
module.exports = TraceCache module.exports = TraceCache
...@@ -74,30 +74,9 @@ TraceManager.prototype.getLength = function (callback) { ...@@ -74,30 +74,9 @@ TraceManager.prototype.getLength = function (callback) {
} }
} }
TraceManager.prototype.getStorageAt = function (stepIndex, tx, callback, address) { TraceManager.prototype.accumulateStorageChanges = function (index, address, storageOrigin, callback) {
var check = this.checkRequestedStep(stepIndex) var storage = this.traceCache.accumulateStorageChanges(index, address, storageOrigin)
if (check) { callback(null, storage)
return callback(check, null)
}
if (!address) {
var stoChange = util.findLowerBoundValue(stepIndex, this.traceCache.storageChanges)
if (stoChange === null) return callback('no storage found', null)
address = this.traceCache.sstore[stoChange].address
}
var self = this
if (this.traceRetriever.debugStorageAtAvailable()) {
this.traceRetriever.getStorage(tx, address, function (error, result) {
if (error) {
// TODO throws proper error when debug_storageRangeAt will be available
console.log(error)
result = {}
}
var storage = self.traceCache.rebuildStorage(address, result, stepIndex)
callback(null, storage)
})
} else {
callback(null, this.trace[stoChange].storage)
}
} }
TraceManager.prototype.getAddresses = function (callback) { TraceManager.prototype.getAddresses = function (callback) {
......
'use strict' 'use strict'
var traceHelper = require('../helpers/traceHelper')
var util = require('../helpers/global') var util = require('../helpers/global')
function TraceRetriever () { function TraceRetriever () {
...@@ -17,32 +16,4 @@ TraceRetriever.prototype.getTrace = function (txHash, callback) { ...@@ -17,32 +16,4 @@ TraceRetriever.prototype.getTrace = function (txHash, callback) {
}) })
} }
TraceRetriever.prototype.getStorage = function (tx, address, callback) {
if (traceHelper.isContractCreation(address)) {
callback(null, {})
} else {
if (util.web3.debug.storageRangeAt) {
var end = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
var maxSize = 10000
// The VM gives only a tx hash
// TODO: get rid of that and use the range parameters
util.web3.debug.storageRangeAt(tx.blockHash, tx.transactionIndex === undefined ? tx.hash : tx.transactionIndex, address, '0x0', '0x' + end, maxSize, function (error, result) {
if (error) {
callback(error)
} else if (result.storage) {
callback(null, result.storage)
} else {
callback('storage has not been provided')
}
})
} else {
callback('no storageRangeAt endpoint found')
}
}
}
TraceRetriever.prototype.debugStorageAtAvailable = function () {
return true
}
module.exports = TraceRetriever module.exports = TraceRetriever
...@@ -12,6 +12,7 @@ function DropdownPanel (_name, _opts) { ...@@ -12,6 +12,7 @@ function DropdownPanel (_name, _opts) {
_opts = {} _opts = {}
} }
this.name = _name this.name = _name
this.header = ''
this.json = _opts.json this.json = _opts.json
if (this.json) { if (this.json) {
this.treeView = new TreeView(_opts) this.treeView = new TreeView(_opts)
...@@ -19,10 +20,11 @@ function DropdownPanel (_name, _opts) { ...@@ -19,10 +20,11 @@ function DropdownPanel (_name, _opts) {
this.view this.view
} }
DropdownPanel.prototype.update = function (_data) { DropdownPanel.prototype.update = function (_data, _header) {
if (this.view) { if (this.view) {
this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t') this.view.querySelector('.dropdownpanel .dropdownrawcontent').innerText = JSON.stringify(_data, null, '\t')
this.view.querySelector('.dropdownpanel button.btn').style.display = 'block' this.view.querySelector('.dropdownpanel button.btn').style.display = 'block'
this.view.querySelector('.title span').innerText = _header || ' '
if (this.json) { if (this.json) {
this.treeView.update(_data) this.treeView.update(_data)
} }
...@@ -44,7 +46,7 @@ DropdownPanel.prototype.render = function (overridestyle) { ...@@ -44,7 +46,7 @@ DropdownPanel.prototype.render = function (overridestyle) {
var view = yo`<div> var view = yo`<div>
<div class='title' style=${ui.formatCss(styleDropdown.title)} onclick=${function () { self.toggle() }}> <div class='title' style=${ui.formatCss(styleDropdown.title)} onclick=${function () { self.toggle() }}>
<div style=${ui.formatCss(styleDropdown.caret)} class='fa fa-caret-right'></div> <div style=${ui.formatCss(styleDropdown.caret)} class='fa fa-caret-right'></div>
<div style=${ui.formatCss(styleDropdown.inner, styleDropdown.titleInner)}>${this.name}</div> <div style=${ui.formatCss(styleDropdown.inner, styleDropdown.titleInner)}>${this.name}</div><span></span>
</div> </div>
<div class='dropdownpanel' style=${ui.formatCss(styleDropdown.content)} style='display:none'> <div class='dropdownpanel' style=${ui.formatCss(styleDropdown.content)} style='display:none'>
<button onclick=${function () { self.toggleRaw() }} style=${ui.formatCss(basicStyles.button, styleDropdown.copyBtn)} title='raw' class="btn fa fa-eye" type="button"> <button onclick=${function () { self.toggleRaw() }} style=${ui.formatCss(basicStyles.button, styleDropdown.copyBtn)} title='raw' class="btn fa fa-eye" type="button">
......
'use strict' 'use strict'
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var StorageViewer = require('../storage/storageViewer')
var yo = require('yo-yo') var yo = require('yo-yo')
function FullStoragesChanges (_parent, _traceManager) { function FullStoragesChanges (_parent, _traceManager) {
this.storageResolver = null
this.parent = _parent this.parent = _parent
this.traceManager = _traceManager this.traceManager = _traceManager
this.addresses = [] this.addresses = []
...@@ -41,17 +43,26 @@ FullStoragesChanges.prototype.init = function () { ...@@ -41,17 +43,26 @@ FullStoragesChanges.prototype.init = function () {
this.parent.event.register('indexChanged', this, function (index) { this.parent.event.register('indexChanged', this, function (index) {
if (index < 0) return if (index < 0) return
if (self.parent.currentStepIndex !== index) return if (self.parent.currentStepIndex !== index) return
if (!self.storageResolver) return
if (index === self.traceLength - 1) { if (index === self.traceLength - 1) {
var storageJSON = {} var storageJSON = {}
for (var k in self.addresses) { for (var k in self.addresses) {
self.traceManager.getStorageAt(index, this.parent.tx, function (error, result) { var address = self.addresses[k]
var storageViewer = new StorageViewer({
stepIndex: self.parent.currentStepIndex,
tx: self.parent.tx,
address: address
}, self.storageResolver, self.traceManager)
storageViewer.storageRange(function (error, result) {
if (!error) { if (!error) {
storageJSON[self.addresses[k]] = result storageJSON[address] = result
self.basicPanel.update(storageJSON) self.basicPanel.update(storageJSON)
} }
}, self.addresses[k]) })
} }
} else {
self.basicPanel.update({})
} }
}) })
} }
......
...@@ -2,13 +2,15 @@ ...@@ -2,13 +2,15 @@
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var localDecoder = require('../solidity/localDecoder') var localDecoder = require('../solidity/localDecoder')
var solidityTypeFormatter = require('./SolidityTypeFormatter') var solidityTypeFormatter = require('./SolidityTypeFormatter')
var StorageViewer = require('../storage/storageViewer')
var yo = require('yo-yo') var yo = require('yo-yo')
class SolidityLocals { class SolidityLocals {
constructor (_parent, _traceManager, internalTreeCall) { constructor (_parent, _traceManager, _internalTreeCall) {
this.parent = _parent this.parent = _parent
this.internalTreeCall = internalTreeCall this.internalTreeCall = _internalTreeCall
this.storageResolver = null
this.traceManager = _traceManager this.traceManager = _traceManager
this.basicPanel = new DropdownPanel('Solidity Locals', { this.basicPanel = new DropdownPanel('Solidity Locals', {
json: true, json: true,
...@@ -31,24 +33,35 @@ class SolidityLocals { ...@@ -31,24 +33,35 @@ class SolidityLocals {
this.parent.event.register('sourceLocationChanged', this, (sourceLocation) => { this.parent.event.register('sourceLocationChanged', this, (sourceLocation) => {
var warningDiv = this.view.querySelector('#warning') var warningDiv = this.view.querySelector('#warning')
warningDiv.innerHTML = '' warningDiv.innerHTML = ''
if (!this.storageResolver) {
warningDiv.innerHTML = 'storage not ready'
return
}
this.traceManager.waterfall([ this.traceManager.waterfall([
this.traceManager.getStackAt, this.traceManager.getStackAt,
this.traceManager.getMemoryAt], this.traceManager.getMemoryAt,
this.traceManager.getCurrentCalledAddressAt],
this.parent.currentStepIndex, this.parent.currentStepIndex,
(error, result) => { (error, result) => {
if (!error) { if (!error) {
var stack = result[0].value var stack = result[0].value
var memory = result[1].value var memory = result[1].value
try { try {
this.traceManager.getStorageAt(this.parent.currentStepIndex, this.parent.tx, (error, storage) => { var storageViewer = new StorageViewer({
if (!error) { stepIndex: this.parent.currentStepIndex,
var locals = localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, storage, sourceLocation) tx: this.parent.tx,
address: result[2].value
}, this.storageResolver, this.traceManager)
localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, sourceLocation).then((locals) => {
if (!locals.error) {
this.basicPanel.update(locals) this.basicPanel.update(locals)
} }
}) })
} catch (e) { } catch (e) {
warningDiv.innerHTML = e.message warningDiv.innerHTML = e.message
} }
} else {
console.log(error)
} }
}) })
}) })
......
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var stateDecoder = require('../solidity/stateDecoder') var stateDecoder = require('../solidity/stateDecoder')
var solidityTypeFormatter = require('./SolidityTypeFormatter') var solidityTypeFormatter = require('./SolidityTypeFormatter')
var StorageViewer = require('../storage/storageViewer')
var yo = require('yo-yo') var yo = require('yo-yo')
function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) { function SolidityState (_parent, _traceManager, _codeManager, _solidityProxy) {
this.storageResolver = null
this.parent = _parent this.parent = _parent
this.traceManager = _traceManager this.traceManager = _traceManager
this.codeManager = _codeManager this.codeManager = _codeManager
...@@ -42,7 +44,12 @@ SolidityState.prototype.init = function () { ...@@ -42,7 +44,12 @@ SolidityState.prototype.init = function () {
return return
} }
self.traceManager.getStorageAt(index, this.parent.tx, function (error, storage) { if (!self.storageResolver) {
warningDiv.innerHTML = 'storage not ready'
return
}
self.traceManager.getCurrentCalledAddressAt(self.parent.currentStepIndex, (error, address) => {
if (error) { if (error) {
self.basicPanel.update({}) self.basicPanel.update({})
console.log(error) console.log(error)
...@@ -52,7 +59,16 @@ SolidityState.prototype.init = function () { ...@@ -52,7 +59,16 @@ SolidityState.prototype.init = function () {
self.basicPanel.update({}) self.basicPanel.update({})
console.log(error) console.log(error)
} else { } else {
self.basicPanel.update(stateDecoder.decodeState(stateVars, storage)) var storageViewer = new StorageViewer({
stepIndex: self.parent.currentStepIndex,
tx: self.parent.tx,
address: address
}, self.storageResolver, self.traceManager)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
if (!result.error) {
self.basicPanel.update(result)
}
})
} }
}) })
} }
......
'use strict' 'use strict'
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var StorageViewer = require('../storage/storageViewer')
var yo = require('yo-yo') var yo = require('yo-yo')
function StoragePanel (_parent, _traceManager, _address) { function StoragePanel (_parent, _traceManager) {
this.parent = _parent this.parent = _parent
this.storageResolver = null
this.traceManager = _traceManager this.traceManager = _traceManager
this.basicPanel = new DropdownPanel('Storage Changes', {json: true}) this.basicPanel = new DropdownPanel('Storage', {json: true})
this.address = _address
this.init() this.init()
this.disabled = false this.disabled = false
} }
...@@ -21,15 +22,27 @@ StoragePanel.prototype.init = function () { ...@@ -21,15 +22,27 @@ StoragePanel.prototype.init = function () {
if (self.disabled) return if (self.disabled) return
if (index < 0) return if (index < 0) return
if (self.parent.currentStepIndex !== index) return if (self.parent.currentStepIndex !== index) return
if (!self.storageResolver) return
self.traceManager.getStorageAt(index, self.parent.tx, function (error, storage) { this.traceManager.getCurrentCalledAddressAt(index, (error, address) => {
if (error) { if (!error) {
console.log(error) var storageViewer = new StorageViewer({
self.basicPanel.update({}) stepIndex: self.parent.currentStepIndex,
} else if (self.parent.currentStepIndex === index) { tx: self.parent.tx,
self.basicPanel.update(storage) address: address
}, self.storageResolver, self.traceManager)
storageViewer.storageRange((error, storage) => {
if (error) {
console.log(error)
self.basicPanel.update({})
} else if (self.parent.currentStepIndex === index) {
var header = storageViewer.isComplete(address) ? 'completely loaded' : 'partially loaded...'
self.basicPanel.update(storage, header)
}
})
} }
}, self.address) })
}) })
} }
......
...@@ -10,6 +10,7 @@ var StepDetail = require('./StepDetail') ...@@ -10,6 +10,7 @@ var StepDetail = require('./StepDetail')
var DropdownPanel = require('./DropdownPanel') var DropdownPanel = require('./DropdownPanel')
var SolidityState = require('./SolidityState') var SolidityState = require('./SolidityState')
var SolidityLocals = require('./SolidityLocals') var SolidityLocals = require('./SolidityLocals')
var StorageResolver = require('../storage/storageResolver.js')
var yo = require('yo-yo') var yo = require('yo-yo')
function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _callTree) { function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _callTree) {
...@@ -43,6 +44,11 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _call ...@@ -43,6 +44,11 @@ function VmDebugger (_parent, _traceManager, _codeManager, _solidityProxy, _call
this.view this.view
var self = this var self = this
_parent.event.register('newTraceLoaded', this, function () { _parent.event.register('newTraceLoaded', this, function () {
var storageResolver = new StorageResolver()
self.storagePanel.storageResolver = storageResolver
self.solidityState.storageResolver = storageResolver
self.solidityLocals.storageResolver = storageResolver
self.fullStoragesChangesPanel.storageResolver = storageResolver
self.view.style.display = 'block' self.view.style.display = 'block'
}) })
_parent.event.register('traceUnloaded', this, function () { _parent.event.register('traceUnloaded', this, function () {
......
...@@ -19,8 +19,8 @@ module.exports = { ...@@ -19,8 +19,8 @@ module.exports = {
methods.push(new web3._extend.Method({ methods.push(new web3._extend.Method({
name: 'storageRangeAt', name: 'storageRangeAt',
call: 'debug_storageRangeAt', call: 'debug_storageRangeAt',
inputFormatter: [null, null, null, null, null, null], inputFormatter: [null, null, null, null, null],
params: 6 params: 5
})) }))
} }
if (methods.length > 0) { if (methods.length > 0) {
......
...@@ -153,7 +153,7 @@ web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) { ...@@ -153,7 +153,7 @@ web3VmProvider.prototype.traceTransaction = function (txHash, options, cb) {
} }
} }
web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, end, maxLength, cb) { // txIndex is the hash in the case of the VM web3VmProvider.prototype.storageRangeAt = function (blockNumber, txIndex, address, start, maxLength, cb) { // txIndex is the hash in the case of the VM
// we don't use the range params here // we don't use the range params here
if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) { if (this.storageCache[txIndex] && this.storageCache[txIndex][address]) {
var storage = this.storageCache[txIndex][address] var storage = this.storageCache[txIndex][address]
......
...@@ -64,7 +64,9 @@ function panels (browser) { ...@@ -64,7 +64,9 @@ function panels (browser) {
.click('#load') .click('#load')
.multipleClick('#intoforward', 63) .multipleClick('#intoforward', 63)
.assertStack(['0:0x', '1:0x60', '2:0x65', '3:0x38', '4:0x55', '5:0x60fe47b1']) .assertStack(['0:0x', '1:0x60', '2:0x65', '3:0x38', '4:0x55', '5:0x60fe47b1'])
.assertStorageChanges(['0x00:0x38']) .assertStorageChanges([
'0x0000000000000000000000000000000000000000000000000000000000000000:Objectkey:0x0000000000000000000000000000000000000000000000000000000000000000value:0x0000000000000000000000000000000000000000000000000000000000000000',
'0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563:ObjecthashedKey:0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563key:0x00value:0x38'])
.assertCallData(['0:0x60fe47b10000000000000000000000000000000000000000000000000000000000000038']) .assertCallData(['0:0x60fe47b10000000000000000000000000000000000000000000000000000000000000038'])
.assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5']) .assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5'])
.assertStackValue(1, '1:0x60') .assertStackValue(1, '1:0x60')
...@@ -73,7 +75,7 @@ function panels (browser) { ...@@ -73,7 +75,7 @@ function panels (browser) {
.assertMemoryValue(8, '0x80:5b806001016000600050819055505b50?????????P??UP?P') .assertMemoryValue(8, '0x80:5b806001016000600050819055505b50?????????P??UP?P')
.click('#intoforward') // CREATE .click('#intoforward') // CREATE
.assertStack(['']) .assertStack([''])
.assertStorageChanges(['']) .assertStorageChanges(['0x0000000000000000000000000000000000000000000000000000000000000000:Objectkey:0x0000000000000000000000000000000000000000000000000000000000000000value:0x0000000000000000000000000000000000000000000000000000000000000000'])
.assertMemory(['']) .assertMemory([''])
.assertCallData(['0:0x0000000000000000000000000000000000000000000000000000000000000000000000000000006060606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055']) .assertCallData(['0:0x0000000000000000000000000000000000000000000000000000000000000000000000000000006060606040526040516020806045833981016040528080519060200190919050505b806001016000600050819055'])
.assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', '1:(ContractCreation-Step63)']) .assertCallStack(['0:0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', '1:(ContractCreation-Step63)'])
......
...@@ -28,7 +28,7 @@ function loadTestWeb3 (data) { ...@@ -28,7 +28,7 @@ function loadTestWeb3 (data) {
callback(null, data.testTraces[txHash]) callback(null, data.testTraces[txHash])
} }
uiTestweb3.debug.storageRangeAt = function (blockNumber, txIndex, address, start, end, size, callback) { uiTestweb3.debug.storageRangeAt = function (blockNumber, txIndex, address, start, size, callback) {
callback(null, { storage: {}, complete: true }) callback(null, { storage: {}, complete: true })
} }
......
...@@ -18,7 +18,7 @@ web3Override.debug.traceTransaction = function (txHash, options, callback) { ...@@ -18,7 +18,7 @@ web3Override.debug.traceTransaction = function (txHash, options, callback) {
callback(null, data.testTraces[txHash]) callback(null, data.testTraces[txHash])
} }
web3Override.debug.storageRangeAt = function (blockNumber, txIndex, address, start, end, maxSize, callback) { web3Override.debug.storageRangeAt = function (blockNumber, txIndex, address, start, maxSize, callback) {
callback(null, { storage: {}, complete: true }) callback(null, { storage: {}, complete: true })
} }
......
...@@ -12,8 +12,9 @@ function decodeLocal (st, index, traceManager, callTree, verifier) { ...@@ -12,8 +12,9 @@ function decodeLocal (st, index, traceManager, callTree, verifier) {
index, index,
function (error, result) { function (error, result) {
if (!error) { if (!error) {
var locals = localDecoder.solidityLocals(index, callTree, result[0].value, result[1].value, {}, {start: 5000}) localDecoder.solidityLocals(index, callTree, result[0].value, result[1].value, {}, {start: 5000}).then((locals) => {
verifier(locals) verifier(locals)
})
} else { } else {
st.fail(error) st.fail(error)
} }
......
'use strict'
var util = require('../../src/helpers/util')
class MockStorageResolver {
constructor (_storage) {
this.storage = {}
for (var k in _storage) {
var hashed = util.sha3_256(k)
this.storage[hashed] = {
hashed: hashed,
key: k,
value: _storage[k]
}
}
}
storageRange (callback) {
callback(null, this.storage)
}
storageSlot (slot, callback) {
var hashed = util.sha3_256(slot)
callback(null, this.storage[hashed])
}
isComplete (address) {
return true
}
fromCache (address, slotKey) {
return this.storage[slotKey]
}
toCache (address, storage, complete) {
}
}
module.exports = MockStorageResolver
...@@ -2,150 +2,166 @@ ...@@ -2,150 +2,166 @@
var tape = require('tape') var tape = require('tape')
var compiler = require('solc') var compiler = require('solc')
var stateDecoder = require('../../src/index').solidity.stateDecoder var stateDecoder = require('../../src/index').solidity.stateDecoder
var MockStorageResolver = require('./mockStorageResolver')
tape('solidity', function (t) { tape('solidity', function (t) {
t.test('storage decoder', function (st) { t.test('storage decoder', function (st) {
testIntStorage(st) testIntStorage(st, function () {
testByteStorage(st) testByteStorage(st, function () {
testStructArrayStorage(st) testStructArrayStorage(st, function () {
st.end() st.end()
})
})
})
}) })
}) })
function testIntStorage (st) { function testIntStorage (st, cb) {
var intStorage = require('./contracts/intStorage') var intStorage = require('./contracts/intStorage')
var output = compiler.compile(intStorage.contract, 0) var output = compiler.compile(intStorage.contract, 0)
var mockStorageResolver
for (var storage of [intStorage.fullStorage, shrinkStorage(intStorage.fullStorage)]) { for (var storage of [intStorage.fullStorage, shrinkStorage(intStorage.fullStorage)]) {
var decoded = stateDecoder.solidityState(storage, output.sources, 'intStorage') mockStorageResolver = new MockStorageResolver(storage)
st.equal(decoded['ui8'].value, '130') stateDecoder.solidityState(mockStorageResolver, output.sources, 'intStorage').then((decoded) => {
st.equal(decoded['ui16'].value, '456') st.equal(decoded['ui8'].value, '130')
st.equal(decoded['ui32'].value, '4356') st.equal(decoded['ui16'].value, '456')
st.equal(decoded['ui64'].value, '3543543543') st.equal(decoded['ui32'].value, '4356')
st.equal(decoded['ui128'].value, '234567') st.equal(decoded['ui64'].value, '3543543543')
st.equal(decoded['ui256'].value, '115792089237316195423570985008687907853269984665640564039457584007880697216513') st.equal(decoded['ui128'].value, '234567')
st.equal(decoded['ui'].value, '123545666') st.equal(decoded['ui256'].value, '115792089237316195423570985008687907853269984665640564039457584007880697216513')
st.equal(decoded['i8'].value, '-45') st.equal(decoded['ui'].value, '123545666')
st.equal(decoded['i16'].value, '-1234') st.equal(decoded['i8'].value, '-45')
st.equal(decoded['i32'].value, '3455') st.equal(decoded['i16'].value, '-1234')
st.equal(decoded['i64'].value, '-35566') st.equal(decoded['i32'].value, '3455')
st.equal(decoded['i128'].value, '-444444') st.equal(decoded['i64'].value, '-35566')
st.equal(decoded['i256'].value, '3434343') st.equal(decoded['i128'].value, '-444444')
st.equal(decoded['i'].value, '-32432423423') st.equal(decoded['i256'].value, '3434343')
st.equal(decoded['ishrink'].value, '2') st.equal(decoded['i'].value, '-32432423423')
st.equal(decoded['ishrink'].value, '2')
})
} }
decoded = stateDecoder.solidityState({}, output.sources, 'intStorage') mockStorageResolver = new MockStorageResolver({})
st.equal(decoded['ui8'].value, '0') stateDecoder.solidityState(mockStorageResolver, output.sources, 'intStorage').then((decoded) => {
st.equal(decoded['ui16'].value, '0') st.equal(decoded['ui8'].value, '0')
st.equal(decoded['ui32'].value, '0') st.equal(decoded['ui16'].value, '0')
st.equal(decoded['ui64'].value, '0') st.equal(decoded['ui32'].value, '0')
st.equal(decoded['ui128'].value, '0') st.equal(decoded['ui64'].value, '0')
st.equal(decoded['ui256'].value, '0') st.equal(decoded['ui128'].value, '0')
st.equal(decoded['ui'].value, '0') st.equal(decoded['ui256'].value, '0')
st.equal(decoded['i8'].value, '0') st.equal(decoded['ui'].value, '0')
st.equal(decoded['i16'].value, '0') st.equal(decoded['i8'].value, '0')
st.equal(decoded['i32'].value, '0') st.equal(decoded['i16'].value, '0')
st.equal(decoded['i64'].value, '0') st.equal(decoded['i32'].value, '0')
st.equal(decoded['i128'].value, '0') st.equal(decoded['i64'].value, '0')
st.equal(decoded['i256'].value, '0') st.equal(decoded['i128'].value, '0')
st.equal(decoded['i'].value, '0') st.equal(decoded['i256'].value, '0')
st.equal(decoded['ishrink'].value, '0') st.equal(decoded['i'].value, '0')
st.equal(decoded['ishrink'].value, '0')
cb()
})
} }
function testByteStorage (st) { function testByteStorage (st, cb) {
var byteStorage = require('./contracts/byteStorage') var byteStorage = require('./contracts/byteStorage')
var output = compiler.compile(byteStorage.contract, 0) var output = compiler.compile(byteStorage.contract, 0)
var mockStorageResolver
for (var storage of [byteStorage.storage, shrinkStorage(byteStorage.storage)]) { for (var storage of [byteStorage.storage, shrinkStorage(byteStorage.storage)]) {
var decoded = stateDecoder.solidityState(storage, output.sources, 'byteStorage') mockStorageResolver = new MockStorageResolver(storage)
st.equal(decoded['b1'].value, false) stateDecoder.solidityState(mockStorageResolver, output.sources, 'byteStorage').then((decoded) => {
st.equal(decoded['a1'].value, '0xFE350F199F244AC9A79038D254400B632A633225') st.equal(decoded['b1'].value, false)
st.equal(decoded['b2'].value, true) st.equal(decoded['a1'].value, '0xFE350F199F244AC9A79038D254400B632A633225')
st.equal(decoded['dynb1'].value, '0x64796e616d69636279746573') st.equal(decoded['b2'].value, true)
st.equal(decoded['dynb1'].length, '0xc') st.equal(decoded['dynb1'].value, '0x64796e616d69636279746573')
st.equal(decoded['stab'].value, '0x01') st.equal(decoded['dynb1'].length, '0xc')
st.equal(decoded['stab1'].value, '0x12') st.equal(decoded['stab'].value, '0x01')
st.equal(decoded['stab2'].value, '0x1579') st.equal(decoded['stab1'].value, '0x12')
st.equal(decoded['stab3'].value, '0x359356') st.equal(decoded['stab2'].value, '0x1579')
st.equal(decoded['stab4'].value, '0x23750000') st.equal(decoded['stab3'].value, '0x359356')
st.equal(decoded['stab5'].value, '0x0235764500') st.equal(decoded['stab4'].value, '0x23750000')
st.equal(decoded['stab6'].value, '0x324435000000') st.equal(decoded['stab5'].value, '0x0235764500')
st.equal(decoded['stab7'].value, '0x00432400000000') st.equal(decoded['stab6'].value, '0x324435000000')
st.equal(decoded['stab8'].value, '0x3245546457650000') st.equal(decoded['stab7'].value, '0x00432400000000')
st.equal(decoded['stab9'].value, '0x034345430000000000') st.equal(decoded['stab8'].value, '0x3245546457650000')
st.equal(decoded['stab10'].value, '0x04543543654657000000') st.equal(decoded['stab9'].value, '0x034345430000000000')
st.equal(decoded['stab11'].value, '0x5435465400000000000000') st.equal(decoded['stab10'].value, '0x04543543654657000000')
st.equal(decoded['stab12'].value, '0x030000000000000000000000') st.equal(decoded['stab11'].value, '0x5435465400000000000000')
st.equal(decoded['stab13'].value, '0x03243242345435000000000000') st.equal(decoded['stab12'].value, '0x030000000000000000000000')
st.equal(decoded['stab14'].value, '0x3245435435435300000000000000') st.equal(decoded['stab13'].value, '0x03243242345435000000000000')
st.equal(decoded['stab15'].value, '0x032454434435000000000000000000') st.equal(decoded['stab14'].value, '0x3245435435435300000000000000')
st.equal(decoded['stab16'].value, '0x32454354440000000000000000000000') st.equal(decoded['stab15'].value, '0x032454434435000000000000000000')
st.equal(decoded['stab17'].value, '0x0324543432432432450000000000000000') st.equal(decoded['stab16'].value, '0x32454354440000000000000000000000')
st.equal(decoded['stab18'].value, '0x032453432543543500000000000000000000') st.equal(decoded['stab17'].value, '0x0324543432432432450000000000000000')
st.equal(decoded['stab19'].value, '0x03245434354354350000000000000000000000') st.equal(decoded['stab18'].value, '0x032453432543543500000000000000000000')
st.equal(decoded['stab20'].value, '0x032454543543AB35000000000000000000000000') st.equal(decoded['stab19'].value, '0x03245434354354350000000000000000000000')
st.equal(decoded['stab21'].value, '0x324544324234350000000000000000000000000000') st.equal(decoded['stab20'].value, '0x032454543543AB35000000000000000000000000')
st.equal(decoded['stab22'].value, '0x324543AEF50000000000000000000000000000000000') st.equal(decoded['stab21'].value, '0x324544324234350000000000000000000000000000')
st.equal(decoded['stab23'].value, '0x3245435FFF000000000000000000000000000000000000') st.equal(decoded['stab22'].value, '0x324543AEF50000000000000000000000000000000000')
st.equal(decoded['stab24'].value, '0x3245435F0000000000000000000000000000000000000000') st.equal(decoded['stab23'].value, '0x3245435FFF000000000000000000000000000000000000')
st.equal(decoded['stab25'].value, '0x3245435F000000000000000000000000000000000000000000') st.equal(decoded['stab24'].value, '0x3245435F0000000000000000000000000000000000000000')
st.equal(decoded['stab26'].value, '0x3245435F00000000000000000000000000000000000000000000') st.equal(decoded['stab25'].value, '0x3245435F000000000000000000000000000000000000000000')
st.equal(decoded['stab27'].value, '0x03245FFFFFFF000000000000000000000000000000000000000000') st.equal(decoded['stab26'].value, '0x3245435F00000000000000000000000000000000000000000000')
st.equal(decoded['stab28'].value, '0x03241235000000000000000000000000000000000000000000000000') st.equal(decoded['stab27'].value, '0x03245FFFFFFF000000000000000000000000000000000000000000')
st.equal(decoded['stab29'].value, '0x0325213213000000000000000000000000000000000000000000000000') st.equal(decoded['stab28'].value, '0x03241235000000000000000000000000000000000000000000000000')
st.equal(decoded['stab30'].value, '0x032454352324230000000000000000000000000000000000000000000000') st.equal(decoded['stab29'].value, '0x0325213213000000000000000000000000000000000000000000000000')
st.equal(decoded['stab31'].value, '0x32454351230000000000000000000000000000000000000000000000000000') st.equal(decoded['stab30'].value, '0x032454352324230000000000000000000000000000000000000000000000')
st.equal(decoded['stab32'].value, '0x324324423432543543AB00000000000000000000000000000000000000000000') st.equal(decoded['stab31'].value, '0x32454351230000000000000000000000000000000000000000000000000000')
st.equal(decoded['enumDec'].value, 'e240') st.equal(decoded['stab32'].value, '0x324324423432543543AB00000000000000000000000000000000000000000000')
st.equal(decoded['str1'].value, 'short') st.equal(decoded['enumDec'].value, 'e240')
st.equal(decoded['str12'].value, 'шеллы') st.equal(decoded['str1'].value, 'short')
st.equal(decoded['str2'].value, 'long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long') st.equal(decoded['str12'].value, 'шеллы')
st.equal(decoded['str2'].value, 'long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long__long')
})
} }
decoded = stateDecoder.solidityState({}, output.sources, 'byteStorage') mockStorageResolver = new MockStorageResolver({})
st.equal(decoded['b1'].value, false) stateDecoder.solidityState(mockStorageResolver, output.sources, 'byteStorage').then((decoded) => {
st.equal(decoded['a1'].value, '0x0000000000000000000000000000000000000000') st.equal(decoded['b1'].value, false)
st.equal(decoded['b2'].value, false) st.equal(decoded['a1'].value, '0x0000000000000000000000000000000000000000')
st.equal(decoded['dynb1'].value, '0x') st.equal(decoded['b2'].value, false)
st.equal(decoded['dynb1'].length, '0x0') st.equal(decoded['dynb1'].value, '0x')
st.equal(decoded['stab'].value, '0x00') st.equal(decoded['dynb1'].length, '0x0')
st.equal(decoded['stab1'].value, '0x00') st.equal(decoded['stab'].value, '0x00')
st.equal(decoded['stab2'].value, '0x0000') st.equal(decoded['stab1'].value, '0x00')
st.equal(decoded['stab3'].value, '0x000000') st.equal(decoded['stab2'].value, '0x0000')
st.equal(decoded['stab4'].value, '0x00000000') st.equal(decoded['stab3'].value, '0x000000')
st.equal(decoded['stab5'].value, '0x0000000000') st.equal(decoded['stab4'].value, '0x00000000')
st.equal(decoded['stab6'].value, '0x000000000000') st.equal(decoded['stab5'].value, '0x0000000000')
st.equal(decoded['stab7'].value, '0x00000000000000') st.equal(decoded['stab6'].value, '0x000000000000')
st.equal(decoded['stab8'].value, '0x0000000000000000') st.equal(decoded['stab7'].value, '0x00000000000000')
st.equal(decoded['stab9'].value, '0x000000000000000000') st.equal(decoded['stab8'].value, '0x0000000000000000')
st.equal(decoded['stab10'].value, '0x00000000000000000000') st.equal(decoded['stab9'].value, '0x000000000000000000')
st.equal(decoded['stab11'].value, '0x0000000000000000000000') st.equal(decoded['stab10'].value, '0x00000000000000000000')
st.equal(decoded['stab12'].value, '0x000000000000000000000000') st.equal(decoded['stab11'].value, '0x0000000000000000000000')
st.equal(decoded['stab13'].value, '0x00000000000000000000000000') st.equal(decoded['stab12'].value, '0x000000000000000000000000')
st.equal(decoded['stab14'].value, '0x0000000000000000000000000000') st.equal(decoded['stab13'].value, '0x00000000000000000000000000')
st.equal(decoded['stab15'].value, '0x000000000000000000000000000000') st.equal(decoded['stab14'].value, '0x0000000000000000000000000000')
st.equal(decoded['stab16'].value, '0x00000000000000000000000000000000') st.equal(decoded['stab15'].value, '0x000000000000000000000000000000')
st.equal(decoded['stab17'].value, '0x0000000000000000000000000000000000') st.equal(decoded['stab16'].value, '0x00000000000000000000000000000000')
st.equal(decoded['stab18'].value, '0x000000000000000000000000000000000000') st.equal(decoded['stab17'].value, '0x0000000000000000000000000000000000')
st.equal(decoded['stab19'].value, '0x00000000000000000000000000000000000000') st.equal(decoded['stab18'].value, '0x000000000000000000000000000000000000')
st.equal(decoded['stab20'].value, '0x0000000000000000000000000000000000000000') st.equal(decoded['stab19'].value, '0x00000000000000000000000000000000000000')
st.equal(decoded['stab21'].value, '0x000000000000000000000000000000000000000000') st.equal(decoded['stab20'].value, '0x0000000000000000000000000000000000000000')
st.equal(decoded['stab22'].value, '0x00000000000000000000000000000000000000000000') st.equal(decoded['stab21'].value, '0x000000000000000000000000000000000000000000')
st.equal(decoded['stab23'].value, '0x0000000000000000000000000000000000000000000000') st.equal(decoded['stab22'].value, '0x00000000000000000000000000000000000000000000')
st.equal(decoded['stab24'].value, '0x000000000000000000000000000000000000000000000000') st.equal(decoded['stab23'].value, '0x0000000000000000000000000000000000000000000000')
st.equal(decoded['stab25'].value, '0x00000000000000000000000000000000000000000000000000') st.equal(decoded['stab24'].value, '0x000000000000000000000000000000000000000000000000')
st.equal(decoded['stab26'].value, '0x0000000000000000000000000000000000000000000000000000') st.equal(decoded['stab25'].value, '0x00000000000000000000000000000000000000000000000000')
st.equal(decoded['stab27'].value, '0x000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab26'].value, '0x0000000000000000000000000000000000000000000000000000')
st.equal(decoded['stab28'].value, '0x00000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab27'].value, '0x000000000000000000000000000000000000000000000000000000')
st.equal(decoded['stab29'].value, '0x0000000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab28'].value, '0x00000000000000000000000000000000000000000000000000000000')
st.equal(decoded['stab30'].value, '0x000000000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab29'].value, '0x0000000000000000000000000000000000000000000000000000000000')
st.equal(decoded['stab31'].value, '0x00000000000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab30'].value, '0x000000000000000000000000000000000000000000000000000000000000')
st.equal(decoded['stab32'].value, '0x0000000000000000000000000000000000000000000000000000000000000000') st.equal(decoded['stab31'].value, '0x00000000000000000000000000000000000000000000000000000000000000')
st.equal(decoded['enumDec'].value, 'e0') st.equal(decoded['stab32'].value, '0x0000000000000000000000000000000000000000000000000000000000000000')
st.equal(decoded['str1'].length, '0x0') st.equal(decoded['enumDec'].value, 'e0')
st.equal(decoded['str2'].length, '0x0') st.equal(decoded['str1'].length, '0x0')
st.equal(decoded['str1'].value, '') st.equal(decoded['str2'].length, '0x0')
st.equal(decoded['str12'].value, '') st.equal(decoded['str1'].value, '')
st.equal(decoded['str2'].value, '') st.equal(decoded['str12'].value, '')
st.equal(decoded['str2'].value, '')
cb()
})
} }
function shrinkStorage (storage) { function shrinkStorage (storage) {
...@@ -158,99 +174,95 @@ function shrinkStorage (storage) { ...@@ -158,99 +174,95 @@ function shrinkStorage (storage) {
return shrinkedStorage return shrinkedStorage
} }
function testStructArrayStorage (st) { function testStructArrayStorage (st, cb) {
var structArrayStorage = require('./contracts/structArrayStorage') var structArrayStorage = require('./contracts/structArrayStorage')
var output = compiler.compile(structArrayStorage.contract, 0) var output = compiler.compile(structArrayStorage.contract, 0)
var decoded = stateDecoder.solidityState(structArrayStorage.storage, output.sources, 'structArrayStorage') var mockStorageResolver = new MockStorageResolver(structArrayStorage.storage)
st.equal(decoded['intStructDec'].value['i8'].value, '32') stateDecoder.solidityState(mockStorageResolver, output.sources, 'structArrayStorage').then((decoded) => {
st.equal(decoded['intStructDec'].value['i16'].value, '-54') st.equal(decoded['intStructDec'].value['i8'].value, '32')
st.equal(decoded['intStructDec'].value['ui32'].value, '128') st.equal(decoded['intStructDec'].value['i16'].value, '-54')
st.equal(decoded['intStructDec'].value['i256'].value, '-1243565465756') st.equal(decoded['intStructDec'].value['ui32'].value, '128')
st.equal(decoded['intStructDec'].value['ui16'].value, '34556') st.equal(decoded['intStructDec'].value['i256'].value, '-1243565465756')
st.equal(decoded['intStructDec'].value['i32'].value, '-345446546') st.equal(decoded['intStructDec'].value['ui16'].value, '34556')
st.equal(decoded['intStructDec'].value['i32'].value, '-345446546')
st.equal(decoded['i5'].length, '0x7') st.equal(decoded['i5'].length, '0x7')
st.equal(decoded['i5'].value[0].value, '-2134') st.equal(decoded['i5'].value[0].value, '-2134')
st.equal(decoded['i5'].value[1].value, '345') st.equal(decoded['i5'].value[1].value, '345')
st.equal(decoded['i5'].value[2].value, '-3246') st.equal(decoded['i5'].value[2].value, '-3246')
st.equal(decoded['i5'].value[3].value, '4357') st.equal(decoded['i5'].value[3].value, '4357')
st.equal(decoded['i5'].value[4].value, '324') st.equal(decoded['i5'].value[4].value, '324')
st.equal(decoded['i5'].value[5].value, '-2344') st.equal(decoded['i5'].value[5].value, '-2344')
st.equal(decoded['i5'].value[6].value, '3254') st.equal(decoded['i5'].value[6].value, '3254')
st.equal(decoded['idyn5'].length, '0x9')
st.equal(decoded['idyn5'].length, '0x9') st.equal(decoded['idyn5'].value[0].value, '-2134')
st.equal(decoded['idyn5'].value[0].value, '-2134') st.equal(decoded['idyn5'].value[1].value, '345')
st.equal(decoded['idyn5'].value[1].value, '345') st.equal(decoded['idyn5'].value[2].value, '-3246')
st.equal(decoded['idyn5'].value[2].value, '-3246') st.equal(decoded['idyn5'].value[3].value, '4357')
st.equal(decoded['idyn5'].value[3].value, '4357') st.equal(decoded['idyn5'].value[4].value, '324')
st.equal(decoded['idyn5'].value[4].value, '324') st.equal(decoded['idyn5'].value[5].value, '-2344')
st.equal(decoded['idyn5'].value[5].value, '-2344') st.equal(decoded['idyn5'].value[6].value, '3254')
st.equal(decoded['idyn5'].value[6].value, '3254') st.equal(decoded['idyn5'].value[7].value, '-254')
st.equal(decoded['idyn5'].value[7].value, '-254') st.equal(decoded['idyn5'].value[8].value, '-2354')
st.equal(decoded['idyn5'].value[8].value, '-2354') st.equal(decoded['dyn1'].length, '0x4')
st.equal(decoded['dyn1'].value[0].length, '0x1')
st.equal(decoded['dyn1'].length, '0x4') st.equal(decoded['dyn1'].value[0].value[0].value, '3')
st.equal(decoded['dyn1'].value[0].length, '0x1') st.equal(decoded['dyn1'].value[1].length, '0x3')
st.equal(decoded['dyn1'].value[0].value[0].value, '3') st.equal(decoded['dyn1'].value[1].value[0].value, '12')
st.equal(decoded['dyn1'].value[1].value[1].value, '-12')
st.equal(decoded['dyn1'].value[1].length, '0x3') st.equal(decoded['dyn1'].value[1].value[2].value, '-1234')
st.equal(decoded['dyn1'].value[1].value[0].value, '12') st.equal(decoded['dyn1'].value[2].length, '0xa')
st.equal(decoded['dyn1'].value[1].value[1].value, '-12') st.equal(decoded['dyn1'].value[2].value[0].value, '1')
st.equal(decoded['dyn1'].value[1].value[2].value, '-1234') st.equal(decoded['dyn1'].value[2].value[1].value, '12')
st.equal(decoded['dyn1'].value[2].value[2].value, '1235')
st.equal(decoded['dyn1'].value[2].length, '0xa') st.equal(decoded['dyn1'].value[2].value[3].value, '-12')
st.equal(decoded['dyn1'].value[2].value[0].value, '1') st.equal(decoded['dyn1'].value[2].value[4].value, '-123456')
st.equal(decoded['dyn1'].value[2].value[1].value, '12') st.equal(decoded['dyn1'].value[2].value[5].value, '-23435435')
st.equal(decoded['dyn1'].value[2].value[2].value, '1235') st.equal(decoded['dyn1'].value[2].value[6].value, '543543')
st.equal(decoded['dyn1'].value[2].value[3].value, '-12') st.equal(decoded['dyn1'].value[2].value[7].value, '2')
st.equal(decoded['dyn1'].value[2].value[4].value, '-123456') st.equal(decoded['dyn1'].value[2].value[8].value, '-1')
st.equal(decoded['dyn1'].value[2].value[5].value, '-23435435') st.equal(decoded['dyn1'].value[2].value[9].value, '232432')
st.equal(decoded['dyn1'].value[2].value[6].value, '543543') st.equal(decoded['dyn1'].value[3].length, '0x2')
st.equal(decoded['dyn1'].value[2].value[7].value, '2') st.equal(decoded['dyn1'].value[3].value[0].value, '232432')
st.equal(decoded['dyn1'].value[2].value[8].value, '-1') st.equal(decoded['dyn1'].value[3].value[0].value, '232432')
st.equal(decoded['dyn1'].value[2].value[9].value, '232432') st.equal(decoded['dyn2'].length, '0x2')
st.equal(decoded['dyn2'].value[0].length, '0x4')
st.equal(decoded['dyn1'].value[3].length, '0x2') st.equal(decoded['dyn2'].value[0].value[0].value[0].value, '23')
st.equal(decoded['dyn1'].value[3].value[0].value, '232432') st.equal(decoded['dyn2'].value[0].value[0].value[1].value, '-23')
st.equal(decoded['dyn1'].value[3].value[0].value, '232432') st.equal(decoded['dyn2'].value[0].value[0].value[2].value, '-28')
st.equal(decoded['dyn2'].value[0].value[1].value[0].value, '23')
st.equal(decoded['dyn2'].length, '0x2') st.equal(decoded['dyn2'].value[0].value[1].value[1].value, '-23')
st.equal(decoded['dyn2'].value[0].length, '0x4') st.equal(decoded['dyn2'].value[0].value[1].value[2].value, '-28')
st.equal(decoded['dyn2'].value[0].value[0].value[0].value, '23') st.equal(decoded['dyn2'].value[0].value[2].value[0].value, '23')
st.equal(decoded['dyn2'].value[0].value[0].value[1].value, '-23') st.equal(decoded['dyn2'].value[0].value[2].value[1].value, '-23')
st.equal(decoded['dyn2'].value[0].value[0].value[2].value, '-28') st.equal(decoded['dyn2'].value[0].value[2].value[2].value, '-28')
st.equal(decoded['dyn2'].value[0].value[1].value[0].value, '23') st.equal(decoded['dyn2'].value[0].value[3].value[0].value, '23')
st.equal(decoded['dyn2'].value[0].value[1].value[1].value, '-23') st.equal(decoded['dyn2'].value[0].value[3].value[1].value, '-23')
st.equal(decoded['dyn2'].value[0].value[1].value[2].value, '-28') st.equal(decoded['dyn2'].value[0].value[3].value[2].value, '-28')
st.equal(decoded['dyn2'].value[0].value[2].value[0].value, '23') st.equal(decoded['dyn2'].value[1].length, '0x4')
st.equal(decoded['dyn2'].value[0].value[2].value[1].value, '-23') st.equal(decoded['dyn2'].value[1].value[0].value[0].value, '23')
st.equal(decoded['dyn2'].value[0].value[2].value[2].value, '-28') st.equal(decoded['dyn2'].value[1].value[0].value[1].value, '-23')
st.equal(decoded['dyn2'].value[0].value[3].value[0].value, '23') st.equal(decoded['dyn2'].value[1].value[0].value[2].value, '-28')
st.equal(decoded['dyn2'].value[0].value[3].value[1].value, '-23') st.equal(decoded['dyn2'].value[1].value[1].value[0].value, '23')
st.equal(decoded['dyn2'].value[0].value[3].value[2].value, '-28') st.equal(decoded['dyn2'].value[1].value[1].value[1].value, '-23')
st.equal(decoded['dyn2'].value[1].length, '0x4') st.equal(decoded['dyn2'].value[1].value[1].value[2].value, '-28')
st.equal(decoded['dyn2'].value[1].value[0].value[0].value, '23') st.equal(decoded['dyn2'].value[1].value[2].value[0].value, '23')
st.equal(decoded['dyn2'].value[1].value[0].value[1].value, '-23') st.equal(decoded['dyn2'].value[1].value[2].value[1].value, '-23')
st.equal(decoded['dyn2'].value[1].value[0].value[2].value, '-28') st.equal(decoded['dyn2'].value[1].value[2].value[2].value, '-28')
st.equal(decoded['dyn2'].value[1].value[1].value[0].value, '23') st.equal(decoded['dyn2'].value[1].value[3].value[0].value, '23')
st.equal(decoded['dyn2'].value[1].value[1].value[1].value, '-23') st.equal(decoded['dyn2'].value[1].value[3].value[1].value, '-23')
st.equal(decoded['dyn2'].value[1].value[1].value[2].value, '-28') st.equal(decoded['dyn2'].value[1].value[3].value[2].value, '-28')
st.equal(decoded['dyn2'].value[1].value[2].value[0].value, '23') st.equal(decoded['arrayStruct'].value[0].value[0].value.i8.value, '34')
st.equal(decoded['dyn2'].value[1].value[2].value[1].value, '-23') st.equal(decoded['arrayStruct'].value[0].value[0].value.str.value, 'test_str_short')
st.equal(decoded['dyn2'].value[1].value[2].value[2].value, '-28') st.equal(decoded['arrayStruct'].value[0].value[1].value.i8.value, '-123')
st.equal(decoded['dyn2'].value[1].value[3].value[0].value, '23') st.equal(decoded['arrayStruct'].value[0].value[1].value.str.value, 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long')
st.equal(decoded['dyn2'].value[1].value[3].value[1].value, '-23') st.equal(decoded['arrayStruct'].value[1].value[0].value.i8.value, '50')
st.equal(decoded['dyn2'].value[1].value[3].value[2].value, '-28') st.equal(decoded['arrayStruct'].value[1].value[0].value.str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[0].value[0].value.i8.value, '34') st.equal(decoded['arrayStruct'].value[2].value[0].value.i8.value, '60')
st.equal(decoded['arrayStruct'].value[0].value[0].value.str.value, 'test_str_short') st.equal(decoded['arrayStruct'].value[2].value[0].value.str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[0].value[1].value.i8.value, '-123') st.equal(decoded['arrayStruct'].value[2].value[1].value.i8.value, '84')
st.equal(decoded['arrayStruct'].value[0].value[1].value.str.value, 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long') st.equal(decoded['arrayStruct'].value[2].value[1].value.str.value, 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long')
st.equal(decoded['arrayStruct'].value[1].value[0].value.i8.value, '50') st.equal(decoded['arrayStruct'].value[2].value[2].value.i8.value, '-34')
st.equal(decoded['arrayStruct'].value[1].value[0].value.str.value, 'test_str_short') st.equal(decoded['arrayStruct'].value[2].value[2].value.str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[2].value[0].value.i8.value, '60') cb()
st.equal(decoded['arrayStruct'].value[2].value[0].value.str.value, 'test_str_short') })
st.equal(decoded['arrayStruct'].value[2].value[1].value.i8.value, '84')
st.equal(decoded['arrayStruct'].value[2].value[1].value.str.value, 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long')
st.equal(decoded['arrayStruct'].value[2].value[2].value.i8.value, '-34')
st.equal(decoded['arrayStruct'].value[2].value[2].value.str.value, 'test_str_short')
} }
...@@ -53,13 +53,12 @@ tape('TraceManager', function (t) { ...@@ -53,13 +53,12 @@ tape('TraceManager', function (t) {
st.end() st.end()
}) })
t.test('TraceManager.getStorageAt', function (st) { t.test('TraceManager.accumulateStorageChanges', function (st) {
var tx = util.web3.eth.getTransaction('0x20ef65b8b186ca942fcccd634f37074dde49b541c27994fc7596740ef44cfd51') traceManager.accumulateStorageChanges(110, '0x0d3a18d64dfe4f927832ab58d6451cecc4e517c5', {}, function (error, result) {
traceManager.getStorageAt(110, tx, function (error, result) {
if (error) { if (error) {
st.fail(error) st.fail(error)
} else { } else {
st.ok(result['0x00'] === '0x38') st.ok(result['0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'].value === '0x38')
st.end() st.end()
} }
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment