Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
8b768613
Commit
8b768613
authored
May 02, 2017
by
cdetrio
Committed by
yann300
May 22, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
initial support for mapping types
parent
06ab09aa
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
167 additions
and
11 deletions
+167
-11
traceHelper.js
src/helpers/traceHelper.js
+4
-0
decodeInfo.js
src/solidity/decodeInfo.js
+15
-4
Mapping.js
src/solidity/types/Mapping.js
+48
-4
StringType.js
src/solidity/types/StringType.js
+1
-1
traceAnalyser.js
src/trace/traceAnalyser.js
+16
-0
traceCache.js
src/trace/traceCache.js
+14
-0
SolidityState.js
src/ui/SolidityState.js
+62
-0
SolidityTypeFormatter.js
src/ui/SolidityTypeFormatter.js
+7
-2
No files found.
src/helpers/traceHelper.js
View file @
8b768613
...
...
@@ -37,6 +37,10 @@ module.exports = {
return
step
.
op
===
'SSTORE'
},
isSHA3Instruction
:
function
(
step
)
{
return
step
.
op
===
'SHA3'
},
newContextStorage
:
function
(
step
)
{
return
step
.
op
===
'CREATE'
||
step
.
op
===
'CALL'
},
...
...
src/solidity/decodeInfo.js
View file @
8b768613
...
...
@@ -19,8 +19,19 @@ var util = require('./types/util')
* @param {String} type - type given by the AST
* @return {Object} returns decoded info about the current type: { storageBytes, typeName}
*/
function
mapping
(
type
)
{
return
new
MappingType
()
function
mapping
(
type
,
stateDefinitions
,
contractName
)
{
var
match
=
type
.
match
(
/mapping
\((
.*
?)(
=>
)?
(
.*
)\)
$/
)
var
keyTypeName
=
match
[
1
]
var
valueTypeName
=
match
[
3
]
var
keyType
=
parseType
(
keyTypeName
,
stateDefinitions
,
contractName
,
'storage'
)
var
valueType
=
parseType
(
valueTypeName
,
stateDefinitions
,
contractName
,
'storage'
)
var
underlyingTypes
=
{
'keyType'
:
keyType
,
'valueType'
:
valueType
}
return
new
MappingType
(
underlyingTypes
,
'location'
,
util
.
removeLocation
(
type
))
}
/**
...
...
@@ -179,7 +190,7 @@ function struct (type, stateDefinitions, contractName, location) {
if
(
!
location
)
{
location
=
match
[
2
].
trim
()
}
var
memberDetails
=
getStructMembers
(
match
[
1
],
stateDefinitions
,
contractName
,
location
)
// type is used to extract the ast struct definition
var
memberDetails
=
getStructMembers
(
match
[
1
],
stateDefinitions
,
contractName
)
// type is used to extract the ast struct definition
if
(
!
memberDetails
)
return
null
return
new
StructType
(
memberDetails
,
location
,
match
[
1
])
}
else
{
...
...
@@ -222,7 +233,7 @@ function getEnum (type, stateDefinitions, contractName) {
* @param {String} location - location of the data (storage ref| storage pointer| memory| calldata)
* @return {Array} containing all members of the current struct type
*/
function
getStructMembers
(
type
,
stateDefinitions
,
contractName
,
location
)
{
function
getStructMembers
(
type
,
stateDefinitions
,
contractName
)
{
var
split
=
type
.
split
(
'.'
)
if
(
!
split
.
length
)
{
type
=
contractName
+
'.'
+
type
...
...
src/solidity/types/Mapping.js
View file @
8b768613
'use strict'
var
RefType
=
require
(
'./RefType'
)
var
ethutil
=
require
(
'ethereumjs-util'
)
class
Mapping
extends
RefType
{
constructor
()
{
super
(
1
,
32
,
'mapping'
,
'storage'
)
constructor
(
underlyingTypes
,
location
,
fullType
)
{
super
(
1
,
32
,
fullType
,
'storage'
)
this
.
keyType
=
underlyingTypes
.
keyType
this
.
valueType
=
underlyingTypes
.
valueType
}
setMappingElements
(
mappingKeyPreimages
)
{
this
.
preimages
=
mappingKeyPreimages
}
async
decodeFromStorage
(
location
,
storageResolver
)
{
// location.offset should always be 0 for a mapping (?? double check)
var
ret
=
{}
for
(
var
i
in
this
.
preimages
)
{
var
preimage
=
this
.
preimages
[
i
]
var
mapLocation
=
getMappingLocation
(
preimage
,
location
.
slot
)
var
globalLocation
=
{
offset
:
location
.
offset
,
slot
:
mapLocation
}
ret
[
preimage
]
=
await
this
.
valueType
.
decodeFromStorage
(
globalLocation
,
storageResolver
)
}
return
{
value
:
'<not implemented>'
,
length
:
'0x'
,
value
:
ret
,
type
:
this
.
typeName
}
}
decodeFromMemoryInternal
(
offset
,
memory
)
{
// mappings can only exist in storage and not in memory
// so this should never be called
return
{
value
:
'<not implemented>'
,
length
:
'0x'
,
...
...
@@ -23,4 +44,27 @@ class Mapping extends RefType {
}
}
function
getMappingLocation
(
key
,
position
)
{
// mapping storage location decribed at http://solidity.readthedocs.io/en/develop/miscellaneous.html#layout-of-state-variables-in-storage
// > the value corresponding to a mapping key k is located at keccak256(k . p) where . is concatenation.
// key should be a hex string, and position an int
var
mappingK
=
ethutil
.
toBuffer
(
'0x'
+
key
)
mappingK
=
ethutil
.
setLengthLeft
(
mappingK
,
32
)
var
mappingP
=
ethutil
.
intToBuffer
(
position
)
mappingP
=
ethutil
.
setLengthLeft
(
mappingP
,
32
)
var
mappingKeyBuf
=
concatTypedArrays
(
mappingK
,
mappingP
)
var
mappingKeyPreimage
=
'0x'
+
mappingKeyBuf
.
toString
(
'hex'
)
var
mappingStorageLocation
=
ethutil
.
sha3
(
mappingKeyPreimage
)
mappingStorageLocation
=
new
ethutil
.
BN
(
mappingStorageLocation
,
16
)
return
mappingStorageLocation
}
function
concatTypedArrays
(
a
,
b
)
{
// a, b TypedArray of same type
let
c
=
new
(
a
.
constructor
)(
a
.
length
+
b
.
length
)
c
.
set
(
a
,
0
)
c
.
set
(
b
,
a
.
length
)
return
c
}
module
.
exports
=
Mapping
src/solidity/types/StringType.js
View file @
8b768613
...
...
@@ -40,7 +40,7 @@ function format (decoded) {
var
value
=
decoded
.
value
value
=
value
.
replace
(
'0x'
,
''
).
replace
(
/
(
..
)
/g
,
'%$1'
)
var
ret
=
{
length
:
decoded
.
length
,
// length: decoded.length, // unneeded, only dynamicBytes uses length
raw
:
decoded
.
value
,
type
:
'string'
}
...
...
src/trace/traceAnalyser.js
View file @
8b768613
'use strict'
var
traceHelper
=
require
(
'../helpers/traceHelper'
)
var
ethutil
=
require
(
'ethereumjs-util'
)
function
TraceAnalyser
(
_cache
)
{
this
.
traceCache
=
_cache
...
...
@@ -71,6 +72,18 @@ TraceAnalyser.prototype.buildMemory = function (index, step) {
}
}
function
getSha3Input
(
stack
,
memory
)
{
var
memoryStart
=
stack
[
stack
.
length
-
1
]
var
memoryLength
=
stack
[
stack
.
length
-
2
]
var
memStartDec
=
(
new
ethutil
.
BN
(
memoryStart
.
replace
(
'0x'
,
''
),
16
)).
toString
(
10
)
memoryStart
=
parseInt
(
memStartDec
)
*
2
var
memLengthDec
=
(
new
ethutil
.
BN
(
memoryLength
.
replace
(
'0x'
,
''
),
16
).
toString
(
10
))
memoryLength
=
parseInt
(
memLengthDec
)
*
2
var
memoryHex
=
memory
.
join
(
''
)
var
sha3Input
=
memoryHex
.
substr
(
memoryStart
,
memoryLength
)
return
sha3Input
}
TraceAnalyser
.
prototype
.
buildStorage
=
function
(
index
,
step
,
context
)
{
if
(
traceHelper
.
newContextStorage
(
step
)
&&
!
traceHelper
.
isCallToPrecompiledContract
(
index
,
this
.
trace
))
{
var
calledAddress
=
traceHelper
.
resolveCalledAddress
(
index
,
this
.
trace
)
...
...
@@ -80,6 +93,9 @@ TraceAnalyser.prototype.buildStorage = function (index, step, context) {
console
.
log
(
'unable to build storage changes. '
+
index
+
' does not match with a CALL. storage changes will be corrupted'
)
}
this
.
traceCache
.
pushStoreChanges
(
index
+
1
,
context
.
storageContext
[
context
.
storageContext
.
length
-
1
])
}
else
if
(
traceHelper
.
isSHA3Instruction
(
step
))
{
var
sha3Input
=
getSha3Input
(
step
.
stack
,
step
.
memory
)
this
.
traceCache
.
pushSha3Preimage
(
sha3Input
,
context
.
storageContext
[
context
.
storageContext
.
length
-
1
])
}
else
if
(
traceHelper
.
isSSTOREInstruction
(
step
))
{
this
.
traceCache
.
pushStoreChanges
(
index
+
1
,
context
.
storageContext
[
context
.
storageContext
.
length
-
1
],
step
.
stack
[
step
.
stack
.
length
-
1
],
step
.
stack
[
step
.
stack
.
length
-
2
])
}
else
if
(
traceHelper
.
isReturnInstruction
(
step
))
{
...
...
src/trace/traceCache.js
View file @
8b768613
'use strict'
var
helper
=
require
(
'../helpers/util'
)
var
ethutil
=
require
(
'ethereumjs-util'
)
function
TraceCache
()
{
this
.
init
()
...
...
@@ -20,6 +21,9 @@ TraceCache.prototype.init = function () {
this
.
memoryChanges
=
[]
this
.
storageChanges
=
[]
this
.
sstore
=
{}
// all sstore occurence in the trace
if
(
!
this
.
sha3Preimages
)
{
// need to accumulate the preimages over multiple tx's, so dont clear
this
.
sha3Preimages
=
{}
}
}
TraceCache
.
prototype
.
pushSteps
=
function
(
index
,
currentCallIndex
)
{
...
...
@@ -92,6 +96,16 @@ TraceCache.prototype.pushStoreChanges = function (index, address, key, value) {
this
.
storageChanges
.
push
(
index
)
}
TraceCache
.
prototype
.
pushSha3Preimage
=
function
(
sha3Input
,
address
)
{
console
.
log
(
'pushSha3Preimage sha3Input:'
,
sha3Input
)
var
preimage
=
sha3Input
var
imageHash
=
ethutil
.
sha3
(
'0x'
+
sha3Input
).
toString
(
'hex'
)
this
.
sha3Preimages
[
imageHash
]
=
{
'address'
:
address
,
'preimage'
:
preimage
}
}
TraceCache
.
prototype
.
accumulateStorageChanges
=
function
(
index
,
address
,
storage
)
{
var
ret
=
Object
.
assign
({},
storage
)
for
(
var
k
in
this
.
storageChanges
)
{
...
...
src/ui/SolidityState.js
View file @
8b768613
...
...
@@ -3,6 +3,8 @@ var DropdownPanel = require('./DropdownPanel')
var
stateDecoder
=
require
(
'../solidity/stateDecoder'
)
var
solidityTypeFormatter
=
require
(
'./SolidityTypeFormatter'
)
var
StorageViewer
=
require
(
'../storage/storageViewer'
)
var
util
=
require
(
'../solidity/types/util'
)
var
ethutil
=
require
(
'ethereumjs-util'
)
var
yo
=
require
(
'yo-yo'
)
function
SolidityState
(
_parent
,
_traceManager
,
_codeManager
,
_solidityProxy
)
{
...
...
@@ -64,6 +66,23 @@ SolidityState.prototype.init = function () {
tx
:
self
.
parent
.
tx
,
address
:
address
},
self
.
storageResolver
,
self
.
traceManager
)
var
storageJSON
=
{}
storageViewer
.
storageRange
(
function
(
error
,
result
)
{
if
(
!
error
)
{
storageJSON
=
result
var
sha3Preimages
=
self
.
traceManager
.
traceCache
.
sha3Preimages
var
mappingPreimages
=
getMappingPreimages
(
stateVars
,
storageJSON
,
sha3Preimages
)
for
(
var
k
in
stateVars
)
{
var
stateVar
=
stateVars
[
k
]
if
(
stateVar
.
type
.
typeName
.
indexOf
(
'mapping'
)
===
0
)
{
var
mapSlot
=
util
.
toBN
(
stateVar
.
storagelocation
.
slot
).
toString
(
16
)
mapSlot
=
ethutil
.
setLengthLeft
(
'0x'
+
mapSlot
,
32
).
toString
(
'hex'
)
stateVar
.
type
.
setMappingElements
(
mappingPreimages
[
mapSlot
])
}
}
stateDecoder
.
decodeState
(
stateVars
,
storageViewer
).
then
((
result
)
=>
{
if
(
!
result
.
error
)
{
self
.
basicPanel
.
update
(
result
)
...
...
@@ -73,7 +92,50 @@ SolidityState.prototype.init = function () {
})
}
})
}
})
})
}
function
getMappingPreimages
(
stateVars
,
storage
,
preimages
)
{
// loop over stateVars and get the locations of all the mappings
// then on each mapping, pass its specific preimage keys
// first filter out all non-mapping storage slots
var
ignoreSlots
=
[]
for
(
var
k
in
stateVars
)
{
var
stateVar
=
stateVars
[
k
]
if
(
stateVar
.
type
.
typeName
.
indexOf
(
'mapping'
)
!==
0
)
{
ignoreSlots
.
push
(
stateVar
.
storagelocation
.
slot
.
toString
())
}
}
var
possibleMappings
=
[]
for
(
var
hashedLoc
in
storage
)
{
var
slotNum
=
util
.
toBN
(
storage
[
hashedLoc
].
key
).
toString
(
10
)
if
(
ignoreSlots
.
indexOf
(
slotNum
)
===
-
1
)
{
possibleMappings
.
push
(
storage
[
hashedLoc
].
key
)
}
}
var
storageMappings
=
{}
for
(
var
pk
in
possibleMappings
)
{
var
possMapKey
=
possibleMappings
[
pk
].
replace
(
'0x'
,
''
)
if
(
preimages
[
possMapKey
])
{
// got preimage!
var
preimage
=
preimages
[
possMapKey
].
preimage
// get mapping position (i.e. storage slot), its the last 32 bytes
var
slotByteOffset
=
preimage
.
length
-
64
var
mappingSlot
=
preimage
.
substr
(
slotByteOffset
)
var
mappingKey
=
preimage
.
substr
(
0
,
slotByteOffset
)
if
(
!
storageMappings
[
mappingSlot
])
{
storageMappings
[
mappingSlot
]
=
[]
}
storageMappings
[
mappingSlot
].
push
(
mappingKey
)
}
}
return
storageMappings
}
module
.
exports
=
SolidityState
src/ui/SolidityTypeFormatter.js
View file @
8b768613
...
...
@@ -41,6 +41,12 @@ function extractData (item, parent, key) {
})
ret
.
self
=
item
.
type
ret
.
isStruct
=
true
}
else
if
(
item
.
type
.
indexOf
(
'mapping'
)
===
0
)
{
ret
.
children
=
Object
.
keys
((
item
.
value
||
{})).
map
(
function
(
key
)
{
return
{
key
:
key
,
value
:
item
.
value
[
key
]}
})
ret
.
isMapping
=
true
ret
.
self
=
item
.
type
}
else
{
ret
.
children
=
[]
ret
.
self
=
item
.
value
...
...
@@ -51,7 +57,7 @@ function extractData (item, parent, key) {
function
fontColor
(
data
)
{
var
color
=
'#124B46'
if
(
data
.
isArray
||
data
.
isStruct
)
{
if
(
data
.
isArray
||
data
.
isStruct
||
data
.
isMapping
)
{
color
=
'#847979'
}
else
if
(
data
.
type
.
indexOf
(
'uint'
)
===
0
||
data
.
type
.
indexOf
(
'int'
)
===
0
||
...
...
@@ -63,4 +69,3 @@ function fontColor (data) {
}
return
'color:'
+
color
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment