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
ce3caa69
Commit
ce3caa69
authored
May 23, 2017
by
yann300
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cache the preimages for a debug session (using the initial state)
parent
e59e5644
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
116 additions
and
60 deletions
+116
-60
Mapping.js
src/solidity/types/Mapping.js
+4
-3
mappingPreimages.js
src/storage/mappingPreimages.js
+13
-38
storageResolver.js
src/storage/storageResolver.js
+38
-5
storageViewer.js
src/storage/storageViewer.js
+61
-14
No files found.
src/solidity/types/Mapping.js
View file @
ce3caa69
...
@@ -11,12 +11,13 @@ class Mapping extends RefType {
...
@@ -11,12 +11,13 @@ class Mapping extends RefType {
}
}
async
decodeFromStorage
(
location
,
storageResolver
)
{
async
decodeFromStorage
(
location
,
storageResolver
)
{
var
mappingsPreimages
try
{
try
{
var
mappingsPreimages
=
await
storageResolver
.
mappingPreimages
()
mappingsPreimages
=
await
storageResolver
.
mappingsLocation
()
}
catch
(
e
)
{
}
catch
(
e
)
{
return
{
return
{
value
:
'<error> '
+
e
.
message
,
value
:
e
.
message
,
type
:
this
.
type
type
:
this
.
type
Name
}
}
}
}
var
mapSlot
=
util
.
normalizeHex
(
ethutil
.
bufferToHex
(
location
.
slot
))
var
mapSlot
=
util
.
normalizeHex
(
ethutil
.
bufferToHex
(
location
.
slot
))
...
...
src/storage/mappingPreimages.js
View file @
ce3caa69
var
global
=
require
(
'../helpers/global'
)
var
global
=
require
(
'../helpers/global'
)
module
.
exports
=
{
module
.
exports
=
{
extractMappingPreimages
:
extractMappingPreimage
s
decodeMappingsKeys
:
decodeMappingsKey
s
}
}
/**
/**
* Uses the storageViewer to retrieve the storage and returns a mapping containing possible solidity mappping type location.
* extract the mappings location from the storage
* like { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... }
* like { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... }
*
*
* @param {Object} address - storageViewer
* @param {Object} storage - storage given by storage Viewer (basically a mapping hashedkey : {key, value})
* @return {Map} - solidity mapping location
* @param {Function} callback - calback
*/
* @return {Map} - solidity mapping location (e.g { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... })
async
function
extractMappingPreimages
(
storageViewer
)
{
*/
return
new
Promise
((
resolve
,
reject
)
=>
{
storageViewer
.
storageRange
(
function
(
error
,
storage
)
{
if
(
!
error
)
{
decodeMappingsKeys
(
storage
,
(
error
,
mappings
)
=>
{
if
(
error
)
{
reject
(
error
)
}
else
{
resolve
(
mappings
)
}
})
}
else
{
reject
(
error
)
}
})
})
}
/**
* Uses the storageViewer to retrieve the storage and returns a mapping containing possible solidity mappping type location.
* like { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... }
*
* @param {Object} storage - storage given by storage Viewer (basically a mapping hashedkey : {key, value})
* @param {Function} callback - calback
* @return {Map} - solidity mapping location (e.g { "<mapping_slot>" : { "<mapping-key1>": preimageOf1 }, { "<mapping-key2>": preimageOf2 }, ... })
*/
async
function
decodeMappingsKeys
(
storage
,
callback
)
{
async
function
decodeMappingsKeys
(
storage
,
callback
)
{
var
ret
=
{}
var
ret
=
{}
for
(
var
hashedLoc
in
storage
)
{
for
(
var
hashedLoc
in
storage
)
{
...
@@ -61,11 +36,11 @@ async function decodeMappingsKeys (storage, callback) {
...
@@ -61,11 +36,11 @@ async function decodeMappingsKeys (storage, callback) {
}
}
/**
/**
* Uses web3 to return preimage of a key
* Uses web3 to return preimage of a key
*
*
* @param {String} key - key to retrieve the preimage of
* @param {String} key - key to retrieve the preimage of
* @return {String} - preimage of the given key
* @return {String} - preimage of the given key
*/
*/
function
getPreimage
(
key
)
{
function
getPreimage
(
key
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
global
.
web3
.
debug
.
preimage
(
key
,
function
(
error
,
preimage
)
{
global
.
web3
.
debug
.
preimage
(
key
,
function
(
error
,
preimage
)
{
...
...
src/storage/storageResolver.js
View file @
ce3caa69
'use strict'
'use strict'
var
traceHelper
=
require
(
'../helpers/traceHelper'
)
var
traceHelper
=
require
(
'../helpers/traceHelper'
)
var
util
=
require
(
'../helpers/global'
)
var
util
=
require
(
'../helpers/global'
)
var
mappingPreimages
=
require
(
'./mappingPreimages'
)
/**
* Basically one instance is created for one debugging session.
* (TODO: one instance need to be shared over all the components)
*/
class
StorageResolver
{
class
StorageResolver
{
constructor
()
{
constructor
()
{
this
.
storageByAddress
=
{}
this
.
storageByAddress
=
{}
this
.
preimagesMappingByAddress
=
{}
this
.
maxSize
=
100
this
.
maxSize
=
100
}
}
...
@@ -22,6 +28,33 @@ class StorageResolver {
...
@@ -22,6 +28,33 @@ class StorageResolver {
}
}
/**
/**
* compute the mappgings type locations for the current address (cached for a debugging session)
* note: that only retrieve the first 100 items.
*
* @param {String} address - contract address
* @param {Object} address - storage
* @return {Function} - callback
*/
initialPreimagesMappings
(
tx
,
stepIndex
,
address
,
callback
)
{
if
(
this
.
preimagesMappingByAddress
[
address
])
{
return
callback
(
null
,
this
.
preimagesMappingByAddress
[
address
])
}
this
.
storageRange
(
tx
,
stepIndex
,
address
,
(
error
,
storage
)
=>
{
if
(
error
)
{
return
callback
(
error
)
}
mappingPreimages
.
decodeMappingsKeys
(
storage
,
(
error
,
mappings
)
=>
{
if
(
error
)
{
callback
(
error
)
}
else
{
this
.
preimagesMappingByAddress
[
address
]
=
mappings
callback
(
null
,
mappings
)
}
})
})
}
/**
* return a slot value for the given context (address and vm trace index)
* return a slot value for the given context (address and vm trace index)
*
*
* @param {String} - slot - slot key
* @param {String} - slot - slot key
...
@@ -96,11 +129,11 @@ function fromCache (self, address) {
...
@@ -96,11 +129,11 @@ function fromCache (self, address) {
}
}
/**
/**
* store the result of `storageRangeAtInternal`
* store the result of `storageRangeAtInternal`
*
*
* @param {String} address - contract address
* @param {String} address - contract address
* @param {Object} storage - result of `storageRangeAtInternal`, contains {key, hashedKey, value}
* @param {Object} storage - result of `storageRangeAtInternal`, contains {key, hashedKey, value}
*/
*/
function
toCache
(
self
,
address
,
storage
)
{
function
toCache
(
self
,
address
,
storage
)
{
if
(
!
self
.
storageByAddress
[
address
])
{
if
(
!
self
.
storageByAddress
[
address
])
{
self
.
storageByAddress
[
address
]
=
{}
self
.
storageByAddress
[
address
]
=
{}
...
...
src/storage/storageViewer.js
View file @
ce3caa69
'use strict'
'use strict'
var
helper
=
require
(
'../helpers/util'
)
var
helper
=
require
(
'../helpers/util'
)
var
mappingPreimages
Extractor
=
require
(
'./mappingPreimages'
)
var
mappingPreimages
=
require
(
'./mappingPreimages'
)
/**
* easier access to the storage resolver
* Basically one instance is created foreach execution step and foreach component that need it.
* (TODO: one instance need to be shared over all the components)
*/
class
StorageViewer
{
class
StorageViewer
{
constructor
(
_context
,
_storageResolver
,
_traceManager
)
{
constructor
(
_context
,
_storageResolver
,
_traceManager
)
{
this
.
context
=
_context
this
.
context
=
_context
this
.
storageResolver
=
_storageResolver
this
.
storageResolver
=
_storageResolver
// contains [mappingSlot][mappingkey] = preimage
// this map is renewed for each execution step
// this map is shared among all the mapping types
this
.
mappingsPreimages
=
null
_traceManager
.
accumulateStorageChanges
(
this
.
context
.
stepIndex
,
this
.
context
.
address
,
{},
(
error
,
storageChanges
)
=>
{
_traceManager
.
accumulateStorageChanges
(
this
.
context
.
stepIndex
,
this
.
context
.
address
,
{},
(
error
,
storageChanges
)
=>
{
if
(
!
error
)
{
if
(
!
error
)
{
this
.
storageChanges
=
storageChanges
this
.
storageChanges
=
storageChanges
...
@@ -20,11 +21,11 @@ class StorageViewer {
...
@@ -20,11 +21,11 @@ class StorageViewer {
}
}
/**
/**
* return the storage for the current context (address and vm trace index)
* return the storage for the current context (address and vm trace index)
* by default now returns the range 0 => 1000
* by default now returns the range 0 => 1000
*
*
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value}
* @param {Function} - callback - contains a map: [hashedKey] = {key, hashedKey, value}
*/
*/
storageRange
(
callback
)
{
storageRange
(
callback
)
{
this
.
storageResolver
.
storageRange
(
this
.
context
.
tx
,
this
.
context
.
stepIndex
,
this
.
context
.
address
,
(
error
,
storage
)
=>
{
this
.
storageResolver
.
storageRange
(
this
.
context
.
tx
,
this
.
context
.
stepIndex
,
this
.
context
.
address
,
(
error
,
storage
)
=>
{
if
(
error
)
{
if
(
error
)
{
...
@@ -64,12 +65,58 @@ class StorageViewer {
...
@@ -64,12 +65,58 @@ class StorageViewer {
return
this
.
storageResolver
.
isComplete
(
address
)
return
this
.
storageResolver
.
isComplete
(
address
)
}
}
async
mappingPreimages
()
{
/**
if
(
!
this
.
mappingsPreimages
)
{
* return all the possible mappings locations for the current context (cached)
this
.
mappingsPreimages
=
await
mappingPreimagesExtractor
.
extractMappingPreimages
(
this
)
*
* @param {Function} callback
*/
async
mappingsLocation
()
{
return
new
Promise
((
resolve
,
reject
)
=>
{
if
(
this
.
completeMappingsLocation
)
{
return
resolve
(
this
.
completeMappingsLocation
)
}
this
.
storageResolver
.
initialPreimagesMappings
(
this
.
context
.
tx
,
this
.
context
.
stepIndex
,
this
.
context
.
address
,
(
error
,
initialMappingsLocation
)
=>
{
if
(
error
)
{
reject
(
error
)
}
else
{
this
.
extractMappingsLocationChanges
(
this
.
storageChanges
,
(
error
,
mappingsLocationChanges
)
=>
{
if
(
error
)
{
return
reject
(
error
)
}
this
.
completeMappingsLocation
=
Object
.
assign
({},
initialMappingsLocation
)
for
(
var
key
in
mappingsLocationChanges
)
{
if
(
!
initialMappingsLocation
[
key
])
{
initialMappingsLocation
[
key
]
=
{}
}
this
.
completeMappingsLocation
[
key
]
=
Object
.
assign
({},
initialMappingsLocation
[
key
],
mappingsLocationChanges
[
key
])
}
resolve
(
this
.
completeMappingsLocation
)
})
}
})
})
}
/**
* retrieve mapping location changes from the storage changes.
*
* @param {Function} callback
*/
extractMappingsLocationChanges
(
storageChanges
,
callback
)
{
if
(
this
.
mappingsLocationChanges
)
{
return
callback
(
null
,
this
.
mappingsLocationChanges
)
}
}
return
this
.
mappingsPreimages
mappingPreimages
.
decodeMappingsKeys
(
storageChanges
,
(
error
,
mappings
)
=>
{
if
(
!
error
)
{
this
.
mappingsLocationChanges
=
mappings
return
callback
(
null
,
this
.
mappingsLocationChanges
)
}
else
{
callback
(
error
)
}
})
}
}
}
}
module
.
exports
=
StorageViewer
module
.
exports
=
StorageViewer
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