mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge d653e63852 into 26d385c18b
This commit is contained in:
commit
876f8748a4
4 changed files with 96 additions and 5 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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{}) {
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
84
eth/api.go
84
eth/api.go
|
|
@ -560,3 +560,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
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: []
|
||||
|
|
|
|||
Loading…
Reference in a new issue