code referenced by codehash in contract accounts needs to be present in kv dstore for the trie to be considered complete by the state node iterator
This commit is contained in:
parent
d26bb68995
commit
00223269f8
@ -17,8 +17,6 @@
|
|||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
@ -75,20 +73,11 @@ func NewValidator(kvs ethdb.KeyValueStore, database ethdb.Database) *Validator {
|
|||||||
// This does consider child storage tries
|
// This does consider child storage tries
|
||||||
func (v *Validator) ValidateTrie(stateRoot common.Hash) error {
|
func (v *Validator) ValidateTrie(stateRoot common.Hash) error {
|
||||||
// Generate the state.NodeIterator for this root
|
// Generate the state.NodeIterator for this root
|
||||||
stateDB, err := state.New(common.Hash{}, v.stateDatabase, nil)
|
stateDB, err := state.New(stateRoot, v.stateDatabase, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
it := state.NewNodeIterator(stateDB)
|
it := state.NewNodeIterator(stateDB)
|
||||||
// state.NodeIterator won't throw an error if we can't find the root node
|
|
||||||
// check if it exists first
|
|
||||||
exists, err := v.kvs.Has(stateRoot.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
return fmt.Errorf("root node for hash %s does not exist in database", stateRoot.Hex())
|
|
||||||
}
|
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
// iterate through entire state trie and descendent storage tries
|
// iterate through entire state trie and descendent storage tries
|
||||||
// it.Next() will return false when we have either completed iteration of the entire trie or have ran into an error (e.g. a missing node)
|
// it.Next() will return false when we have either completed iteration of the entire trie or have ran into an error (e.g. a missing node)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package validator_test
|
package validator_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -62,10 +63,12 @@ var (
|
|||||||
})
|
})
|
||||||
stateRoot = crypto.Keccak256Hash(stateBranchRootNode)
|
stateRoot = crypto.Keccak256Hash(stateBranchRootNode)
|
||||||
|
|
||||||
|
mockCode = []byte{1, 2, 3, 4, 5}
|
||||||
|
codeHash = crypto.Keccak256Hash(mockCode)
|
||||||
contractAccount, _ = rlp.EncodeToBytes(state.Account{
|
contractAccount, _ = rlp.EncodeToBytes(state.Account{
|
||||||
Nonce: 1,
|
Nonce: 1,
|
||||||
Balance: big.NewInt(0),
|
Balance: big.NewInt(0),
|
||||||
CodeHash: common.HexToHash("0xaaea5efba4fd7b45d7ec03918ac5d8b31aa93b48986af0e6b591f0f087c80127").Bytes(),
|
CodeHash: codeHash.Bytes(),
|
||||||
Root: crypto.Keccak256Hash(storageBranchRootNode),
|
Root: crypto.Keccak256Hash(storageBranchRootNode),
|
||||||
})
|
})
|
||||||
contractAccountLeafNode, _ = rlp.EncodeToBytes([]interface{}{
|
contractAccountLeafNode, _ = rlp.EncodeToBytes([]interface{}{
|
||||||
@ -204,31 +207,40 @@ var _ = Describe("PG-IPFS Validator", func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
It("Returns an error the state root node is missing", func() {
|
It("Returns an error the state root node is missing", func() {
|
||||||
loadTrie(missingRootStateNodes, trieStorageNodes)
|
// we write code to ethdb, there should probably be an EthCode IPLD codec
|
||||||
|
// but there isn't, and we don't need one here since blockstore keys are mh-derived
|
||||||
|
loadTrie(append(missingRootStateNodes, mockCode), trieStorageNodes)
|
||||||
err = v.ValidateTrie(stateRoot)
|
err = v.ValidateTrie(stateRoot)
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("does not exist in database"))
|
Expect(err.Error()).To(ContainSubstring("missing trie node"))
|
||||||
})
|
})
|
||||||
It("Fails to return an error if the storage root node is missing", func() {
|
It("Returns an error if the storage root node is missing", func() {
|
||||||
// NOTE this failure was not expected and renders this approach unreliable, this is an issue with the go-ethereum core/state/iterator.NodeIterator
|
loadTrie(append(trieStateNodes, mockCode), missingRootStorageNodes)
|
||||||
loadTrie(trieStateNodes, missingRootStorageNodes)
|
|
||||||
err = v.ValidateTrie(stateRoot)
|
err = v.ValidateTrie(stateRoot)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("missing trie node"))
|
||||||
})
|
})
|
||||||
It("Fails to return an error if the entire state (state trie and storage tries) cannot be validated", func() {
|
It("Returns an error if the state trie is missing node(s)", func() {
|
||||||
// NOTE this failure was not expected and renders this approach unreliable, this is an issue with the go-ethereum core/state/iterator.NodeIterator
|
loadTrie(append(missingNodeStateNodes, mockCode), trieStorageNodes)
|
||||||
loadTrie(missingNodeStateNodes, trieStorageNodes)
|
|
||||||
err = v.ValidateTrie(stateRoot)
|
err = v.ValidateTrie(stateRoot)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("missing trie node"))
|
||||||
})
|
})
|
||||||
It("Fails to return an error if the entire state (state trie and storage tries) cannot be validated", func() {
|
It("Returns an error if the storage trie is missing node(s)", func() {
|
||||||
// NOTE this failure was not expected and renders this approach unreliable, this is an issue with the go-ethereum core/state/iterator.NodeIterator
|
loadTrie(append(trieStateNodes, mockCode), missingNodeStorageNodes)
|
||||||
loadTrie(trieStateNodes, missingNodeStorageNodes)
|
|
||||||
err = v.ValidateTrie(stateRoot)
|
err = v.ValidateTrie(stateRoot)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("missing trie node"))
|
||||||
|
})
|
||||||
|
It("Returns an error if contract code is missing", func() {
|
||||||
|
loadTrie(trieStateNodes, trieStorageNodes)
|
||||||
|
err = v.ValidateTrie(stateRoot)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
subStr := fmt.Sprintf("code %s: sql: no rows in result set", codeHash.Hex()[2:])
|
||||||
|
Expect(err.Error()).To(ContainSubstring(subStr))
|
||||||
})
|
})
|
||||||
It("Returns no error if the entire state (state trie and storage tries) can be validated", func() {
|
It("Returns no error if the entire state (state trie and storage tries) can be validated", func() {
|
||||||
loadTrie(trieStateNodes, trieStorageNodes)
|
loadTrie(append(trieStateNodes, mockCode), trieStorageNodes)
|
||||||
err = v.ValidateTrie(stateRoot)
|
err = v.ValidateTrie(stateRoot)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user