Fix node resolution; use Cid struct as key
was erroneously storing the cid in the fullNode's flag.cache
This commit is contained in:
parent
3f0e36c0a3
commit
88e7a394d0
@ -1,4 +1,4 @@
|
|||||||
package util
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
"github.com/cerc-io/ipld-eth-statedb/internal"
|
||||||
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
|
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,11 +98,10 @@ func (db *cachingDB) ContractCode(codeHash common.Hash) ([]byte, error) {
|
|||||||
if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
// TODO - use non panicking
|
codeCID, err := internal.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes())
|
||||||
codeCID := ipld.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes())
|
if err != nil {
|
||||||
// if err != nil {
|
return nil, err
|
||||||
// return nil, err
|
}
|
||||||
// }
|
|
||||||
code, err := db.db.DiskDB().Get(codeCID.Bytes())
|
code, err := db.db.DiskDB().Get(codeCID.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -22,12 +22,13 @@ import (
|
|||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CidBytes = []byte
|
type CidKey = cid.Cid
|
||||||
|
|
||||||
func isEmpty(key CidBytes) bool {
|
func isEmpty(key CidKey) bool {
|
||||||
return len(key) == 0
|
return len(key.KeyString()) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database is an intermediate read-only layer between the trie data structures and
|
// Database is an intermediate read-only layer between the trie data structures and
|
||||||
@ -73,57 +74,30 @@ func (db *Database) DiskDB() ethdb.KeyValueStore {
|
|||||||
return db.diskdb
|
return db.diskdb
|
||||||
}
|
}
|
||||||
|
|
||||||
// node retrieves a cached trie node from memory, or returns nil if none can be
|
// Node retrieves an encoded trie node by CID. If it cannot be found
|
||||||
// found in the memory cache.
|
// cached in memory, it queries the persistent database.
|
||||||
func (db *Database) node(key CidBytes) (node, error) {
|
func (db *Database) Node(key CidKey) ([]byte, error) {
|
||||||
// Retrieve the node from the clean cache if available
|
|
||||||
if db.cleans != nil {
|
|
||||||
if enc := db.cleans.Get(nil, key); enc != nil {
|
|
||||||
// The returned value from cache is in its own copy,
|
|
||||||
// safe to use mustDecodeNodeUnsafe for decoding.
|
|
||||||
return decodeNodeUnsafe(key, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Content unavailable in memory, attempt to retrieve from disk
|
|
||||||
enc, err := db.diskdb.Get(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if enc == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if db.cleans != nil {
|
|
||||||
db.cleans.Set(key, enc)
|
|
||||||
}
|
|
||||||
// The returned value from database is in its own copy,
|
|
||||||
// safe to use mustDecodeNodeUnsafe for decoding.
|
|
||||||
return decodeNodeUnsafe(key, enc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Node retrieves an encoded cached trie node from memory. If it cannot be found
|
|
||||||
// cached, the method queries the persistent database for the content.
|
|
||||||
func (db *Database) Node(key CidBytes) ([]byte, error) {
|
|
||||||
// It doesn't make sense to retrieve the metaroot
|
// It doesn't make sense to retrieve the metaroot
|
||||||
if isEmpty(key) {
|
if isEmpty(key) {
|
||||||
return nil, errors.New("not found")
|
return nil, errors.New("not found")
|
||||||
}
|
}
|
||||||
|
cidbytes := key.Bytes()
|
||||||
// Retrieve the node from the clean cache if available
|
// Retrieve the node from the clean cache if available
|
||||||
if db.cleans != nil {
|
if db.cleans != nil {
|
||||||
if enc := db.cleans.Get(nil, key); enc != nil {
|
if enc := db.cleans.Get(nil, cidbytes); enc != nil {
|
||||||
return enc, nil
|
return enc, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content unavailable in memory, attempt to retrieve from disk
|
// Content unavailable in memory, attempt to retrieve from disk
|
||||||
enc, err := db.diskdb.Get(key)
|
enc, err := db.diskdb.Get(cidbytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(enc) != 0 {
|
if len(enc) != 0 {
|
||||||
if db.cleans != nil {
|
if db.cleans != nil {
|
||||||
db.cleans.Set(key[:], enc)
|
db.cleans.Set(cidbytes, enc)
|
||||||
}
|
}
|
||||||
return enc, nil
|
return enc, nil
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import (
|
|||||||
// to retrieve the meta root.
|
// to retrieve the meta root.
|
||||||
func TestDatabaseMetarootFetch(t *testing.T) {
|
func TestDatabaseMetarootFetch(t *testing.T) {
|
||||||
db := trie.NewDatabase(memorydb.New())
|
db := trie.NewDatabase(memorydb.New())
|
||||||
if _, err := db.Node(trie.CidBytes(nil)); err == nil {
|
if _, err := db.Node(trie.CidKey{}); err == nil {
|
||||||
t.Fatalf("metaroot retrieval succeeded")
|
t.Fatalf("metaroot retrieval succeeded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
|
util "github.com/cerc-io/ipld-eth-statedb/internal"
|
||||||
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -161,7 +162,11 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new
|
|||||||
if hash == nil {
|
if hash == nil {
|
||||||
return nil, origNode, 0, errors.New("non-consensus node")
|
return nil, origNode, 0, errors.New("non-consensus node")
|
||||||
}
|
}
|
||||||
blob, err := t.db.Node(hash)
|
cid, err := util.Keccak256ToCid(t.codec, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, origNode, 0, err
|
||||||
|
}
|
||||||
|
blob, err := t.db.Node(cid)
|
||||||
return blob, origNode, 1, err
|
return blob, origNode, 1, err
|
||||||
}
|
}
|
||||||
// Path still needs to be traversed, descend into children
|
// Path still needs to be traversed, descend into children
|
||||||
@ -206,8 +211,15 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new
|
|||||||
// resolveHash loads node from the underlying database with the provided
|
// resolveHash loads node from the underlying database with the provided
|
||||||
// node hash and path prefix.
|
// node hash and path prefix.
|
||||||
func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
||||||
cid := ipld.Keccak256ToCid(t.codec, n)
|
cid, err := util.Keccak256ToCid(t.codec, n)
|
||||||
node, err := t.db.node(cid.Bytes())
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
enc, err := t.db.Node(cid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
node, err := decodeNodeUnsafe(n, enc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -220,8 +232,14 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
|||||||
// resolveHash loads rlp-encoded node blob from the underlying database
|
// resolveHash loads rlp-encoded node blob from the underlying database
|
||||||
// with the provided node hash and path prefix.
|
// with the provided node hash and path prefix.
|
||||||
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
||||||
cid := ipld.Keccak256ToCid(t.codec, n)
|
cid, err := util.Keccak256ToCid(t.codec, n)
|
||||||
blob, _ := t.db.Node(cid.Bytes())
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blob, err := t.db.Node(cid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if len(blob) != 0 {
|
if len(blob) != 0 {
|
||||||
return blob, nil
|
return blob, nil
|
||||||
}
|
}
|
||||||
@ -231,20 +249,20 @@ func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
|||||||
// Hash returns the root hash of the trie. It does not write to the
|
// Hash returns the root hash of the trie. It does not write to the
|
||||||
// database and can be used even if the trie doesn't have one.
|
// database and can be used even if the trie doesn't have one.
|
||||||
func (t *Trie) Hash() common.Hash {
|
func (t *Trie) Hash() common.Hash {
|
||||||
hash, cached, _ := t.hashRoot()
|
hash, cached := t.hashRoot()
|
||||||
t.root = cached
|
t.root = cached
|
||||||
return common.BytesToHash(hash.(hashNode))
|
return common.BytesToHash(hash.(hashNode))
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashRoot calculates the root hash of the given trie
|
// hashRoot calculates the root hash of the given trie
|
||||||
func (t *Trie) hashRoot() (node, node, error) {
|
func (t *Trie) hashRoot() (node, node) {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return hashNode(emptyRoot.Bytes()), nil, nil
|
return hashNode(emptyRoot.Bytes()), nil
|
||||||
}
|
}
|
||||||
// If the number of changes is below 100, we let one thread handle it
|
// If the number of changes is below 100, we let one thread handle it
|
||||||
h := newHasher(t.unhashed >= 100)
|
h := newHasher(t.unhashed >= 100)
|
||||||
defer returnHasherToPool(h)
|
defer returnHasherToPool(h)
|
||||||
hashed, cached := h.hash(t.root, true)
|
hashed, cached := h.hash(t.root, true)
|
||||||
t.unhashed = 0
|
t.unhashed = 0
|
||||||
return hashed, cached, nil
|
return hashed, cached
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user