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)),
|
Code: common.Bytes2Hex(obj.Code(self.db)),
|
||||||
Storage: make(map[string]string),
|
Storage: make(map[string]string),
|
||||||
}
|
}
|
||||||
storageIt := obj.getTrie(self.db).Iterator()
|
storageIt := obj.GetTrie(self.db).Iterator()
|
||||||
for storageIt.Next() {
|
for storageIt.Next() {
|
||||||
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,9 @@ func (c *StateObject) touch() {
|
||||||
c.touched = true
|
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 {
|
if c.trie == nil {
|
||||||
var err error
|
var err error
|
||||||
c.trie, err = trie.NewSecure(c.data.Root, db, 0)
|
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
|
return value
|
||||||
}
|
}
|
||||||
// Load from DB in case it is missing.
|
// 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)
|
_, content, _, err := rlp.Split(enc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.setError(err)
|
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.
|
// updateTrie writes cached storage modifications into the object's storage trie.
|
||||||
func (self *StateObject) updateTrie(db trie.Database) {
|
func (self *StateObject) updateTrie(db trie.Database) {
|
||||||
tr := self.getTrie(db)
|
tr := self.GetTrie(db)
|
||||||
for key, value := range self.dirtyStorage {
|
for key, value := range self.dirtyStorage {
|
||||||
delete(self.dirtyStorage, key)
|
delete(self.dirtyStorage, key)
|
||||||
if (value == common.Hash{}) {
|
if (value == common.Hash{}) {
|
||||||
|
|
@ -388,7 +390,7 @@ func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
|
||||||
cb(h, value)
|
cb(h, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
it := self.getTrie(self.db.db).Iterator()
|
it := self.GetTrie(self.db.db).Iterator()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
// ignore cached values
|
// ignore cached values
|
||||||
key := common.BytesToHash(self.trie.GetKey(it.Key))
|
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")
|
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',
|
call: 'debug_traceTransaction',
|
||||||
params: 2,
|
params: 2,
|
||||||
inputFormatter: [null, null]
|
inputFormatter: [null, null]
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'storageRangeAt',
|
||||||
|
call: 'debug_storageRangeAt',
|
||||||
|
params: 6,
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
properties: []
|
properties: []
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue