diff --git a/core/state/statedb.go b/core/state/statedb.go index 76e67d839d..ccd6f3d786 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -136,6 +136,10 @@ func (self *StateDB) Reset(root common.Hash) error { return nil } +func (self *StateDB) GetTrie() Trie { + return self.trie +} + func (self *StateDB) AddLog(log *types.Log) { self.journal.append(addLogChange{txhash: self.thash}) diff --git a/eth/api.go b/eth/api.go index 816b9cd335..432752c439 100644 --- a/eth/api.go +++ b/eth/api.go @@ -20,6 +20,7 @@ import ( "compress/gzip" "context" "errors" + "bytes" "fmt" "io" "math/big" @@ -47,6 +48,47 @@ type PublicEthereumAPI struct { e *Ethereum } +type addressMap map[common.Hash]common.Address + +type AccountRangeResult struct { + AddressMap addressMap `json:"addressMap"` +} + +func accountRange(st state.Trie, start *common.Hash, maxResult int) (AccountRangeResult, error) { + it := trie.NewIterator(st.NodeIterator(start[:])) + result := AccountRangeResult{AddressMap: addressMap{}} + for i := 0; i < maxResult && it.Next(); i++ { + key := st.GetKey(it.Key) + // If key is nil, that means it wasn't found in the preimage database. + // This is not a problem, because we still return the hash of the key together with + // address zero and the client can very easily determine that the hash of the addres zero + // is not matching, which means it wasn't found. + result.AddressMap[common.BytesToHash(it.Key)] = common.BytesToAddress(key) + } + return result, nil +} + +//block hash or number, tx index, start address hash, max results +func (api *PrivateDebugAPI) AccountRangeAt(ctx context.Context, blockNr rpc.BlockNumber, txIndex int, startAddr *common.Hash, maxResults int) (AccountRangeResult, error) { + zeros := make([]byte, common.HashLength) + + if (maxResults > 100) { + maxResults = 100 + } + + if bytes.Equal(startAddr[:], zeros) { + startAddr = nil + } + + blockHash := api.eth.blockchain.CurrentBlock().Hash() + _, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0) + if err != nil { + return AccountRangeResult{}, err + } + + return accountRange(statedb.GetTrie(), startAddr, maxResults) +} + // NewPublicEthereumAPI creates a new Ethereum protocol API for full nodes. func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI { return &PublicEthereumAPI{e}