Merge pull request #139 from ethereum/typeDecoder

Refactor computeoffsets()
pull/7/head
chriseth 8 years ago committed by GitHub
commit 0261c3abc6
  1. 19
      src/solidity/astHelper.js
  2. 70
      src/solidity/decodeInfo.js
  3. 36
      src/solidity/stateDecoder.js
  4. 2
      src/solidity/types/Struct.js
  5. 10
      test/solidity/decodeInfo.js

@ -37,28 +37,37 @@ function getLinearizedBaseContracts (id, contractsById) {
* *
* @param {String} contractName - contract for which state var should be resolved * @param {String} contractName - contract for which state var should be resolved
* @param {Object} sourcesList - sources list (containing root AST node) * @param {Object} sourcesList - sources list (containing root AST node)
* @return {Array} - return an array of AST node of all state variables (including inherited) (this will include all enum/struct declarations) * @return {Object} - return an object containing: stateItems - list of all the children node of the @arg contractName
* stateVariables - list of all the variable declaration of the @arg contractName
*/ */
function extractStateVariables (contractName, sourcesList) { function extractState (contractName, sourcesList) {
var contracts = extractContractDefinitions(sourcesList) var contracts = extractContractDefinitions(sourcesList)
var node = contracts.contractsByName[contractName] var node = contracts.contractsByName[contractName]
if (node) { if (node) {
var stateItems = []
var stateVar = [] var stateVar = []
var baseContracts = getLinearizedBaseContracts(node.id, contracts.contractsById) var baseContracts = getLinearizedBaseContracts(node.id, contracts.contractsById)
baseContracts.reverse() baseContracts.reverse()
for (var k in baseContracts) { for (var k in baseContracts) {
var ctr = baseContracts[k] var ctr = baseContracts[k]
for (var i in ctr.children) { for (var i in ctr.children) {
stateVar.push(ctr.children[i]) var item = ctr.children[i]
stateItems.push(item)
if (item.name === 'VariableDeclaration') {
stateVar.push(item)
}
} }
} }
return stateVar return {
stateItems: stateItems,
stateVariables: stateVar
}
} }
return null return null
} }
module.exports = { module.exports = {
extractStateVariables: extractStateVariables, extractState: extractState,
extractContractDefinitions: extractContractDefinitions, extractContractDefinitions: extractContractDefinitions,
getLinearizedBaseContracts: getLinearizedBaseContracts getLinearizedBaseContracts: getLinearizedBaseContracts
} }

@ -164,28 +164,17 @@ function getEnum (type, stateDefinitions) {
* @return {Array} containing all members of the current struct type * @return {Array} containing all members of the current struct type
*/ */
function getStructMembers (typeName, stateDefinitions) { function getStructMembers (typeName, stateDefinitions) {
var members = []
var storageBytes = 0
for (var k in stateDefinitions) { for (var k in stateDefinitions) {
var dec = stateDefinitions[k] var dec = stateDefinitions[k]
if (dec.name === 'StructDefinition' && typeName === dec.attributes.name) { if (dec.name === 'StructDefinition' && typeName === dec.attributes.name) {
for (var i in dec.children) { var offsets = computeOffsets(dec.children, stateDefinitions)
var member = dec.children[i] return {
var decoded = parseType(member.attributes.type, stateDefinitions) members: offsets.typesOffsets,
if (!decoded) { storageSlots: offsets.endLocation.slot
console.log('unable to retrieve decode info of ' + member.attributes.type)
return null
}
members.push(decoded)
storageBytes += decoded.storageBytes
} }
break
} }
} }
return { return null
members: members,
storageBytes: storageBytes
}
} }
/** /**
@ -233,8 +222,57 @@ function parseType (type, stateDefinitions) {
return decodeInfos[currentType](type, stateDefinitions) return decodeInfos[currentType](type, stateDefinitions)
} }
/**
* compute offset (slot offset and byte offset of the @arg list of types)
*
* @param {Array} types - list of types
* @param {Object} stateItems - all state definitions given by the AST (including struct and enum type declaration)
* @return {Array} - return an array of types item: {name, type, location}. location defines the byte offset and slot offset
*/
function computeOffsets (types, stateItems, cb) {
var ret = []
var location = {
offset: 0,
slot: 0
}
for (var i in types) {
var variable = types[i]
var type = parseType(variable.attributes.type, stateItems)
if (!type) {
console.log('unable to retrieve decode info of ' + variable.attributes.type)
return null
}
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
}
}
if (location.offset > 0) {
location.slot++
}
return {
typesOffsets: ret,
endLocation: location
}
}
module.exports = { module.exports = {
parseType: parseType, parseType: parseType,
computeOffsets: computeOffsets,
Uint: Uint, Uint: Uint,
Address: Address, Address: Address,
Bool: Bool, Bool: Bool,

@ -25,40 +25,13 @@ function decodeState (stateVars, storageContent) {
* @return {Object} - return the location of all contract variables in the storage * @return {Object} - return the location of all contract variables in the storage
*/ */
function extractStateVariables (contractName, sourcesList) { function extractStateVariables (contractName, sourcesList) {
var stateDefinitions = astHelper.extractStateVariables(contractName, sourcesList) var state = astHelper.extractState(contractName, sourcesList)
var ret = [] var ret = []
if (!stateDefinitions) { if (!state) {
return ret return ret
} }
var location = { var offsets = decodeInfo.computeOffsets(state.stateVariables, state.stateItems)
offset: 0, return offsets.typesOffsets
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
} }
/** /**
@ -79,4 +52,3 @@ module.exports = {
extractStateVariables: extractStateVariables, extractStateVariables: extractStateVariables,
decodeState: decodeState decodeState: decodeState
} }

@ -1,7 +1,7 @@
'use strict' 'use strict'
function Struct (memberDetails) { function Struct (memberDetails) {
this.storageSlots = Math.ceil(memberDetails.storageBytes / 32) this.storageSlots = memberDetails.storageSlots
this.storageBytes = 32 this.storageBytes = 32
this.members = memberDetails.members this.members = memberDetails.members
this.typeName = 'struct' this.typeName = 'struct'

@ -8,7 +8,7 @@ tape('solidity', function (t) {
t.test('astHelper, decodeInfo', function (st) { t.test('astHelper, decodeInfo', function (st) {
var output = compiler.compile(contracts, 0) var output = compiler.compile(contracts, 0)
var stateDec = index.solidity.astHelper.extractStateVariables('contractUint', output.sources) var stateDec = index.solidity.astHelper.extractState('contractUint', output.sources).stateItems
var decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) var decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 1, 1, 'uint') checkDecodeInfo(st, decodeInfo, 1, 1, 'uint')
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec)
@ -18,7 +18,7 @@ tape('solidity', function (t) {
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[4].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[4].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 1, 16, 'bytesX') checkDecodeInfo(st, decodeInfo, 1, 16, 'bytesX')
stateDec = index.solidity.astHelper.extractStateVariables('contractStructAndArray', output.sources) stateDec = index.solidity.astHelper.extractState('contractStructAndArray', output.sources).stateItems
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 2, 32, 'struct') checkDecodeInfo(st, decodeInfo, 2, 32, 'struct')
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec)
@ -26,7 +26,7 @@ tape('solidity', function (t) {
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[3].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[3].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 2, 32, 'array') checkDecodeInfo(st, decodeInfo, 2, 32, 'array')
stateDec = index.solidity.astHelper.extractStateVariables('contractArray', output.sources) stateDec = index.solidity.astHelper.extractState('contractArray', output.sources).stateItems
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 1, 32, 'array') checkDecodeInfo(st, decodeInfo, 1, 32, 'array')
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec)
@ -34,11 +34,11 @@ tape('solidity', function (t) {
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[2].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 4, 32, 'array') checkDecodeInfo(st, decodeInfo, 4, 32, 'array')
stateDec = index.solidity.astHelper.extractStateVariables('contractEnum', output.sources) stateDec = index.solidity.astHelper.extractState('contractEnum', output.sources).stateItems
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 1, 2, 'enum') checkDecodeInfo(st, decodeInfo, 1, 2, 'enum')
stateDec = index.solidity.astHelper.extractStateVariables('contractSmallVariable', output.sources) stateDec = index.solidity.astHelper.extractState('contractSmallVariable', output.sources).stateItems
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[0].attributes.type, stateDec)
checkDecodeInfo(st, decodeInfo, 1, 1, 'int') checkDecodeInfo(st, decodeInfo, 1, 1, 'int')
decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec) decodeInfo = index.solidity.decodeInfo.parseType(stateDec[1].attributes.type, stateDec)

Loading…
Cancel
Save