Refactor for v5 and IPFS v0 blockstore (#73)

* vulcanize => cerc

* Use v0-blockstore based DB

via ipld-eth-statedb/trie_by_cid

* Update CI workflows

* Update modules

- concurrent iterator interface
- ginkgo v2
- go 1.19
This commit is contained in:
2023-05-18 22:46:51 -05:00
committed by GitHub
parent f09675a0f3
commit 5eeeecf667
14 changed files with 146 additions and 107 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ package validator_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
+6 -8
View File
@@ -2,21 +2,19 @@ package validator_test
import (
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
dshelp "github.com/ipfs/go-ipfs-ds-help"
"github.com/jmoiron/sqlx"
)
// PublishRaw derives a cid from raw bytes and provided codec and multihash type, and writes it to the db tx
func PublishRaw(tx *sqlx.Tx, codec, mh uint64, raw []byte, blockNumber uint64) (string, error) {
func PublishRaw(tx *sqlx.Tx, codec, mh uint64, raw []byte, blockNumber uint64) error {
c, err := RawdataToCid(codec, raw, mh)
if err != nil {
return "", err
return err
}
dbKey := dshelp.MultihashToDsKey(c.Hash())
prefixedKey := blockstore.BlockPrefix.String() + dbKey.String()
_, err = tx.Exec(`INSERT INTO ipld.blocks (key, data, block_number) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`, prefixedKey, raw, blockNumber)
return c.String(), err
_, err = tx.Exec(
`INSERT INTO ipld.blocks (key, data, block_number) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`,
c.String(), raw, blockNumber)
return err
}
// RawdataToCid takes the desired codec, multihash type, and a slice of bytes
+7 -8
View File
@@ -25,12 +25,10 @@ import (
"github.com/spf13/viper"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ipfs/go-blockservice"
"github.com/jmoiron/sqlx"
"github.com/mailgun/groupcache/v2"
@@ -38,7 +36,9 @@ import (
"golang.org/x/sync/errgroup"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5"
pgipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v1"
pgipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
nodeiter "github.com/ethereum/go-ethereum/trie/concurrent_iterator"
"github.com/ethereum/go-ethereum/trie/concurrent_iterator/tracker"
)
@@ -203,10 +203,9 @@ func (v *Validator) iterate(it trie.NodeIterator, storage bool) error {
}
dataIt := dataTrie.NodeIterator(nil)
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
addrHash := common.BytesToHash(it.LeafKey())
_, err := v.stateDatabase.ContractCode(addrHash, common.BytesToHash(account.CodeHash))
_, err := v.stateDatabase.ContractCode(common.BytesToHash(account.CodeHash))
if err != nil {
return fmt.Errorf("code %x: %w (path %x)", account.CodeHash, err, nodeiter.HexToKeyBytes(it.Path()))
return fmt.Errorf("code hash %x: %w (path %x)", account.CodeHash, err, nodeiter.HexToKeyBytes(it.Path()))
}
}
for dataIt.Next(true) {
@@ -231,7 +230,7 @@ func iterateTracked(tree state.Trie, recoveryFile string, iterCount uint, fn fun
}
// attempt to restore from recovery file if it exists
iters, err := tracker.Restore(tree)
iters, err := tracker.Restore(tree.NodeIterator)
if err != nil {
return err
}
@@ -240,7 +239,7 @@ func iterateTracked(tree state.Trie, recoveryFile string, iterCount uint, fn fun
}
if iters == nil { // nothing restored
iters = nodeiter.SubtrieIterators(tree, iterCount)
iters = nodeiter.SubtrieIterators(tree.NodeIterator, iterCount)
for i, it := range iters {
iters[i] = tracker.Tracked(it, nil)
}
+18 -19
View File
@@ -17,7 +17,6 @@
package validator_test
import (
"fmt"
"math/big"
"os"
"path/filepath"
@@ -29,7 +28,7 @@ import (
cid "github.com/ipfs/go-cid/_rsrch/cidiface"
"github.com/jmoiron/sqlx"
"github.com/multiformats/go-multihash"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
@@ -203,7 +202,7 @@ var (
config = validator.Config{
Hostname: "localhost",
Name: "vulcanize_testing",
Name: "cerc_testing",
User: "vdbm",
Password: "password",
Port: 8077,
@@ -234,44 +233,40 @@ var _ = Describe("PG-IPFS Validator", func() {
It("Returns an error if the state root node is missing", func() {
// 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)
loadTrie(missingRootStateNodes, trieStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node"))
})
It("Returns an error if the storage root node is missing", func() {
loadTrie(append(trieStateNodes, mockCode), missingRootStorageNodes)
loadTrie(trieStateNodes, missingRootStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node"))
})
It("Returns an error if the state trie is missing node(s)", func() {
loadTrie(append(missingNodeStateNodes, mockCode), trieStorageNodes)
loadTrie(missingNodeStateNodes, trieStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node"))
pathSubStr := fmt.Sprintf("path %x", missingStateNodePath)
Expect(err.Error()).To(ContainSubstring(pathSubStr))
Expect(err.Error()).To(ContainSubstring("%x", missingStateNodePath))
})
It("Returns an error if the storage trie is missing node(s)", func() {
loadTrie(append(trieStateNodes, mockCode), missingNodeStorageNodes)
loadTrie(trieStateNodes, missingNodeStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node"))
pathSubStr := fmt.Sprintf("path %x", missingStorageNodePath)
Expect(err.Error()).To(ContainSubstring(pathSubStr))
Expect(err.Error()).To(ContainSubstring("%x", missingStorageNodePath))
})
It("Returns an error if contract code is missing", func() {
loadTrie(trieStateNodes, trieStorageNodes)
err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred())
codeSubStr := fmt.Sprintf("code %s: not found", codeHash.Hex()[2:])
Expect(err.Error()).To(ContainSubstring(codeSubStr))
pathSubStr := fmt.Sprintf("path %x", codePath)
Expect(err.Error()).To(ContainSubstring(pathSubStr))
Expect(err.Error()).To(ContainSubstring("%x", codeHash))
Expect(err.Error()).To(ContainSubstring("%x", codePath))
})
It("Returns no error if the entire state (state trie and storage tries) can be validated", func() {
loadTrie(append(trieStateNodes, mockCode), trieStorageNodes)
loadTrie(trieStateNodes, trieStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot)
Expect(err).ToNot(HaveOccurred())
})
@@ -326,15 +321,19 @@ var _ = Describe("PG-IPFS Validator", func() {
})
})
func loadTrie(stateNodes, storageNodes [][]byte) {
func loadTrie(stateNodes, storageNodes [][]byte, contractCode ...[]byte) {
tx, err := db.Beginx()
Expect(err).ToNot(HaveOccurred())
for _, node := range stateNodes {
_, err := PublishRaw(tx, cid.EthStateTrie, multihash.KECCAK_256, node, blockNumber)
err := PublishRaw(tx, cid.EthStateTrie, multihash.KECCAK_256, node, blockNumber)
Expect(err).ToNot(HaveOccurred())
}
for _, node := range storageNodes {
_, err := PublishRaw(tx, cid.EthStorageTrie, multihash.KECCAK_256, node, blockNumber)
err := PublishRaw(tx, cid.EthStorageTrie, multihash.KECCAK_256, node, blockNumber)
Expect(err).ToNot(HaveOccurred())
}
for _, code := range contractCode {
err := PublishRaw(tx, cid.Raw, multihash.KECCAK_256, code, blockNumber)
Expect(err).ToNot(HaveOccurred())
}
err = tx.Commit()