Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/state/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (self *StateDB) RawDump() Dump {
Code: common.Bytes2Hex(obj.Code(self.db)),
Storage: make(map[string]string),
}
storageIt := obj.getTrie(self.db).Iterator()
storageIt := obj.GetTrie(self.db).Iterator()
for storageIt.Next() {
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
}
Expand Down
10 changes: 6 additions & 4 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ func (c *StateObject) touch() {
c.touched = true
}

func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
// GetTrie returns the current instantiated trie or creates a new one
// using the data's root to initialise the trie.
func (c *StateObject) GetTrie(db trie.Database) *trie.SecureTrie {
if c.trie == nil {
var err error
c.trie, err = trie.NewSecure(c.data.Root, db, 0)
Expand All @@ -171,7 +173,7 @@ func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash
return value
}
// Load from DB in case it is missing.
if enc := self.getTrie(db).Get(key[:]); len(enc) > 0 {
if enc := self.GetTrie(db).Get(key[:]); len(enc) > 0 {
_, content, _, err := rlp.Split(enc)
if err != nil {
self.setError(err)
Expand Down Expand Up @@ -206,7 +208,7 @@ func (self *StateObject) setState(key, value common.Hash) {

// updateTrie writes cached storage modifications into the object's storage trie.
func (self *StateObject) updateTrie(db trie.Database) {
tr := self.getTrie(db)
tr := self.GetTrie(db)
for key, value := range self.dirtyStorage {
delete(self.dirtyStorage, key)
if (value == common.Hash{}) {
Expand Down Expand Up @@ -388,7 +390,7 @@ func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
cb(h, value)
}

it := self.getTrie(self.db.db).Iterator()
it := self.GetTrie(self.db.db).Iterator()
for it.Next() {
// ignore cached values
key := common.BytesToHash(self.trie.GetKey(it.Key))
Expand Down
84 changes: 84 additions & 0 deletions eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,3 +547,87 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
}
return nil, errors.New("database inconsistency")
}

type StorageRangeAtResult struct {
Storage map[string]string `json:"storage"`
Complete bool `json:"complete"`
}

// StorageRangeAt returns the storage at the given block height and
// transaction index (exclusive). It may be limited using the
// storageAddress, storageAddressEnd (inclusive) and maxResult parameters.
//
// StorageRangeAt is currently limited and requires needless iterators
// due to the limitation of the trie iterator. At present we can't start
// iterating from any given key, thus we need to loop over any key that's
// not inclusive in the range of start and end.
//
// BUG: Because the state objects make use of the secure storage, iterating
// trie keys is out of order and will be returned the exact same way.
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, storageAddressStart, storageAddressEnd common.Hash, maxResult int) (interface{}, error) {
block := api.eth.BlockChain().GetBlockByHash(blockHash)
if block == nil {
return nil, fmt.Errorf("block %x not found", blockHash)
}
// Create the state database to mutate and eventually trace
parent := api.eth.BlockChain().GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, fmt.Errorf("block parent %x not found", block.ParentHash())
}
stateDb, err := api.eth.BlockChain().StateAt(parent.Root())
if err != nil {
return nil, err
}

result := StorageRangeAtResult{Storage: make(map[string]string)}

signer := types.MakeSigner(api.config, block.Number())
// Mutate the state and trace the selected transaction
done:
for idx, tx := range block.Transactions() {
// Assemble the transaction call message
msg, err := tx.AsMessage(signer)
if err != nil {
return nil, fmt.Errorf("sender retrieval failed: %v", err)
}
context := core.NewEVMContext(msg, block.Header(), api.eth.BlockChain())

// Mutate the state if we haven't reached the tracing transaction yet
if idx < txIndex {
vmenv := vm.NewEnvironment(context, stateDb, api.config, vm.Config{})
_, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil {
return nil, fmt.Errorf("mutation failed: %v", err)
}
stateDb.DeleteSuicides()
continue
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please extract this code into its own function. This basically recomputes the state up to a certain transaction
and is duplicated in the tracing code just above.


stateObject := stateDb.GetStateObject(contractAddress)
// We need to check if the object exists again. It might have been deleted in between the
// transactions.
if stateObject != nil {
trie := stateObject.GetTrie(api.eth.ChainDb())
it := trie.Iterator()

for it.Next() && len(result.Storage) < maxResult {
Copy link
Copy Markdown
Contributor

@fjl fjl Dec 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be better to use ForEachStorage here instead of exposing the trie

var (
value common.Hash
key = trie.GetKey(it.Key)
)

if bytes.Compare(storageAddressStart[:], key[:]) > 0 {
continue
}
if bytes.Compare(storageAddressEnd[:], key[:]) < 0 {
break done
}

rlp.DecodeBytes(it.Value, &value)
result.Storage[common.ToHex(key)] = value.Hex()
}
result.Complete = !it.Next()
}
}
return result, nil
}
5 changes: 5 additions & 0 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ web3._extend({
call: 'debug_traceTransaction',
params: 2,
inputFormatter: [null, null]
}),
new web3._extend.Method({
name: 'storageRangeAt',
call: 'debug_storageRangeAt',
params: 6,
})
],
properties: []
Expand Down