diff --git a/src/solidity/types/ArrayType.js b/src/solidity/types/ArrayType.js index 727cf1c46c..ea924f4cfb 100644 --- a/src/solidity/types/ArrayType.js +++ b/src/solidity/types/ArrayType.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 '' + 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 diff --git a/src/solidity/types/Struct.js b/src/solidity/types/Struct.js index 06b2df20a1..172d919d01 100644 --- a/src/solidity/types/Struct.js +++ b/src/solidity/types/Struct.js @@ -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 '' + 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 diff --git a/src/solidity/types/util.js b/src/solidity/types/util.js index cf8c2659c8..518e75c7da 100644 --- a/src/solidity/types/util.js +++ b/src/solidity/types/util.js @@ -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)) +} diff --git a/test/solidity/contracts/structArrayStorage.js b/test/solidity/contracts/structArrayStorage.js new file mode 100644 index 0000000000..7f542733f6 --- /dev/null +++ b/test/solidity/contracts/structArrayStorage.js @@ -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' + } +} diff --git a/test/solidity/storageDecoder.js b/test/solidity/storageDecoder.js index c41c9b918c..40333eb416 100644 --- a/test/solidity/storageDecoder.js +++ b/test/solidity/storageDecoder.js @@ -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') +}