aboutsummaryrefslogtreecommitdiffstats
path: root/eth
diff options
context:
space:
mode:
authorNick Johnson <arachnid@notdot.net>2017-11-20 23:18:50 +0800
committerPéter Szilágyi <peterke@gmail.com>2017-11-20 23:18:50 +0800
commit72ed186f46a31ec29bb255bfcadfbfd036cce791 (patch)
treec50d3831a4b43544cb58e041d948ac8a739ef2db /eth
parent7b95cca56c28975eb66cd59f143a83178b969ddf (diff)
downloaddexon-72ed186f46a31ec29bb255bfcadfbfd036cce791.tar.gz
dexon-72ed186f46a31ec29bb255bfcadfbfd036cce791.tar.zst
dexon-72ed186f46a31ec29bb255bfcadfbfd036cce791.zip
eth, internal: Implement getModifiedAccountsBy(Hash|Number) using trie diffs (#15512)
* eth, internal: Implement using trie diffs * eth, internal: Changes in response to review * eth: More fixes to getModifiedAccountsBy* * eth: minor polishes on error capitalization
Diffstat (limited to 'eth')
-rw-r--r--eth/api.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/eth/api.go b/eth/api.go
index e91f51bb9..12448a6a1 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -636,3 +636,86 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu
}
return result
}
+
+// GetModifiedAccountsByumber returns all accounts that have changed between the
+// two blocks specified. A change is defined as a difference in nonce, balance,
+// code hash, or storage hash.
+//
+// With one parameter, returns the list of accounts modified in the specified block.
+func (api *PrivateDebugAPI) GetModifiedAccountsByNumber(startNum uint64, endNum *uint64) ([]common.Address, error) {
+ var startBlock, endBlock *types.Block
+
+ startBlock = api.eth.blockchain.GetBlockByNumber(startNum)
+ if startBlock == nil {
+ return nil, fmt.Errorf("start block %x not found", startNum)
+ }
+
+ if endNum == nil {
+ endBlock = startBlock
+ startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
+ if startBlock == nil {
+ return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
+ }
+ } else {
+ endBlock = api.eth.blockchain.GetBlockByNumber(*endNum)
+ if endBlock == nil {
+ return nil, fmt.Errorf("end block %d not found", *endNum)
+ }
+ }
+ return api.getModifiedAccounts(startBlock, endBlock)
+}
+
+// GetModifiedAccountsByHash returns all accounts that have changed between the
+// two blocks specified. A change is defined as a difference in nonce, balance,
+// code hash, or storage hash.
+//
+// With one parameter, returns the list of accounts modified in the specified block.
+func (api *PrivateDebugAPI) GetModifiedAccountsByHash(startHash common.Hash, endHash *common.Hash) ([]common.Address, error) {
+ var startBlock, endBlock *types.Block
+ startBlock = api.eth.blockchain.GetBlockByHash(startHash)
+ if startBlock == nil {
+ return nil, fmt.Errorf("start block %x not found", startHash)
+ }
+
+ if endHash == nil {
+ endBlock = startBlock
+ startBlock = api.eth.blockchain.GetBlockByHash(startBlock.ParentHash())
+ if startBlock == nil {
+ return nil, fmt.Errorf("block %x has no parent", endBlock.Number())
+ }
+ } else {
+ endBlock = api.eth.blockchain.GetBlockByHash(*endHash)
+ if endBlock == nil {
+ return nil, fmt.Errorf("end block %x not found", *endHash)
+ }
+ }
+ return api.getModifiedAccounts(startBlock, endBlock)
+}
+
+func (api *PrivateDebugAPI) getModifiedAccounts(startBlock, endBlock *types.Block) ([]common.Address, error) {
+ if startBlock.Number().Uint64() >= endBlock.Number().Uint64() {
+ return nil, fmt.Errorf("start block height (%d) must be less than end block height (%d)", startBlock.Number().Uint64(), endBlock.Number().Uint64())
+ }
+
+ oldTrie, err := trie.NewSecure(startBlock.Root(), api.eth.chainDb, 0)
+ if err != nil {
+ return nil, err
+ }
+ newTrie, err := trie.NewSecure(endBlock.Root(), api.eth.chainDb, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ diff, _ := trie.NewDifferenceIterator(oldTrie.NodeIterator([]byte{}), newTrie.NodeIterator([]byte{}))
+ iter := trie.NewIterator(diff)
+
+ var dirty []common.Address
+ for iter.Next() {
+ key := newTrie.GetKey(iter.Key)
+ if key == nil {
+ return nil, fmt.Errorf("no preimage found for hash %x", iter.Key)
+ }
+ dirty = append(dirty, common.BytesToAddress(key))
+ }
+ return dirty, nil
+}