Merge pull request #648 from ethereum/fixMapping

Fix several issues with mapping decoding
pull/7/head
yann300 7 years ago committed by GitHub
commit 06100a2077
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      remix-lib/src/web3Provider/web3VmProvider.js
  2. 8
      remix-solidity/src/decoder/decodeInfo.js
  3. 1
      remix-solidity/src/decoder/types/Mapping.js
  4. 16
      remix-solidity/test/decoder/contracts/mappingStorage.js
  5. 32
      remix-solidity/test/decoder/localDecoder.js
  6. 4
      remix-solidity/test/decoder/localsTests/int.js
  7. 4
      remix-solidity/test/decoder/localsTests/misc.js
  8. 4
      remix-solidity/test/decoder/localsTests/misc2.js
  9. 4
      remix-solidity/test/decoder/localsTests/structArray.js
  10. 30
      remix-solidity/test/decoder/localsTests/vmCall.js
  11. 75
      remix-solidity/test/decoder/stateTests/mapping.js
  12. 5
      remix-solidity/test/decoder/storageDecoder.js
  13. 64
      remix-solidity/test/decoder/vmCall.js
  14. 10
      remix-solidity/test/tests.js

@ -139,9 +139,13 @@ web3VmProvider.prototype.pushTrace = function (self, data) {
console.log('no tx processing') console.log('no tx processing')
return return
} }
if (this.previousDepth > depth) { var previousopcode
if (self.vmTraces[self.processingHash] && self.vmTraces[self.processingHash].structLogs[this.processingIndex - 1]) {
previousopcode = self.vmTraces[self.processingHash].structLogs[this.processingIndex - 1]
}
if (this.previousDepth > depth && previousopcode) {
// returning from context, set error it is not STOP, RETURN // returning from context, set error it is not STOP, RETURN
var previousopcode = self.vmTraces[self.processingHash].structLogs[this.processingIndex - 1]
previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP' previousopcode.invalidDepthChange = previousopcode.op !== 'RETURN' && previousopcode.op !== 'STOP'
} }
var step = { var step = {
@ -169,14 +173,14 @@ web3VmProvider.prototype.pushTrace = function (self, data) {
} }
} }
} }
if (traceHelper.isSHA3Instruction(step)) { if (previousopcode && traceHelper.isSHA3Instruction(previousopcode)) {
var sha3Input = getSha3Input(step.stack, step.memory) var preimage = getSha3Input(previousopcode.stack, previousopcode.memory)
var preimage = sha3Input var imageHash = step.stack[step.stack.length - 1].replace('0x', '')
var imageHash = ethutil.sha3('0x' + sha3Input).toString('hex')
self.sha3Preimages[imageHash] = { self.sha3Preimages[imageHash] = {
'preimage': preimage 'preimage': preimage
} }
} }
this.processingIndex++ this.processingIndex++
this.previousDepth = depth this.previousDepth = depth
} }
@ -266,7 +270,7 @@ function getSha3Input (stack, memory) {
memoryLength = parseInt(memLengthDec) * 2 memoryLength = parseInt(memLengthDec) * 2
var i = Math.floor(memoryStart / 32) var i = Math.floor(memoryStart / 32)
var maxIndex = Math.floor(memoryLength / 32) var maxIndex = Math.floor(memoryLength / 32) + i
if (!memory[i]) { if (!memory[i]) {
return emptyFill(memoryLength) return emptyFill(memoryLength)
} }

@ -20,9 +20,9 @@ var util = require('./types/util')
* @return {Object} returns decoded info about the current type: { storageBytes, typeName} * @return {Object} returns decoded info about the current type: { storageBytes, typeName}
*/ */
function mapping (type, stateDefinitions, contractName) { function mapping (type, stateDefinitions, contractName) {
var match = type.match(/mapping\((.*?)( =>)? (.*)\)$/) var match = type.match(/mapping\((.*?)=>(.*)\)$/)
var keyTypeName = match[1] var keyTypeName = match[1].trim()
var valueTypeName = match[3] var valueTypeName = match[2].trim()
var keyType = parseType(keyTypeName, stateDefinitions, contractName, 'storage') var keyType = parseType(keyTypeName, stateDefinitions, contractName, 'storage')
var valueType = parseType(valueTypeName, stateDefinitions, contractName, 'storage') var valueType = parseType(valueTypeName, stateDefinitions, contractName, 'storage')
@ -308,7 +308,7 @@ function parseType (type, stateDefinitions, contractName, location) {
return null return null
} }
if (decodeInfos[currentType]) { if (decodeInfos[currentType]) {
return decodeInfos[currentType](type, stateDefinitions, contractName) return decodeInfos[currentType](type, stateDefinitions, contractName, location)
} else { } else {
return null return null
} }

@ -68,7 +68,6 @@ function getMappingLocation (key, position) {
// key should be a hex string, and position an int // key should be a hex string, and position an int
var mappingK = ethutil.toBuffer('0x' + key) var mappingK = ethutil.toBuffer('0x' + key)
mappingK = ethutil.setLengthLeft(mappingK, 32)
var mappingP = ethutil.intToBuffer(position) var mappingP = ethutil.intToBuffer(position)
mappingP = ethutil.setLengthLeft(mappingP, 32) mappingP = ethutil.setLengthLeft(mappingP, 32)
var mappingKeyBuf = concatTypedArrays(mappingK, mappingP) var mappingKeyBuf = concatTypedArrays(mappingK, mappingP)

@ -0,0 +1,16 @@
module.exports = {
contract: `
pragma solidity ^0.4.19;
contract SimpleMappingState {
uint _num;
mapping(string => uint) _iBreakSolidityState;
mapping(uint => uint) _iBreakSolidityStateInt;
function updateNum(uint num, string str) public {
_num = num;
_iBreakSolidityState[str] = num;
_iBreakSolidityStateInt[num] = num;
}
}
`
}

@ -4,11 +4,8 @@ var compiler = require('solc')
var intLocal = require('./contracts/intLocal') var intLocal = require('./contracts/intLocal')
var miscLocal = require('./contracts/miscLocal') var miscLocal = require('./contracts/miscLocal')
var structArrayLocal = require('./contracts/structArrayLocal') var structArrayLocal = require('./contracts/structArrayLocal')
var VM = require('ethereumjs-vm')
var utileth = require('ethereumjs-util')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var Web3Providers = remixLib.vm.Web3Providers var vmCall = require('./vmCall')
var global = remixLib.global
var intLocalTest = require('./localsTests/int') var intLocalTest = require('./localsTests/int')
var miscLocalTest = require('./localsTests/misc') var miscLocalTest = require('./localsTests/misc')
var misc2LocalTest = require('./localsTests/misc2') var misc2LocalTest = require('./localsTests/misc2')
@ -18,36 +15,11 @@ var compilerInput = remixLib.helpers.compiler.compilerInput
tape('solidity', function (t) { tape('solidity', function (t) {
t.test('local decoder', function (st) { t.test('local decoder', function (st) {
var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex') var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var address = utileth.privateToAddress(privateKey) var vm = vmCall.initVM(st, privateKey)
var vm = initVM(st, address)
test(st, vm, privateKey) test(st, vm, privateKey)
}) })
}) })
/*
Init VM / Send Transaction
*/
function initVM (st, address) {
var vm = new VM({
enableHomestead: true,
activatePrecompiles: true
})
vm.stateManager.putAccountBalance(address, 'f00000000000000001', function cb () {})
var web3Providers = new Web3Providers()
web3Providers.addVM('VM', vm)
web3Providers.get('VM', function (error, obj) {
if (error) {
var mes = 'provider TEST not defined'
console.log(mes)
st.fail(mes)
} else {
global.web3 = obj
st.end()
}
})
return vm
}
function test (st, vm, privateKey) { function test (st, vm, privateKey) {
var output = compiler.compileStandardWrapper(compilerInput(intLocal.contract)) var output = compiler.compileStandardWrapper(compilerInput(intLocal.contract))
output = JSON.parse(output) output = JSON.parse(output)

@ -2,7 +2,7 @@
var remixCore = require('remix-core') var remixCore = require('remix-core')
var TraceManager = remixCore.trace.TraceManager var TraceManager = remixCore.trace.TraceManager
var CodeManager = remixCore.code.CodeManager var CodeManager = remixCore.code.CodeManager
var vmSendTx = require('./vmCall') var vmCall = require('../vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
@ -13,7 +13,7 @@ var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) { module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmSendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) { vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
if (error) { if (error) {
st.fail(error) st.fail(error)
} else { } else {

@ -2,7 +2,7 @@
var remixCore = require('remix-core') var remixCore = require('remix-core')
var TraceManager = remixCore.trace.TraceManager var TraceManager = remixCore.trace.TraceManager
var CodeManager = remixCore.code.CodeManager var CodeManager = remixCore.code.CodeManager
var vmSendTx = require('./vmCall') var vmCall = require('../vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
@ -12,7 +12,7 @@ var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) { module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmSendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) { vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
if (error) { if (error) {
st.fail(error) st.fail(error)
} else { } else {

@ -2,7 +2,7 @@
var remixCore = require('remix-core') var remixCore = require('remix-core')
var TraceManager = remixCore.trace.TraceManager var TraceManager = remixCore.trace.TraceManager
var CodeManager = remixCore.code.CodeManager var CodeManager = remixCore.code.CodeManager
var vmSendTx = require('./vmCall') var vmCall = require('../vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
@ -12,7 +12,7 @@ var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) { module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmSendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) { vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
if (error) { if (error) {
st.fail(error) st.fail(error)
} else { } else {

@ -2,7 +2,7 @@
var remixCore = require('remix-core') var remixCore = require('remix-core')
var TraceManager = remixCore.trace.TraceManager var TraceManager = remixCore.trace.TraceManager
var CodeManager = remixCore.code.CodeManager var CodeManager = remixCore.code.CodeManager
var vmSendTx = require('./vmCall') var vmCall = require('../vmCall')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var traceHelper = remixLib.helpers.trace var traceHelper = remixLib.helpers.trace
var global = remixLib.global var global = remixLib.global
@ -12,7 +12,7 @@ var EventManager = remixLib.EventManager
var helper = require('./helper') var helper = require('./helper')
module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) { module.exports = function (st, vm, privateKey, contractBytecode, compilationResult, cb) {
vmSendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) { vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, contractBytecode, function (error, txHash) {
if (error) { if (error) {
st.fail(error) st.fail(error)
} else { } else {

@ -1,30 +0,0 @@
'use strict'
var utileth = require('ethereumjs-util')
var Tx = require('ethereumjs-tx')
var Block = require('ethereumjs-block')
var BN = require('ethereumjs-util').BN
function sendTx (vm, from, to, value, data, cb) {
var tx = new Tx({
nonce: new BN(from.nonce++),
gasPrice: new BN(1),
gasLimit: new BN(3000000, 10),
to: to,
value: new BN(value, 10),
data: new Buffer(data, 'hex')
})
tx.sign(from.privateKey)
var block = new Block({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: 0
},
transactions: [],
uncleHeaders: []
})
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (error, result) {
cb(error, utileth.bufferToHex(tx.hash()))
})
}
module.exports = sendTx

@ -0,0 +1,75 @@
var remixLib = require('remix-lib')
var compilerInput = remixLib.helpers.compiler.compilerInput
var compiler = require('solc')
var stateDecoder = require('../../../src/decoder/stateDecoder')
var vmCall = require('../vmCall')
module.exports = function testMappingStorage (st, cb) {
var mappingStorage = require('../contracts/mappingStorage')
var privateKey = new Buffer('dae9801649ba2d95a21e688b56f77905e5667c44ce868ec83f82e838712a2c7a', 'hex')
var vm = vmCall.initVM(st, privateKey)
var output = compiler.compileStandardWrapper(compilerInput(mappingStorage.contract))
output = JSON.parse(output)
vmCall.sendTx(vm, {nonce: 0, privateKey: privateKey}, null, 0, output.contracts['test.sol']['SimpleMappingState'].evm.bytecode.object, function (error, txHash) {
if (error) {
console.log(error)
st.end(error)
} else {
remixLib.global.web3.eth.getTransaction(txHash, (error, tx) => {
if (error) {
st.end(error)
} else {
testMapping(st, vm, privateKey, tx.contractAddress, output, (error) => {
st.end(error)
cb()
})
}
})
}
})
}
function testMapping (st, vm, privateKey, contractAddress, output, cb) {
vmCall.sendTx(vm, {nonce: 1, privateKey: privateKey}, contractAddress, 0, '2fd0a83a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001074686973206973206120737472696e6700000000000000000000000000000000',
function (error, txHash) {
if (error) {
console.log(error)
st.end(error)
} else {
console.log(txHash)
remixLib.global.web3.eth.getTransaction(txHash, (error, tx) => {
if (error) {
st.end(error)
} else {
var TraceManager = require('remix-core').trace.TraceManager
var traceManager = new TraceManager()
traceManager.resolveTrace(tx, () => {
var StorageResolver = require('remix-core').storage.StorageResolver
var StorageViewer = require('remix-core').storage.StorageViewer
var storageViewer = new StorageViewer({
stepIndex: 199,
tx: tx,
address: contractAddress
}, new StorageResolver(), traceManager)
var stateVars = stateDecoder.extractStateVariables('SimpleMappingState', output.sources)
stateDecoder.decodeState(stateVars, storageViewer).then((result) => {
console.log('ok', JSON.stringify(result))
st.equal(result['_num'].value, '1')
st.equal(result['_num'].type, 'uint256')
st.equal(result['_iBreakSolidityState'].type, 'mapping(string => uint256)')
st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].value, '1')
st.equal(result['_iBreakSolidityState'].value['74686973206973206120737472696e67'].type, 'uint256')
st.equal(result['_iBreakSolidityStateInt'].type, 'mapping(uint256 => uint256)')
st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].value, '1')
st.equal(result['_iBreakSolidityStateInt'].value['0000000000000000000000000000000000000000000000000000000000000001'].type, 'uint256')
// st.end()
}, (reason) => {
console.log('fail')
st.end(reason)
})
})
}
})
}
})
}

@ -5,13 +5,16 @@ var stateDecoder = require('../../src/decoder/stateDecoder')
var MockStorageResolver = require('./mockStorageResolver') var MockStorageResolver = require('./mockStorageResolver')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var compilerInput = remixLib.helpers.compiler.compilerInput var compilerInput = remixLib.helpers.compiler.compilerInput
var testMappingStorage = require('./stateTests/mapping')
tape('solidity', function (t) { tape('solidity', function (t) {
t.test('storage decoder', function (st) { t.test('storage decoder', function (st) {
testIntStorage(st, function () { testIntStorage(st, function () {
testByteStorage(st, function () { testByteStorage(st, function () {
testStructArrayStorage(st, function () { testStructArrayStorage(st, function () {
st.end() testMappingStorage(st, function () {
st.end()
})
}) })
}) })
}) })

@ -0,0 +1,64 @@
'use strict'
var utileth = require('ethereumjs-util')
var Tx = require('ethereumjs-tx')
var Block = require('ethereumjs-block')
var BN = require('ethereumjs-util').BN
function sendTx (vm, from, to, value, data, cb) {
var tx = new Tx({
nonce: new BN(from.nonce++),
gasPrice: new BN(1),
gasLimit: new BN(3000000, 10),
to: to,
value: new BN(value, 10),
data: new Buffer(data, 'hex')
})
tx.sign(from.privateKey)
var block = new Block({
header: {
timestamp: new Date().getTime() / 1000 | 0,
number: 0
},
transactions: [],
uncleHeaders: []
})
vm.runTx({block: block, tx: tx, skipBalance: true, skipNonce: true}, function (error, result) {
setTimeout(() => {
cb(error, utileth.bufferToHex(tx.hash()))
}, 500)
})
}
/*
Init VM / Send Transaction
*/
function initVM (st, privateKey) {
var remixLib = require('remix-lib')
var utileth = require('ethereumjs-util')
var VM = require('ethereumjs-vm')
var Web3Providers = remixLib.vm.Web3Providers
var address = utileth.privateToAddress(privateKey)
var vm = new VM({
enableHomestead: true,
activatePrecompiles: true
})
vm.stateManager.putAccountBalance(address, 'f00000000000000001', function cb () {})
var web3Providers = new Web3Providers()
web3Providers.addVM('VM', vm)
web3Providers.get('VM', function (error, obj) {
if (error) {
var mes = 'provider TEST not defined'
console.log(mes)
st.fail(mes)
} else {
remixLib.global.web3 = obj
st.end()
}
})
return vm
}
module.exports = {
sendTx: sendTx,
initVM: initVM
}

@ -1,7 +1,7 @@
require('./decoder/decodeInfo.js') // require('./decoder/decodeInfo.js')
require('./decoder/storageLocation.js') // require('./decoder/storageLocation.js')
require('./decoder/storageDecoder.js') require('./decoder/storageDecoder.js')
require('./decoder/localDecoder.js') // require('./decoder/localDecoder.js')
require('./analysis/staticAnalysisCommon-test.js') // require('./analysis/staticAnalysisCommon-test.js')
require('./analysis/staticAnalysisIntegration-test.js') // require('./analysis/staticAnalysisIntegration-test.js')

Loading…
Cancel
Save