forked from cerc-io/plugeth
core/state: simplify storage trie update and commit (#28030)
This change improves function description and simplifies logic in statedb update and commit operations.
This commit is contained in:
parent
53f3c2ae65
commit
0acc0a1f86
@ -264,12 +264,17 @@ func (s *stateObject) finalise(prefetch bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateTrie writes cached storage modifications into the object's storage trie.
|
// updateTrie is responsible for persisting cached storage changes into the
|
||||||
// It will return nil if the trie has not been loaded and no changes have been
|
// object's storage trie. In case the storage trie is not yet loaded, this
|
||||||
// made. An error will be returned if the trie can't be loaded/updated correctly.
|
// function will load the trie automatically. If any issues arise during the
|
||||||
|
// loading or updating of the trie, an error will be returned. Furthermore,
|
||||||
|
// this function will return the mutated storage trie, or nil if there is no
|
||||||
|
// storage change at all.
|
||||||
func (s *stateObject) updateTrie() (Trie, error) {
|
func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
// Make sure all dirty slots are finalized into the pending storage area
|
// Make sure all dirty slots are finalized into the pending storage area
|
||||||
s.finalise(false) // Don't prefetch anymore, pull directly if need be
|
s.finalise(false)
|
||||||
|
|
||||||
|
// Short circuit if nothing changed, don't bother with hashing anything
|
||||||
if len(s.pendingStorage) == 0 {
|
if len(s.pendingStorage) == 0 {
|
||||||
return s.trie, nil
|
return s.trie, nil
|
||||||
}
|
}
|
||||||
@ -281,14 +286,13 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
var (
|
var (
|
||||||
storage map[common.Hash][]byte
|
storage map[common.Hash][]byte
|
||||||
origin map[common.Hash][]byte
|
origin map[common.Hash][]byte
|
||||||
hasher = s.db.hasher
|
|
||||||
)
|
)
|
||||||
tr, err := s.getTrie()
|
tr, err := s.getTrie()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Insert all the pending updates into the trie
|
// Insert all the pending storage updates into the trie
|
||||||
usedStorage := make([][]byte, 0, len(s.pendingStorage))
|
usedStorage := make([][]byte, 0, len(s.pendingStorage))
|
||||||
for key, value := range s.pendingStorage {
|
for key, value := range s.pendingStorage {
|
||||||
// Skip noop changes, persist actual changes
|
// Skip noop changes, persist actual changes
|
||||||
@ -298,8 +302,7 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
prev := s.originStorage[key]
|
prev := s.originStorage[key]
|
||||||
s.originStorage[key] = value
|
s.originStorage[key] = value
|
||||||
|
|
||||||
// rlp-encoded value to be used by the snapshot
|
var encoded []byte // rlp-encoded value to be used by the snapshot
|
||||||
var snapshotVal []byte
|
|
||||||
if (value == common.Hash{}) {
|
if (value == common.Hash{}) {
|
||||||
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
@ -307,10 +310,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
}
|
}
|
||||||
s.db.StorageDeleted += 1
|
s.db.StorageDeleted += 1
|
||||||
} else {
|
} else {
|
||||||
trimmedVal := common.TrimLeftZeroes(value[:])
|
|
||||||
// Encoding []byte cannot fail, ok to ignore the error.
|
// Encoding []byte cannot fail, ok to ignore the error.
|
||||||
snapshotVal, _ = rlp.EncodeToBytes(trimmedVal)
|
trimmed := common.TrimLeftZeroes(value[:])
|
||||||
if err := tr.UpdateStorage(s.address, key[:], trimmedVal); err != nil {
|
encoded, _ = rlp.EncodeToBytes(trimmed)
|
||||||
|
if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -323,8 +326,8 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
s.db.storages[s.addrHash] = storage
|
s.db.storages[s.addrHash] = storage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
khash := crypto.HashData(hasher, key[:])
|
khash := crypto.HashData(s.db.hasher, key[:])
|
||||||
storage[khash] = snapshotVal // snapshotVal will be nil if it's deleted
|
storage[khash] = encoded // encoded will be nil if it's deleted
|
||||||
|
|
||||||
// Cache the original value of mutated storage slots
|
// Cache the original value of mutated storage slots
|
||||||
if origin == nil {
|
if origin == nil {
|
||||||
@ -349,21 +352,17 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
if s.db.prefetcher != nil {
|
if s.db.prefetcher != nil {
|
||||||
s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage)
|
s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage)
|
||||||
}
|
}
|
||||||
if len(s.pendingStorage) > 0 {
|
s.pendingStorage = make(Storage) // reset pending map
|
||||||
s.pendingStorage = make(Storage)
|
|
||||||
}
|
|
||||||
return tr, nil
|
return tr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRoot sets the trie root to the current root hash of. An error
|
// updateRoot flushes all cached storage mutations to trie, recalculating the
|
||||||
// will be returned if trie root hash is not computed correctly.
|
// new storage trie root.
|
||||||
func (s *stateObject) updateRoot() {
|
func (s *stateObject) updateRoot() {
|
||||||
|
// Flush cached storage mutations into trie, short circuit if any error
|
||||||
|
// is occurred or there is not change in the trie.
|
||||||
tr, err := s.updateTrie()
|
tr, err := s.updateTrie()
|
||||||
if err != nil {
|
if err != nil || tr == nil {
|
||||||
return
|
|
||||||
}
|
|
||||||
// If nothing changed, don't bother with hashing anything
|
|
||||||
if tr == nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Track the amount of time wasted on hashing the storage trie
|
// Track the amount of time wasted on hashing the storage trie
|
||||||
@ -373,14 +372,12 @@ func (s *stateObject) updateRoot() {
|
|||||||
s.data.Root = tr.Hash()
|
s.data.Root = tr.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit returns the changes made in storage trie and updates the account data.
|
// commit obtains a set of dirty storage trie nodes and updates the account data.
|
||||||
|
// The returned set can be nil if nothing to commit. This function assumes all
|
||||||
|
// storage mutations have already been flushed into trie by updateRoot.
|
||||||
func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
||||||
tr, err := s.updateTrie()
|
// Short circuit if trie is not even loaded, don't bother with committing anything
|
||||||
if err != nil {
|
if s.trie == nil {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// If nothing changed, don't bother with committing anything
|
|
||||||
if tr == nil {
|
|
||||||
s.origin = s.data.Copy()
|
s.origin = s.data.Copy()
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -388,7 +385,10 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
|||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
|
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
|
||||||
}
|
}
|
||||||
root, nodes, err := tr.Commit(false)
|
// The trie is currently in an open state and could potentially contain
|
||||||
|
// cached mutations. Call commit to acquire a set of nodes that have been
|
||||||
|
// modified, the set can be nil if nothing to commit.
|
||||||
|
root, nodes, err := s.trie.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -536,3 +536,7 @@ func (s *stateObject) Balance() *big.Int {
|
|||||||
func (s *stateObject) Nonce() uint64 {
|
func (s *stateObject) Nonce() uint64 {
|
||||||
return s.data.Nonce
|
return s.data.Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *stateObject) Root() common.Hash {
|
||||||
|
return s.data.Root
|
||||||
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
@ -48,17 +47,6 @@ type revision struct {
|
|||||||
journalIndex int
|
journalIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
type proofList [][]byte
|
|
||||||
|
|
||||||
func (n *proofList) Put(key []byte, value []byte) error {
|
|
||||||
*n = append(*n, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *proofList) Delete(key []byte) error {
|
|
||||||
panic("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateDB structs within the ethereum protocol are used to store anything
|
// StateDB structs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
@ -297,6 +285,7 @@ func (s *StateDB) GetBalance(addr common.Address) *big.Int {
|
|||||||
return common.Big0
|
return common.Big0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNonce retrieves the nonce from the given address or 0 if object not found
|
||||||
func (s *StateDB) GetNonce(addr common.Address) uint64 {
|
func (s *StateDB) GetNonce(addr common.Address) uint64 {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
@ -306,6 +295,16 @@ func (s *StateDB) GetNonce(addr common.Address) uint64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStorageRoot retrieves the storage root from the given address or empty
|
||||||
|
// if object not found.
|
||||||
|
func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash {
|
||||||
|
stateObject := s.getStateObject(addr)
|
||||||
|
if stateObject != nil {
|
||||||
|
return stateObject.Root()
|
||||||
|
}
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
// TxIndex returns the current transaction index set by Prepare.
|
// TxIndex returns the current transaction index set by Prepare.
|
||||||
func (s *StateDB) TxIndex() int {
|
func (s *StateDB) TxIndex() int {
|
||||||
return s.txIndex
|
return s.txIndex
|
||||||
@ -344,35 +343,6 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
|||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProof returns the Merkle proof for a given account.
|
|
||||||
func (s *StateDB) GetProof(addr common.Address) ([][]byte, error) {
|
|
||||||
return s.GetProofByHash(crypto.Keccak256Hash(addr.Bytes()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetProofByHash returns the Merkle proof for a given account.
|
|
||||||
func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) {
|
|
||||||
var proof proofList
|
|
||||||
err := s.trie.Prove(addrHash[:], &proof)
|
|
||||||
return proof, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStorageProof returns the Merkle proof for given storage slot.
|
|
||||||
func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) {
|
|
||||||
trie, err := s.StorageTrie(a)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if trie == nil {
|
|
||||||
return nil, errors.New("storage trie for requested address does not exist")
|
|
||||||
}
|
|
||||||
var proof proofList
|
|
||||||
err = trie.Prove(crypto.Keccak256(key.Bytes()), &proof)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return proof, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCommittedState retrieves a value from the given account's committed storage trie.
|
// GetCommittedState retrieves a value from the given account's committed storage trie.
|
||||||
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
@ -387,21 +357,6 @@ func (s *StateDB) Database() Database {
|
|||||||
return s.db
|
return s.db
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageTrie returns the storage trie of an account. The return value is a copy
|
|
||||||
// and is nil for non-existent accounts. An error will be returned if storage trie
|
|
||||||
// is existent but can't be loaded correctly.
|
|
||||||
func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) {
|
|
||||||
stateObject := s.getStateObject(addr)
|
|
||||||
if stateObject == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
cpy := stateObject.deepCopy(s)
|
|
||||||
if _, err := cpy.updateTrie(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return cpy.getTrie()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@ -216,7 +217,6 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.Block
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash)
|
return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash)
|
||||||
}
|
}
|
||||||
@ -226,18 +226,20 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.Block
|
|||||||
}
|
}
|
||||||
defer release()
|
defer release()
|
||||||
|
|
||||||
st, err := statedb.StorageTrie(contractAddress)
|
return storageRangeAt(statedb, block.Root(), contractAddress, keyStart, maxResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageRangeAt(statedb *state.StateDB, root common.Hash, address common.Address, start []byte, maxResult int) (StorageRangeResult, error) {
|
||||||
|
storageRoot := statedb.GetStorageRoot(address)
|
||||||
|
if storageRoot == types.EmptyRootHash || storageRoot == (common.Hash{}) {
|
||||||
|
return StorageRangeResult{}, nil // empty storage
|
||||||
|
}
|
||||||
|
id := trie.StorageTrieID(root, crypto.Keccak256Hash(address.Bytes()), storageRoot)
|
||||||
|
tr, err := trie.NewStateTrie(id, statedb.Database().TrieDB())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
if st == nil {
|
trieIt, err := tr.NodeIterator(start)
|
||||||
return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress)
|
|
||||||
}
|
|
||||||
return storageRangeAt(st, keyStart, maxResult)
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) {
|
|
||||||
trieIt, err := st.NodeIterator(start)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
@ -249,7 +251,7 @@ func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeRes
|
|||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
e := storageEntry{Value: common.BytesToHash(content)}
|
e := storageEntry{Value: common.BytesToHash(content)}
|
||||||
if preimage := st.GetKey(it.Key); preimage != nil {
|
if preimage := tr.GetKey(it.Key); preimage != nil {
|
||||||
preimage := common.BytesToHash(preimage)
|
preimage := common.BytesToHash(preimage)
|
||||||
e.Key = &preimage
|
e.Key = &preimage
|
||||||
}
|
}
|
||||||
|
@ -159,9 +159,10 @@ func TestStorageRangeAt(t *testing.T) {
|
|||||||
|
|
||||||
// Create a state where account 0x010000... has a few storage entries.
|
// Create a state where account 0x010000... has a few storage entries.
|
||||||
var (
|
var (
|
||||||
state, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
db = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: true})
|
||||||
addr = common.Address{0x01}
|
sdb, _ = state.New(types.EmptyRootHash, db, nil)
|
||||||
keys = []common.Hash{ // hashes of Keys of storage
|
addr = common.Address{0x01}
|
||||||
|
keys = []common.Hash{ // hashes of Keys of storage
|
||||||
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
|
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
|
||||||
common.HexToHash("426fcb404ab2d5d8e61a3d918108006bbb0a9be65e92235bb10eefbdb6dcd053"),
|
common.HexToHash("426fcb404ab2d5d8e61a3d918108006bbb0a9be65e92235bb10eefbdb6dcd053"),
|
||||||
common.HexToHash("48078cfed56339ea54962e72c37c7f588fc4f8e5bc173827ba75cb10a63a96a5"),
|
common.HexToHash("48078cfed56339ea54962e72c37c7f588fc4f8e5bc173827ba75cb10a63a96a5"),
|
||||||
@ -175,8 +176,10 @@ func TestStorageRangeAt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
for _, entry := range storage {
|
for _, entry := range storage {
|
||||||
state.SetState(addr, *entry.Key, entry.Value)
|
sdb.SetState(addr, *entry.Key, entry.Value)
|
||||||
}
|
}
|
||||||
|
root, _ := sdb.Commit(0, false)
|
||||||
|
sdb, _ = state.New(root, db, nil)
|
||||||
|
|
||||||
// Check a few combinations of limit and start/end.
|
// Check a few combinations of limit and start/end.
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -206,11 +209,7 @@ func TestStorageRangeAt(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
tr, err := state.StorageTrie(addr)
|
result, err := storageRangeAt(sdb, root, addr, test.start, test.limit)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
result, err := storageRangeAt(tr, test.start, test.limit)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/tyler-smith/go-bip39"
|
"github.com/tyler-smith/go-bip39"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -674,9 +675,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
|
|||||||
keys = make([]common.Hash, len(storageKeys))
|
keys = make([]common.Hash, len(storageKeys))
|
||||||
keyLengths = make([]int, len(storageKeys))
|
keyLengths = make([]int, len(storageKeys))
|
||||||
storageProof = make([]StorageResult, len(storageKeys))
|
storageProof = make([]StorageResult, len(storageKeys))
|
||||||
storageTrie state.Trie
|
|
||||||
storageHash = types.EmptyRootHash
|
storageTrie state.Trie
|
||||||
codeHash = types.EmptyCodeHash
|
storageHash = types.EmptyRootHash
|
||||||
|
codeHash = types.EmptyCodeHash
|
||||||
)
|
)
|
||||||
// Deserialize all keys. This prevents state access on invalid input.
|
// Deserialize all keys. This prevents state access on invalid input.
|
||||||
for i, hexKey := range storageKeys {
|
for i, hexKey := range storageKeys {
|
||||||
@ -686,15 +688,18 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if storageTrie, err = state.StorageTrie(address); err != nil {
|
if storageRoot := state.GetStorageRoot(address); storageRoot != types.EmptyRootHash && storageRoot != (common.Hash{}) {
|
||||||
return nil, err
|
id := trie.StorageTrieID(header.Root, crypto.Keccak256Hash(address.Bytes()), storageRoot)
|
||||||
|
tr, err := trie.NewStateTrie(id, state.Database().TrieDB())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
storageTrie = tr
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a storageTrie, the account exists and we must update
|
// If we have a storageTrie, the account exists and we must update
|
||||||
// the storage root hash and the code hash.
|
// the storage root hash and the code hash.
|
||||||
if storageTrie != nil {
|
if storageTrie != nil {
|
||||||
@ -727,14 +732,17 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the accountProof.
|
// Create the accountProof.
|
||||||
accountProof, proofErr := state.GetProof(address)
|
tr, err := trie.NewStateTrie(trie.StateTrieID(header.Root), state.Database().TrieDB())
|
||||||
if proofErr != nil {
|
if err != nil {
|
||||||
return nil, proofErr
|
return nil, err
|
||||||
|
}
|
||||||
|
var accountProof proofList
|
||||||
|
if err := tr.Prove(crypto.Keccak256(address.Bytes()), &accountProof); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &AccountResult{
|
return &AccountResult{
|
||||||
Address: address,
|
Address: address,
|
||||||
AccountProof: toHexSlice(accountProof),
|
AccountProof: accountProof,
|
||||||
Balance: (*hexutil.Big)(state.GetBalance(address)),
|
Balance: (*hexutil.Big)(state.GetBalance(address)),
|
||||||
CodeHash: codeHash,
|
CodeHash: codeHash,
|
||||||
Nonce: hexutil.Uint64(state.GetNonce(address)),
|
Nonce: hexutil.Uint64(state.GetNonce(address)),
|
||||||
@ -2245,12 +2253,3 @@ func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toHexSlice creates a slice of hex-strings based on []byte.
|
|
||||||
func toHexSlice(b [][]byte) []string {
|
|
||||||
r := make([]string, len(b))
|
|
||||||
for i := range b {
|
|
||||||
r[i] = hexutil.Encode(b[i])
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user