diff --git a/src/index.js b/src/index.js index aa182e68b1..10262d83c4 100644 --- a/src/index.js +++ b/src/index.js @@ -8,6 +8,7 @@ var disassembler = require('./code/disassembler') var SourceMappingDecoder = require('./util/sourceMappingDecoder') var AstWalker = require('./util/astWalker') var decodeInfo = require('./solidity/decodeInfo') +var stateDecoder = require('./solidity/stateDecoder') var astHelper = require('./solidity/astHelper') if (typeof (module) !== 'undefined' && typeof (module.exports) !== 'undefined') { @@ -38,7 +39,8 @@ function modules () { }, solidity: { decodeInfo: decodeInfo, - astHelper: astHelper + astHelper: astHelper, + stateDecoder: stateDecoder } } } diff --git a/src/solidity/decodeInfo.js b/src/solidity/decodeInfo.js index 20ed46d44c..515041b1d3 100644 --- a/src/solidity/decodeInfo.js +++ b/src/solidity/decodeInfo.js @@ -1,153 +1,118 @@ 'use strict' + +var AddressType = require('./types/Address') +var ArrayType = require('./types/ArrayType') +var BoolType = require('./types/Bool') +var BytesType = require('./types/DynamicByteArray') +var BytesXType = require('./types/FixedByteArray') +var EnumType = require('./types/Enum') +var StringType = require('./types/StringType') +var StructType = require('./types/Struct') +var IntType = require('./types/Int') +var UintType = require('./types/Uint') + /** * Uint decode the given @arg type * * @param {String} type - type given by the AST (e.g uint256, uint32) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function Uint (type) { type === 'uint' ? 'uint256' : type - return { - needsFreeStorageSlot: false, - storageBytes: parseInt(type.replace('uint', '')) / 8, - typeName: type - } + var storageBytes = parseInt(type.replace('uint', '')) / 8 + return new UintType(storageBytes) } /** * Int decode the given @arg type * * @param {String} type - type given by the AST (e.g int256, int32) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function Int (type) { type === 'int' ? 'int256' : type - return { - needsFreeStorageSlot: false, - storageBytes: parseInt(type.replace('int', '')) / 8, - typeName: type - } + var storageBytes = parseInt(type.replace('int', '')) / 8 + return new IntType(storageBytes) } /** * Address decode the given @arg type * * @param {String} type - type given by the AST (e.g address) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function Address (type) { - return { - needsFreeStorageSlot: false, - storageBytes: 20, - typeName: 'address' - } + return new AddressType() } /** * Bool decode the given @arg type * * @param {String} type - type given by the AST (e.g bool) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function Bool (type) { - return { - needsFreeStorageSlot: false, - storageBytes: 1, - typeName: 'bool' - } + return new BoolType() } /** * DynamicByteArray decode the given @arg type * * @param {String} type - type given by the AST (e.g bytes storage ref) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function DynamicByteArray (type) { - return { - needsFreeStorageSlot: true, - storageBytes: 32, - typeName: 'bytes' - } + return new BytesType() } /** * FixedByteArray decode the given @arg type * * @param {String} type - type given by the AST (e.g bytes16) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ function FixedByteArray (type) { - return { - needsFreeStorageSlot: false, - storageBytes: parseInt(type.replace('bytes', '')), - typeName: type - } + var storageBytes = parseInt(type.replace('bytes', '')) + return new BytesXType(storageBytes) } /** * StringType decode the given @arg type * * @param {String} type - type given by the AST (e.g string storage ref) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName} */ -function StringType (type) { - return { - needsFreeStorageSlot: true, - storageBytes: 32, - typeName: 'string' - } +function String (type) { + return new StringType() } /** * ArrayType decode the given @arg type * * @param {String} type - type given by the AST (e.g int256[] storage ref, int256[] storage ref[] storage ref) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName, arraySize, subArray} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName, arraySize, subArray} */ -function ArrayType (type, stateDefinitions) { +function Array (type, stateDefinitions) { var arraySize - var storageBytes - var match = type.match(/(.*)\[(.*?)\]( storage ref| storage pointer| memory| calldata)?$/) if (!match || match.length < 3) { console.log('unable to parse type ' + type) return null } - arraySize = match[2] === '' ? 'dynamic' : parseInt(match[2]) - - var underlyingType = decode(match[1], stateDefinitions) + var underlyingType = parseType(match[1], stateDefinitions) if (underlyingType === null) { console.log('unable to parse type ' + type) return null } - - if (arraySize === 'dynamic') { - storageBytes = 32 - } else { - storageBytes = underlyingType.storageBytes - if (storageBytes > 32) { - storageBytes = 32 * arraySize * Math.ceil(storageBytes / 32) - } else { - storageBytes = 32 * (arraySize / Math.floor(32 / storageBytes)) - } - } - - return { - needsFreeStorageSlot: true, - storageBytes: storageBytes, - typeName: type, - arraySize: arraySize, - underlyingType: underlyingType - } + return new ArrayType(underlyingType, arraySize) } /** * Enum decode the given @arg type * * @param {String} type - type given by the AST (e.g enum enumDef) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName, enum} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName, enum} */ function Enum (type, stateDefinitions) { var enumDef = getEnum(type, stateDefinitions) @@ -155,25 +120,14 @@ function Enum (type, stateDefinitions) { console.log('unable to retrieve decode info of ' + type) return null } - var length = enumDef.children.length - var storageBytes = 0 - while (length > 1) { - length = length / 256 - storageBytes++ - } - return { - needsFreeStorageSlot: false, - storageBytes: storageBytes, - typeName: type, - enum: enumDef - } + return new EnumType(enumDef) } /** * Struct decode the given @arg type * * @param {String} type - type given by the AST (e.g struct structDef storage ref) - * @return {Object} returns decoded info about the current type: { needsFreeStorageSlot, storageBytes, typeName, members} + * @return {Object} returns decoded info about the current type: { storageBytes, typeName, members} */ function Struct (type, stateDefinitions) { var match = type.match(/struct (.*?)( storage ref| storage pointer| memory| calldata)?$/) @@ -182,12 +136,7 @@ function Struct (type, stateDefinitions) { } var memberDetails = getStructMembers(match[1], stateDefinitions) // type is used to extract the ast struct definition if (!memberDetails) return null - return { - needsFreeStorageSlot: true, - storageBytes: memberDetails.storageBytes, - typeName: type, - members: memberDetails.members - } + return new StructType(memberDetails) } /** @@ -200,7 +149,7 @@ function Struct (type, stateDefinitions) { function getEnum (type, stateDefinitions) { for (var k in stateDefinitions) { var dec = stateDefinitions[k] - if (type === 'enum ' + dec.attributes.name) { + if (dec.attributes && dec.attributes.name && type === 'enum ' + dec.attributes.name) { return dec } } @@ -222,15 +171,12 @@ function getStructMembers (typeName, stateDefinitions) { if (dec.name === 'StructDefinition' && typeName === dec.attributes.name) { for (var i in dec.children) { var member = dec.children[i] - var decoded = decode(member.attributes.type, stateDefinitions) + var decoded = parseType(member.attributes.type, stateDefinitions) if (!decoded) { console.log('unable to retrieve decode info of ' + member.attributes.type) return null } members.push(decoded) - if (decoded.needsFreeStorageSlot) { - storageBytes = Math.ceil(storageBytes / 32) * 32 - } storageBytes += decoded.storageBytes } break @@ -266,15 +212,15 @@ function typeClass (fullType) { * @param {Object} stateDefinitions - all state stateDefinitions given by the AST (including struct and enum type declaration) * @return {Object} - return the corresponding decoder or null on error */ -function decode (type, stateDefinitions) { +function parseType (type, stateDefinitions) { var decodeInfos = { 'address': Address, - 'array': ArrayType, + 'array': Array, 'bool': Bool, 'bytes': DynamicByteArray, 'bytesX': FixedByteArray, 'enum': Enum, - 'string': StringType, + 'string': String, 'struct': Struct, 'int': Int, 'uint': Uint @@ -288,15 +234,15 @@ function decode (type, stateDefinitions) { } module.exports = { - decode: decode, + parseType: parseType, Uint: Uint, Address: Address, Bool: Bool, DynamicByteArray: DynamicByteArray, FixedByteArray: FixedByteArray, Int: Int, - StringType: StringType, - ArrayType: ArrayType, + String: String, + Array: Array, Enum: Enum, Struct: Struct } diff --git a/src/solidity/stateDecoder.js b/src/solidity/stateDecoder.js new file mode 100644 index 0000000000..21473026ff --- /dev/null +++ b/src/solidity/stateDecoder.js @@ -0,0 +1,82 @@ +var astHelper = require('./astHelper') +var decodeInfo = require('./decodeInfo') + +/** + * decode the contract state storage + * + * @param {Array} storage location - location of all state variables + * @param {Map} storageContent - storage + * @return {Map} - decoded state variable + */ +function decodeState (stateVars, storageContent) { + var ret = {} + for (var k in stateVars) { + var stateVar = stateVars[k] + ret[stateVar.name] = stateVar.type.decodeFromStorage(stateVar.location, storageContent) + } + return ret +} + +/** + * return all storage location variables of the given @arg contractName + * + * @param {String} contractName - name of the contract + * @param {Object} sourcesList - sources list + * @return {Object} - return the location of all contract variables in the storage + */ +function extractStateVariables (contractName, sourcesList) { + var stateDefinitions = astHelper.extractStateVariables(contractName, sourcesList) + var ret = [] + if (!stateDefinitions) { + return ret + } + var location = { + offset: 0, + slot: 0 + } + for (var k in stateDefinitions) { + var variable = stateDefinitions[k] + if (variable.name === 'VariableDeclaration') { + var type = decodeInfo.parseType(variable.attributes.type, stateDefinitions) + if (location.offset + type.storageBytes > 32) { + location.slot++ + location.offset = 0 + } + ret.push({ + name: variable.attributes.name, + type: type, + location: { + offset: location.offset, + slot: location.slot + } + }) + if (type.storageSlots === 1 && location.offset + type.storageBytes <= 32) { + location.offset += type.storageBytes + } else { + location.slot += type.storageSlots + location.offset = 0 + } + } + } + return ret +} + +/** + * return the state of the given @a contractName as a json object + * + * @param {Map} storageContent - contract storage + * @param {astList} astList - AST nodes of all the sources + * @param {String} contractName - contract for which state var should be resolved + * @return {Map} - return the state of the contract + */ +function solidityState (storageContent, astList, contractName) { + var stateVars = extractStateVariables(contractName, astList) + return decodeState(stateVars, storageContent) +} + +module.exports = { + solidityState: solidityState, + extractStateVariables: extractStateVariables, + decodeState: decodeState +} + diff --git a/src/solidity/types/Address.js b/src/solidity/types/Address.js new file mode 100644 index 0000000000..3d94eb0922 --- /dev/null +++ b/src/solidity/types/Address.js @@ -0,0 +1,13 @@ +'use strict' + +function Address () { + this.storageSlots = 1 + this.storageBytes = 20 + this.typeName = 'address' +} + +Address.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Address diff --git a/src/solidity/types/ArrayType.js b/src/solidity/types/ArrayType.js new file mode 100644 index 0000000000..727cf1c46c --- /dev/null +++ b/src/solidity/types/ArrayType.js @@ -0,0 +1,25 @@ +'use strict' + +function ArrayType (underlyingType, arraySize) { + this.typeName = 'array' + this.storageBytes = 32 + this.underlyingType = underlyingType + this.arraySize = arraySize + this.storageSlots = null + if (arraySize === 'dynamic') { + this.storageSlots = 1 + } else { + if (underlyingType.storageBytes < 32) { + var itemPerSlot = Math.floor(32 / underlyingType.storageBytes) + this.storageSlots = Math.ceil(arraySize / itemPerSlot) + } else { + this.storageSlots = arraySize * underlyingType.storageSlots + } + } +} + +ArrayType.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = ArrayType diff --git a/src/solidity/types/Bool.js b/src/solidity/types/Bool.js new file mode 100644 index 0000000000..8752dc1d79 --- /dev/null +++ b/src/solidity/types/Bool.js @@ -0,0 +1,13 @@ +'use strict' + +function Bool () { + this.storageSlots = 1 + this.storageBytes = 1 + this.typeName = 'bool' +} + +Bool.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Bool diff --git a/src/solidity/types/DynamicByteArray.js b/src/solidity/types/DynamicByteArray.js new file mode 100644 index 0000000000..cbf1b618f8 --- /dev/null +++ b/src/solidity/types/DynamicByteArray.js @@ -0,0 +1,13 @@ +'use strict' + +function DynamicByteArray () { + this.storageSlots = 1 + this.storageBytes = 32 + this.typeName = 'bytes' +} + +DynamicByteArray.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = DynamicByteArray diff --git a/src/solidity/types/Enum.js b/src/solidity/types/Enum.js new file mode 100644 index 0000000000..6c38aec83c --- /dev/null +++ b/src/solidity/types/Enum.js @@ -0,0 +1,19 @@ +'use strict' + +function Enum (enumDef) { + this.enumDef = enumDef + this.typeName = 'enum' + this.storageSlots = 1 + var length = enumDef.children.length + this.storageBytes = 0 + while (length > 1) { + length = length / 256 + this.storageBytes++ + } +} + +Enum.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Enum diff --git a/src/solidity/types/FixedByteArray.js b/src/solidity/types/FixedByteArray.js new file mode 100644 index 0000000000..6dcbb5456b --- /dev/null +++ b/src/solidity/types/FixedByteArray.js @@ -0,0 +1,13 @@ +'use strict' + +function FixedByteArray (storageBytes) { + this.storageSlots = 1 + this.storageBytes = storageBytes + this.typeName = 'bytesX' +} + +FixedByteArray.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = FixedByteArray diff --git a/src/solidity/types/Int.js b/src/solidity/types/Int.js new file mode 100644 index 0000000000..25df4c7f33 --- /dev/null +++ b/src/solidity/types/Int.js @@ -0,0 +1,13 @@ +'use strict' + +function Int (storageBytes) { + this.storageSlots = 1 + this.storageBytes = storageBytes + this.typeName = 'int' +} + +Int.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Int diff --git a/src/solidity/types/StringType.js b/src/solidity/types/StringType.js new file mode 100644 index 0000000000..7431eed3a2 --- /dev/null +++ b/src/solidity/types/StringType.js @@ -0,0 +1,13 @@ +'use strict' + +function StringType () { + this.storageSlots = 1 + this.storageBytes = 32 + this.typeName = 'string' +} + +StringType.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = StringType diff --git a/src/solidity/types/Struct.js b/src/solidity/types/Struct.js new file mode 100644 index 0000000000..f44f9b5e1f --- /dev/null +++ b/src/solidity/types/Struct.js @@ -0,0 +1,14 @@ +'use strict' + +function Struct (memberDetails) { + this.storageSlots = Math.ceil(memberDetails.storageBytes / 32) + this.storageBytes = 32 + this.members = memberDetails.members + this.typeName = 'struct' +} + +Struct.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Struct diff --git a/src/solidity/types/Uint.js b/src/solidity/types/Uint.js new file mode 100644 index 0000000000..b80d336791 --- /dev/null +++ b/src/solidity/types/Uint.js @@ -0,0 +1,13 @@ +'use strict' + +function Uint (storageBytes) { + this.storageSlots = 1 + this.storageBytes = storageBytes + this.typeName = 'uint' +} + +Uint.prototype.decodeFromStorage = function (location, storageContent) { + return '' +} + +module.exports = Uint diff --git a/test/decodeInfo.js b/test/decodeInfo.js deleted file mode 100644 index 46d72cf277..0000000000 --- a/test/decodeInfo.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict' -var tape = require('tape') -var compiler = require('solc') -var index = require('../src/index') - -tape('solidity', function (t) { - t.test('astHelper, decodeInfo', function (st) { - var output = compiler.compile(contracts, 0) - - var stateDec = index.solidity.astHelper.extractStateVariables('contractUint', output.sources) - var decodeInfo = index.solidity.decodeInfo.decode(stateDec[0].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 1, 'uint8') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[2].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 32, 'uint256') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[3].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 32, 'uint256') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[4].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 16, 'bytes16') - - stateDec = index.solidity.astHelper.extractStateVariables('contractStructAndArray', output.sources) - decodeInfo = index.solidity.decodeInfo.decode(stateDec[1].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 64, 'struct structDef storage ref') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[2].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 192, 'struct structDef storage ref[3] storage ref') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[3].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 64, 'bytes12[4] storage ref') - - stateDec = index.solidity.astHelper.extractStateVariables('contractArray', output.sources) - decodeInfo = index.solidity.decodeInfo.decode(stateDec[0].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 4 * 5, 'uint32[5] storage ref') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[1].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 32, 'int8[] storage ref') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[2].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, true, 4 * 32, 'int16[] storage ref[3] storage ref[] storage ref[4] storage ref') - - stateDec = index.solidity.astHelper.extractStateVariables('contractEnum', output.sources) - decodeInfo = index.solidity.decodeInfo.decode(stateDec[1].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 2, 'enum enumDef') - - stateDec = index.solidity.astHelper.extractStateVariables('contractSmallVariable', output.sources) - decodeInfo = index.solidity.decodeInfo.decode(stateDec[0].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 1, 'int8') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[1].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 1, 'uint8') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[2].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 2, 'uint16') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[3].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 4, 'int32') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[4].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 32, 'uint256') - decodeInfo = index.solidity.decodeInfo.decode(stateDec[5].attributes.type, stateDec) - checkDecodeInfo(st, decodeInfo, false, 2, 'int16') - - st.end() - }) -}) - -function checkDecodeInfo (st, decodeInfo, freeSlot, storageBytes, typeName, name) { - st.equal(decodeInfo.needsFreeStorageSlot, freeSlot) - st.equal(decodeInfo.storageBytes, storageBytes) - st.equal(decodeInfo.typeName, typeName) -} - -var contracts = ` - contract baseContract { - uint8 u; - } - - contract contractUint is baseContract { - uint256 ui; - uint ui1; - bytes16 b; - } - - contract contractStructAndArray { - struct structDef { - uint8 ui; - string str; - } - structDef structDec; - structDef[3] array; - bytes12[4] bytesArray; - } - - contract contractArray { - uint32[5] i32st; - int8[] i8dyn; - int16[][3][][4] i16dyn; - } - - contract contractEnum { - enum enumDef {item0,item1,item2,item3,item4,item5,item6,item7,item8,item9,item10,item11,item12,item13,item14,item15,item16,item17,item18,item19,item20,item21,item22,item23,item24,item25,item26,item27,item28,item29,item30,item31,item32,item33,item34,item35,item36,item37,item38,item39,item40,item41,item42,item43,item44,item45,item46,item47,item48,item49,item50,item51,item52,item53,item54,item55,item56,item57,item58,item59,item60,item61,item62,item63,item64,item65,item66,item67,item68,item69,item70,item71,item72,item73,item74,item75,item76,item77,item78,item79,item80,item81,item82,item83,item84,item85,item86,item87,item88,item89,item90,item91,item92,item93,item94,item95,item96,item97,item98,item99,item100,item101,item102,item103,item104,item105,item106,item107,item108,item109,item110,item111,item112,item113,item114,item115,item116,item117,item118,item119,item120,item121,item122,item123,item124,item125,item126,item127,item128,item129,item130,item131,item132,item133,item134,item135,item136,item137,item138,item139,item140,item141,item142,item143,item144,item145,item146,item147,item148,item149,item150,item151,item152,item153,item154,item155,item156,item157,item158,item159,item160,item161,item162,item163,item164,item165,item166,item167,item168,item169,item170,item171,item172,item173,item174,item175,item176,item177,item178,item179,item180,item181,item182,item183,item184,item185,item186,item187,item188,item189,item190,item191,item192,item193,item194,item195,item196,item197,item198,item199,item200,item201,item202,item203,item204,item205,item206,item207,item208,item209,item210,item211,item212,item213,item214,item215,item216,item217,item218,item219,item220,item221,item222,item223,item224,item225,item226,item227,item228,item229,item230,item231,item232,item233,item234,item235,item236,item237,item238,item239,item240,item241,item242,item243,item244,item245,item246,item247,item248,item249,item250,item251,item252,item253,item254,item255,item256,item257,item258,item259,item260,item261,item262,item263,item264,item265,item266,item267,item268,item269,item270,item271,item272,item273,item274,item275,item276,item277,item278,item279,item280,item281,item282,item283,item284,item285,item286,item287,item288,item289,item290,item291,item292,item293,item294,item295,item296,item297,item298,item299,item100000000} - enumDef enum1; - } - - contract contractSmallVariable { - int8 i8; - uint8 iu8; - uint16 iu18; - int32 i32; - uint ui32; - int16 i16; - } -` diff --git a/test/solidity/contracts.js b/test/solidity/contracts.js new file mode 100644 index 0000000000..7e8f9214be --- /dev/null +++ b/test/solidity/contracts.js @@ -0,0 +1,80 @@ +'use strict' +module.exports = ` + contract baseContract { + uint8 u; + } + + contract contractUint is baseContract { + uint256 ui; + uint ui1; + bytes16 b; + } + + contract contractStructAndArray { + struct structDef { + uint8 ui; + string str; + } + structDef structDec; + structDef[3] array; + bytes12[4] bytesArray; + } + + contract contractArray { + uint32[5] i32st; + int8[] i8dyn; + int16[][3][][4] i16dyn; + } + + contract contractEnum { + enum enumDef {item0,item1,item2,item3,item4,item5,item6,item7,item8,item9,item10,item11,item12,item13,item14,item15,item16,item17,item18,item19,item20,item21,item22,item23,item24,item25,item26,item27,item28,item29,item30,item31,item32,item33,item34,item35,item36,item37,item38,item39,item40,item41,item42,item43,item44,item45,item46,item47,item48,item49,item50,item51,item52,item53,item54,item55,item56,item57,item58,item59,item60,item61,item62,item63,item64,item65,item66,item67,item68,item69,item70,item71,item72,item73,item74,item75,item76,item77,item78,item79,item80,item81,item82,item83,item84,item85,item86,item87,item88,item89,item90,item91,item92,item93,item94,item95,item96,item97,item98,item99,item100,item101,item102,item103,item104,item105,item106,item107,item108,item109,item110,item111,item112,item113,item114,item115,item116,item117,item118,item119,item120,item121,item122,item123,item124,item125,item126,item127,item128,item129,item130,item131,item132,item133,item134,item135,item136,item137,item138,item139,item140,item141,item142,item143,item144,item145,item146,item147,item148,item149,item150,item151,item152,item153,item154,item155,item156,item157,item158,item159,item160,item161,item162,item163,item164,item165,item166,item167,item168,item169,item170,item171,item172,item173,item174,item175,item176,item177,item178,item179,item180,item181,item182,item183,item184,item185,item186,item187,item188,item189,item190,item191,item192,item193,item194,item195,item196,item197,item198,item199,item200,item201,item202,item203,item204,item205,item206,item207,item208,item209,item210,item211,item212,item213,item214,item215,item216,item217,item218,item219,item220,item221,item222,item223,item224,item225,item226,item227,item228,item229,item230,item231,item232,item233,item234,item235,item236,item237,item238,item239,item240,item241,item242,item243,item244,item245,item246,item247,item248,item249,item250,item251,item252,item253,item254,item255,item256,item257,item258,item259,item260,item261,item262,item263,item264,item265,item266,item267,item268,item269,item270,item271,item272,item273,item274,item275,item276,item277,item278,item279,item280,item281,item282,item283,item284,item285,item286,item287,item288,item289,item290,item291,item292,item293,item294,item295,item296,item297,item298,item299,item100000000} + enumDef enum1; + } + + contract contractSmallVariable { + int8 i8; + uint8 iu8; + uint16 iu18; + int32 i32; + uint ui32; + int16 i16; + } + + contract testSimpleStorage1 { + uint32 uibase1; + } + + contract testSimpleStorage is testSimpleStorage1 { + uint ui1; + uint ui2; + uint[1] ui3; + uint[][1][4] ui4; + + int16 i16; + + struct structDef { + uint ui; + string str; + } + + structDef structDec; + + structDef[3] arrayStructDec; + + int32 i32; + int16 i16_2; + + enum enumDef { + first, + second, + third + } + + enumDef enumDec; + bool boolean; + + uint[][2][][3] ui5; + + string _string; + } +` diff --git a/test/solidity/decodeInfo.js b/test/solidity/decodeInfo.js new file mode 100644 index 0000000000..36b28ee64f --- /dev/null +++ b/test/solidity/decodeInfo.js @@ -0,0 +1,63 @@ +'use strict' +var tape = require('tape') +var compiler = require('solc') +var index = require('../../src/index') +var contracts = require('./contracts') + +tape('solidity', function (t) { + t.test('astHelper, decodeInfo', function (st) { + var output = compiler.compile(contracts, 0) + + var stateDec = index.solidity.astHelper.extractStateVariables('contractUint', output.sources) + var decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 1, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 32, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[3].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 32, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[4].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 16, 'bytesX') + + stateDec = index.solidity.astHelper.extractStateVariables('contractStructAndArray', output.sources) + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 2, 32, 'struct') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 6, 32, 'array') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[3].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 2, 32, 'array') + + stateDec = index.solidity.astHelper.extractStateVariables('contractArray', output.sources) + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 32, 'array') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 32, 'array') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 4, 32, 'array') + + stateDec = index.solidity.astHelper.extractStateVariables('contractEnum', output.sources) + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 2, 'enum') + + stateDec = index.solidity.astHelper.extractStateVariables('contractSmallVariable', output.sources) + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 1, 'int') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 1, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 2, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[3].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 4, 'int') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[4].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 32, 'uint') + decodeInfo = index.solidity.decodeInfo.parseType(stateDec[5].attributes.type, stateDec) + checkDecodeInfo(st, decodeInfo, 1, 2, 'int') + + st.end() + }) +}) + +function checkDecodeInfo (st, decodeInfo, storageSlots, storageBytes, typeName) { + st.equal(decodeInfo.storageSlots, storageSlots) + st.equal(decodeInfo.storageBytes, storageBytes) + st.equal(decodeInfo.typeName, typeName) +} diff --git a/test/solidity/storageLocation.js b/test/solidity/storageLocation.js new file mode 100644 index 0000000000..d734eedb75 --- /dev/null +++ b/test/solidity/storageLocation.js @@ -0,0 +1,57 @@ +'use strict' +var tape = require('tape') +var compiler = require('solc') +var index = require('../../src/index') +var contracts = require('./contracts') + +tape('solidity', function (t) { + t.test('astHelper, decodeInfo', function (st) { + var output = compiler.compile(contracts, 0) + var stateDec = index.solidity.stateDecoder.extractStateVariables('contractUint', output.sources) + checkLocation(st, stateDec[0].location, 0, 0) + checkLocation(st, stateDec[1].location, 1, 0) + checkLocation(st, stateDec[2].location, 2, 0) + checkLocation(st, stateDec[3].location, 3, 0) + + stateDec = index.solidity.stateDecoder.extractStateVariables('contractStructAndArray', output.sources) + checkLocation(st, stateDec[0].location, 0, 0) + checkLocation(st, stateDec[1].location, 2, 0) + checkLocation(st, stateDec[2].location, 8, 0) + + stateDec = index.solidity.stateDecoder.extractStateVariables('contractArray', output.sources) + checkLocation(st, stateDec[0].location, 0, 0) + checkLocation(st, stateDec[1].location, 1, 0) + checkLocation(st, stateDec[2].location, 2, 0) + + stateDec = index.solidity.stateDecoder.extractStateVariables('contractSmallVariable', output.sources) + checkLocation(st, stateDec[0].location, 0, 0) + checkLocation(st, stateDec[1].location, 0, 1) + checkLocation(st, stateDec[2].location, 0, 2) + checkLocation(st, stateDec[3].location, 0, 4) + checkLocation(st, stateDec[4].location, 1, 0) + checkLocation(st, stateDec[5].location, 2, 0) + + stateDec = index.solidity.stateDecoder.extractStateVariables('testSimpleStorage', output.sources) + checkLocation(st, stateDec[0].location, 0, 0) + checkLocation(st, stateDec[1].location, 1, 0) + checkLocation(st, stateDec[2].location, 2, 0) + checkLocation(st, stateDec[3].location, 3, 0) + checkLocation(st, stateDec[4].location, 4, 0) + checkLocation(st, stateDec[5].location, 8, 0) + checkLocation(st, stateDec[6].location, 9, 0) + checkLocation(st, stateDec[8].location, 17, 0) + checkLocation(st, stateDec[9].location, 17, 4) + checkLocation(st, stateDec[10].location, 17, 6) + checkLocation(st, stateDec[11].location, 17, 7) + checkLocation(st, stateDec[12].location, 18, 0) + checkLocation(st, stateDec[13].location, 21, 0) + + st.end() + }) +}) + +function checkLocation (st, location, slot, offset) { + st.equal(location.offset, offset) + st.equal(location.slot, slot) +} + diff --git a/test/tests.js b/test/tests.js index faeb4da66f..3a97dfdbfa 100644 --- a/test/tests.js +++ b/test/tests.js @@ -7,4 +7,5 @@ require('./astwalker.js') require('./disassembler.js') require('./eventManager.js') require('./sourceMappingDecoder.js') -require('./decodeInfo.js') +require('./solidity/decodeInfo.js') +require('./solidity/storageLocation.js')