Merge pull request #143 from ethereum/decodeArrayStruct

Decode Array/Struct [WIP]
pull/7/head
chriseth 8 years ago committed by GitHub
commit 30f2c0c6e0
  1. 34
      src/solidity/types/ArrayType.js
  2. 11
      src/solidity/types/Struct.js
  3. 20
      src/solidity/types/util.js
  4. 204
      test/solidity/contracts/structArrayStorage.js
  5. 98
      test/solidity/storageDecoder.js

@ -1,4 +1,6 @@
'use strict'
var util = require('./util')
var BN = require('ethereumjs-util').BN
function ArrayType (underlyingType, arraySize) {
this.typeName = 'array'
@ -19,7 +21,37 @@ function ArrayType (underlyingType, arraySize) {
}
ArrayType.prototype.decodeFromStorage = function (location, storageContent) {
return '<not implemented yet>'
var ret = []
var size = null
var slotValue = util.extractHexValue(location, storageContent, this.storageBytes)
var currentLocation = {
offset: 0,
slot: location.slot
}
if (this.arraySize === 'dynamic') {
size = util.toBN('0x' + slotValue)
currentLocation.slot = util.sha3(location.slot)
} else {
size = new BN(this.arraySize)
}
var k = util.toBN(0)
for (; k.lt(size) && k.ltn(300); k.iaddn(1)) {
ret.push(this.underlyingType.decodeFromStorage(currentLocation, storageContent))
if (this.underlyingType.storageSlots === 1 && location.offset + this.underlyingType.storageBytes <= 32) {
currentLocation.offset += this.underlyingType.storageBytes
if (currentLocation.offset + this.underlyingType.storageBytes > 32) {
currentLocation.offset = 0
currentLocation.slot = '0x' + util.add(currentLocation.slot, 1).toString(16)
}
} else {
currentLocation.slot = '0x' + util.add(currentLocation.slot, this.underlyingType.storageSlots).toString(16)
currentLocation.offset = 0
}
}
return {
value: ret,
length: '0x' + size.toString(16)
}
}
module.exports = ArrayType

@ -1,4 +1,5 @@
'use strict'
var util = require('./util')
function Struct (memberDetails) {
this.storageSlots = memberDetails.storageSlots
@ -8,7 +9,15 @@ function Struct (memberDetails) {
}
Struct.prototype.decodeFromStorage = function (location, storageContent) {
return '<not implemented yet>'
var ret = {}
this.members.map(function (item, i) {
var globalLocation = {
offset: location.offset + item.location.offset,
slot: util.add(location.slot, item.location.slot)
}
ret[item.name] = item.type.decodeFromStorage(globalLocation, storageContent)
})
return ret
}
module.exports = Struct

@ -6,7 +6,9 @@ module.exports = {
readFromStorage: readFromStorage,
decodeInt: decodeInt,
extractHexValue: extractHexValue,
sha3: sha3
sha3: sha3,
toBN: toBN,
add: add
}
function decodeInt (location, storageContent, byteLength, signed) {
@ -67,3 +69,19 @@ function sha3 (slot) {
var key = ethutil.sha3(remoteSlot)
return ethutil.bufferToHex(key)
}
function toBN (value) {
if (value instanceof BN) {
return value
} else if (value.indexOf && value.indexOf('0x') === 0) {
value = ethutil.unpad(value.replace('Ox', ''))
value = new BN(value === '' ? '0' : value, 16)
} else if (!isNaN(value)) {
value = new BN(value)
}
return value
}
function add (value1, value2) {
return toBN(value1).add(toBN(value2))
}

@ -0,0 +1,204 @@
'use strict'
module.exports = {
contract: `contract structArrayStorage {
struct intStruct {
int8 i8;
int16 i16;
uint32 ui32;
int i256;
uint16 ui16;
int32 i32;
}
intStruct intStructDec;
int64[7] i5;
int64[] idyn5;
int32[][4] dyn1;
int32[][4][] dyn2;
struct simpleStruct {
int8 i8;
string str;
}
simpleStruct[][3] arrayStruct;
function structArrayStorage () {
intStructDec.i8 = 32;
intStructDec.i16 = -54;
intStructDec.ui32 = 128;
intStructDec.i256 = -1243565465756;
intStructDec.ui16 = 34556;
intStructDec.i32 = -345446546;
i5[0] = -2134;
i5[1] = 345;
i5[2] = -3246;
i5[3] = 4357;
i5[4] = 324;
i5[5] = -2344;
i5[6] = 3254;
idyn5.length = 9;
idyn5[0] = -2134;
idyn5[1] = 345;
idyn5[2] = -3246;
idyn5[3] = 4357;
idyn5[4] = 324;
idyn5[5] = -2344;
idyn5[6] = 3254;
idyn5[7] = -254;
idyn5[8] = -2354;
dyn1[0].length = 1;
dyn1[1].length = 3;
dyn1[2].length = 10;
dyn1[3].length = 2;
dyn1[0][0] = 3;
dyn1[1][0] = 12;
dyn1[1][1] = -12;
dyn1[1][2] = -1234;
dyn1[2][0] = 1;
dyn1[2][1] = 12;
dyn1[2][2] = 1235;
dyn1[2][3] = -12;
dyn1[2][4] = -123456;
dyn1[2][5] = -23435435;
dyn1[2][6] = 543543;
dyn1[2][7] = 2;
dyn1[2][8] = -1;
dyn1[2][9] = 232432;
dyn1[3][0] = 232432;
dyn1[3][1] = 232432;
dyn2.length = 2;
dyn2[0][0].length = 3;
dyn2[0][1].length = 3;
dyn2[0][2].length = 3;
dyn2[0][3].length = 3;
dyn2[1][0].length = 3;
dyn2[1][1].length = 3;
dyn2[1][2].length = 3;
dyn2[1][3].length = 3;
dyn2[0][0][0] = 23;
dyn2[0][0][1] = -23;
dyn2[0][0][2] = -28;
dyn2[0][1][0] = 23;
dyn2[0][1][1] = -23;
dyn2[0][1][2] = -28;
dyn2[0][2][0] = 23;
dyn2[0][2][1] = -23;
dyn2[0][2][2] = -28;
dyn2[0][3][0] = 23;
dyn2[0][3][1] = -23;
dyn2[0][3][2] = -28;
dyn2[1][0][0] = 23;
dyn2[1][0][1] = -23;
dyn2[1][0][2] = -28;
dyn2[1][1][0] = 23;
dyn2[1][1][1] = -23;
dyn2[1][1][2] = -28;
dyn2[1][2][0] = 23;
dyn2[1][2][1] = -23;
dyn2[1][2][2] = -28;
dyn2[1][3][0] = 23;
dyn2[1][3][1] = -23;
dyn2[1][3][2] = -28;
arrayStruct[0].length = 2;
arrayStruct[1].length = 1;
arrayStruct[2].length = 3;
arrayStruct[0][0].i8 = 34;
arrayStruct[0][0].str = 'test_str_short';
arrayStruct[0][1].i8 = -123;
arrayStruct[0][1].str = 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long';
arrayStruct[1][0].i8 = 50;
arrayStruct[1][0].str = 'test_str_short';
arrayStruct[2][0].i8 = 60;
arrayStruct[2][0].str = 'test_str_short';
arrayStruct[2][1].i8 = 84;
arrayStruct[2][1].str = 'test_str_long test_str_lo ngtest_str_longtest_str_ longtest_str_longtest_ str_longtest_str_l ongtest_str_long';
arrayStruct[2][2].i8 = -34;
arrayStruct[2][2].str = 'test_str_short';
}
}
`,
storage: {
'0x0000000000000000000000000000000000000000000000000000000000000000': '0x0000000000000000000000000000000000000000000000000000000080ffca20',
'0x0000000000000000000000000000000000000000000000000000000000000001': '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffede75b8df64',
'0x0000000000000000000000000000000000000000000000000000000000000002': '0x0000000000000000000000000000000000000000000000000000eb68e76e86fc',
'0x0000000000000000000000000000000000000000000000000000000000000003': '0x0000000000001105fffffffffffff3520000000000000159fffffffffffff7aa',
'0x0000000000000000000000000000000000000000000000000000000000000004': '0x00000000000000000000000000000cb6fffffffffffff6d80000000000000144',
'0x0000000000000000000000000000000000000000000000000000000000000005': '0x0000000000000000000000000000000000000000000000000000000000000009',
'0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0': '0x0000000000001105fffffffffffff3520000000000000159fffffffffffff7aa',
'0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db1': '0xffffffffffffff020000000000000cb6fffffffffffff6d80000000000000144',
'0x036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db2': '0x000000000000000000000000000000000000000000000000fffffffffffff6ce',
'0x0000000000000000000000000000000000000000000000000000000000000006': '0x0000000000000000000000000000000000000000000000000000000000000001',
'0x0000000000000000000000000000000000000000000000000000000000000007': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0x0000000000000000000000000000000000000000000000000000000000000008': '0x000000000000000000000000000000000000000000000000000000000000000a',
'0x0000000000000000000000000000000000000000000000000000000000000009': '0x0000000000000000000000000000000000000000000000000000000000000002',
'0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688': '0x0000000000000000000000000000000000000000fffffb2efffffff40000000c',
'0xf3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3': '0x0000000200084b37fe9a6755fffe1dc0fffffff4000004d30000000c00000001',
'0xf3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee4': '0x00000000000000000000000000000000000000000000000000038bf0ffffffff',
'0x6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af': '0x00000000000000000000000000000000000000000000000000038bf000038bf0',
'0x000000000000000000000000000000000000000000000000000000000000000a': '0x0000000000000000000000000000000000000000000000000000000000000002',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a9': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2aa': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ab': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ac': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ad': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ae': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0xc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2af': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0x410c2796757c1866e144712b649ab035b22d7295530f125d2b7bc17fa7b793b5': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0x06b493c1ca289c5326ef56c162cd187bf96c737c2c9bbda318cc345be15042af': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0x7a0b543a77c72a2154fae01417d93ab4a7f07c9a6bbce5febfeb9904a41b7914': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0x5370eae143cc2f6260640bd734b0cdaf587bbcfc81362df39d56d5a29a7e663b': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0xd5211e5652076f058928f5b24e1816690291c298b337ea927f8d0f3aabb8a05a': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0xf232dee5d9edbb879fab95c81a3867fe42b8d79b05e9c99336c5297487f94e8d': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0x8a82e6d20ae2c2a82dd8e575dac6354ce964fd35e3d1cdb79bb1757c6a7675b6': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0xa9e6724ab7d0ccf2de69222bc5703c9df2049038736e6d57f437315272b76a3a': '0x0000000000000000000000000000000000000000ffffffe4ffffffe900000017',
'0x000000000000000000000000000000000000000000000000000000000000000b': '0x0000000000000000000000000000000000000000000000000000000000000002',
'0x000000000000000000000000000000000000000000000000000000000000000c': '0x0000000000000000000000000000000000000000000000000000000000000001',
'0x000000000000000000000000000000000000000000000000000000000000000d': '0x0000000000000000000000000000000000000000000000000000000000000003',
'0x0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9': '0x0000000000000000000000000000000000000000000000000000000000000022',
'0x0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba': '0x746573745f7374725f73686f727400000000000000000000000000000000001c',
'0x0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb': '0x0000000000000000000000000000000000000000000000000000000000000085',
'0x0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbc': '0x00000000000000000000000000000000000000000000000000000000000000db',
'0x40abea1508c7557b93b3e219e777ce8530b60f9f8452ef1c627dbc62b53708fc': '0x746573745f7374725f6c6f6e6720746573745f7374725f6c6f206e6774657374',
'0x40abea1508c7557b93b3e219e777ce8530b60f9f8452ef1c627dbc62b53708fd': '0x5f7374725f6c6f6e67746573745f7374725f206c6f6e67746573745f7374725f',
'0x40abea1508c7557b93b3e219e777ce8530b60f9f8452ef1c627dbc62b53708fe': '0x6c6f6e67746573745f207374725f6c6f6e67746573745f7374725f6c206f6e67',
'0x40abea1508c7557b93b3e219e777ce8530b60f9f8452ef1c627dbc62b53708ff': '0x746573745f7374725f6c6f6e6700000000000000000000000000000000000000',
'0xdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7': '0x0000000000000000000000000000000000000000000000000000000000000032',
'0xdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c8': '0x746573745f7374725f73686f727400000000000000000000000000000000001c',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5': '0x000000000000000000000000000000000000000000000000000000000000003c',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb6': '0x746573745f7374725f73686f727400000000000000000000000000000000001c',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb7': '0x0000000000000000000000000000000000000000000000000000000000000054',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb8': '0x00000000000000000000000000000000000000000000000000000000000000db',
'0x87466a1ae97409dd9d9cd9368751b439509d8b3f8fc2bb47a4264e5d6fd4d324': '0x746573745f7374725f6c6f6e6720746573745f7374725f6c6f206e6774657374',
'0x87466a1ae97409dd9d9cd9368751b439509d8b3f8fc2bb47a4264e5d6fd4d325': '0x5f7374725f6c6f6e67746573745f7374725f206c6f6e67746573745f7374725f',
'0x87466a1ae97409dd9d9cd9368751b439509d8b3f8fc2bb47a4264e5d6fd4d326': '0x6c6f6e67746573745f207374725f6c6f6e67746573745f7374725f6c206f6e67',
'0x87466a1ae97409dd9d9cd9368751b439509d8b3f8fc2bb47a4264e5d6fd4d327': '0x746573745f7374725f6c6f6e6700000000000000000000000000000000000000',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb9': '0x00000000000000000000000000000000000000000000000000000000000000de',
'0xd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eba': '0x746573745f7374725f73686f727400000000000000000000000000000000001c'
}
}

@ -7,6 +7,7 @@ tape('solidity', function (t) {
t.test('storage decoder', function (st) {
testIntStorage(st)
testByteStorage(st)
testStructArrayStorage(st)
st.end()
})
})
@ -156,3 +157,100 @@ function shrinkStorage (storage) {
}
return shrinkedStorage
}
function testStructArrayStorage (st) {
var structArrayStorage = require('./contracts/structArrayStorage')
var output = compiler.compile(structArrayStorage.contract, 0)
var decoded = stateDecoder.solidityState(structArrayStorage.storage, output.sources, 'structArrayStorage')
st.equal(decoded['intStructDec']['i8'], '32')
st.equal(decoded['intStructDec']['i16'], '-54')
st.equal(decoded['intStructDec']['ui32'], '128')
st.equal(decoded['intStructDec']['i256'], '-1243565465756')
st.equal(decoded['intStructDec']['ui16'], '34556')
st.equal(decoded['intStructDec']['i32'], '-345446546')
st.equal(decoded['i5'].length, '0x7')
st.equal(decoded['i5'].value[0], '-2134')
st.equal(decoded['i5'].value[1], '345')
st.equal(decoded['i5'].value[2], '-3246')
st.equal(decoded['i5'].value[3], '4357')
st.equal(decoded['i5'].value[4], '324')
st.equal(decoded['i5'].value[5], '-2344')
st.equal(decoded['i5'].value[6], '3254')
st.equal(decoded['idyn5'].length, '0x9')
st.equal(decoded['idyn5'].value[0], '-2134')
st.equal(decoded['idyn5'].value[1], '345')
st.equal(decoded['idyn5'].value[2], '-3246')
st.equal(decoded['idyn5'].value[3], '4357')
st.equal(decoded['idyn5'].value[4], '324')
st.equal(decoded['idyn5'].value[5], '-2344')
st.equal(decoded['idyn5'].value[6], '3254')
st.equal(decoded['idyn5'].value[7], '-254')
st.equal(decoded['idyn5'].value[8], '-2354')
st.equal(decoded['dyn1'].length, '0x4')
st.equal(decoded['dyn1'].value[0].length, '0x1')
st.equal(decoded['dyn1'].value[0].value[0], '3')
st.equal(decoded['dyn1'].value[1].length, '0x3')
st.equal(decoded['dyn1'].value[1].value[0], '12')
st.equal(decoded['dyn1'].value[1].value[1], '-12')
st.equal(decoded['dyn1'].value[1].value[2], '-1234')
st.equal(decoded['dyn1'].value[2].length, '0xa')
st.equal(decoded['dyn1'].value[2].value[0], '1')
st.equal(decoded['dyn1'].value[2].value[1], '12')
st.equal(decoded['dyn1'].value[2].value[2], '1235')
st.equal(decoded['dyn1'].value[2].value[3], '-12')
st.equal(decoded['dyn1'].value[2].value[4], '-123456')
st.equal(decoded['dyn1'].value[2].value[5], '-23435435')
st.equal(decoded['dyn1'].value[2].value[6], '543543')
st.equal(decoded['dyn1'].value[2].value[7], '2')
st.equal(decoded['dyn1'].value[2].value[8], '-1')
st.equal(decoded['dyn1'].value[2].value[9], '232432')
st.equal(decoded['dyn1'].value[3].length, '0x2')
st.equal(decoded['dyn1'].value[3].value[0], '232432')
st.equal(decoded['dyn1'].value[3].value[0], '232432')
st.equal(decoded['dyn2'].length, '0x2')
st.equal(decoded['dyn2'].value[0].length, '0x4')
st.equal(decoded['dyn2'].value[0].value[0].value[0], '23')
st.equal(decoded['dyn2'].value[0].value[0].value[1], '-23')
st.equal(decoded['dyn2'].value[0].value[0].value[2], '-28')
st.equal(decoded['dyn2'].value[0].value[1].value[0], '23')
st.equal(decoded['dyn2'].value[0].value[1].value[1], '-23')
st.equal(decoded['dyn2'].value[0].value[1].value[2], '-28')
st.equal(decoded['dyn2'].value[0].value[2].value[0], '23')
st.equal(decoded['dyn2'].value[0].value[2].value[1], '-23')
st.equal(decoded['dyn2'].value[0].value[2].value[2], '-28')
st.equal(decoded['dyn2'].value[0].value[3].value[0], '23')
st.equal(decoded['dyn2'].value[0].value[3].value[1], '-23')
st.equal(decoded['dyn2'].value[0].value[3].value[2], '-28')
st.equal(decoded['dyn2'].value[1].length, '0x4')
st.equal(decoded['dyn2'].value[1].value[0].value[0], '23')
st.equal(decoded['dyn2'].value[1].value[0].value[1], '-23')
st.equal(decoded['dyn2'].value[1].value[0].value[2], '-28')
st.equal(decoded['dyn2'].value[1].value[1].value[0], '23')
st.equal(decoded['dyn2'].value[1].value[1].value[1], '-23')
st.equal(decoded['dyn2'].value[1].value[1].value[2], '-28')
st.equal(decoded['dyn2'].value[1].value[2].value[0], '23')
st.equal(decoded['dyn2'].value[1].value[2].value[1], '-23')
st.equal(decoded['dyn2'].value[1].value[2].value[2], '-28')
st.equal(decoded['dyn2'].value[1].value[3].value[0], '23')
st.equal(decoded['dyn2'].value[1].value[3].value[1], '-23')
st.equal(decoded['dyn2'].value[1].value[3].value[2], '-28')
st.equal(decoded['arrayStruct'].value[0].value[0].i8, '34')
st.equal(decoded['arrayStruct'].value[0].value[0].str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[0].value[1].i8, '-123')
st.equal(decoded['arrayStruct'].value[0].value[1].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].i8, '50')
st.equal(decoded['arrayStruct'].value[1].value[0].str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[2].value[0].i8, '60')
st.equal(decoded['arrayStruct'].value[2].value[0].str.value, 'test_str_short')
st.equal(decoded['arrayStruct'].value[2].value[1].i8, '84')
st.equal(decoded['arrayStruct'].value[2].value[1].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].i8, '-34')
st.equal(decoded['arrayStruct'].value[2].value[2].str.value, 'test_str_short')
}

Loading…
Cancel
Save