From 72ed186f46a31ec29bb255bfcadfbfd036cce791 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Mon, 20 Nov 2017 16:18:50 +0100 Subject: 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 --- eth/api.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'eth/api.go') 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 +} -- cgit v1.2.3 From eab2201f808bbe1ef08a504f86cf41dd03aa979c Mon Sep 17 00:00:00 2001 From: Benoit Verkindt Date: Wed, 6 Dec 2017 07:42:16 -0800 Subject: eth: return rlp-decoded values from debug_storageRangeAt (#15476) Fixes #15196 --- eth/api.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'eth/api.go') diff --git a/eth/api.go b/eth/api.go index 12448a6a1..a907c3649 100644 --- a/eth/api.go +++ b/eth/api.go @@ -615,14 +615,18 @@ func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common if st == nil { return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress) } - return storageRangeAt(st, keyStart, maxResult), nil + return storageRangeAt(st, keyStart, maxResult) } -func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResult { +func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) { it := trie.NewIterator(st.NodeIterator(start)) result := StorageRangeResult{Storage: storageMap{}} for i := 0; i < maxResult && it.Next(); i++ { - e := storageEntry{Value: common.BytesToHash(it.Value)} + _, content, _, err := rlp.Split(it.Value) + if err != nil { + return StorageRangeResult{}, err + } + e := storageEntry{Value: common.BytesToHash(content)} if preimage := st.GetKey(it.Key); preimage != nil { preimage := common.BytesToHash(preimage) e.Key = &preimage @@ -634,7 +638,7 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) StorageRangeResu next := common.BytesToHash(it.Key) result.NextKey = &next } - return result + return result, nil } // GetModifiedAccountsByumber returns all accounts that have changed between the -- cgit v1.2.3 From 732f5468d33ae184dfa518fb75b9da87efeee940 Mon Sep 17 00:00:00 2001 From: Michael Ruminer Date: Sat, 9 Dec 2017 17:47:13 -0500 Subject: eth: make tracing API errors more user friendly (#15589) --- eth/api.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'eth/api.go') diff --git a/eth/api.go b/eth/api.go index a907c3649..c748f75de 100644 --- a/eth/api.go +++ b/eth/api.go @@ -452,7 +452,12 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConf } statedb, err := blockchain.StateAt(blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1).Root()) if err != nil { - return false, structLogger.StructLogs(), err + switch err.(type) { + case *trie.MissingNodeError: + return false, structLogger.StructLogs(), fmt.Errorf("required historical state unavailable") + default: + return false, structLogger.StructLogs(), err + } } receipts, _, usedGas, err := processor.Process(block, statedb, config) @@ -518,7 +523,12 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. } msg, context, statedb, err := api.computeTxEnv(blockHash, int(txIndex)) if err != nil { - return nil, err + switch err.(type) { + case *trie.MissingNodeError: + return nil, fmt.Errorf("required historical state unavailable") + default: + return nil, err + } } // Run the transaction with tracing enabled. -- cgit v1.2.3