Compare commits

..

No commits in common. "v5" and "release-v4.0.7-alpha" have entirely different histories.

17 changed files with 1751 additions and 1310 deletions

View File

@ -1,38 +0,0 @@
name: Run tests
on:
- pull_request
env:
# Needed until we can incorporate docker startup into the executor container
DOCKER_HOST: unix:///var/run/dind.sock
jobs:
unit-tests:
name: Run unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version-file: 'go.mod'
check-latest: true
- name: Run dockerd
run: |
dockerd -H $DOCKER_HOST --userland-proxy=false &
sleep 5
- name: Run DB container
working-directory: ./test
run: docker compose up --wait --quiet-pull
- name: Set Gitea access token
env:
TOKEN: ${{ secrets.CICD_REPO_TOKEN }}
run: |
git config --global url."https://$TOKEN:@git.vdb.to/".insteadOf https://git.vdb.to/
- name: Build and run tests
run: |
until [[ "$(docker inspect -f '{{.State.Status}}' test-ipld-eth-db)" = 'running' ]]
do sleep 1; done &
go build ./...
wait $!
go test -p 1 -v ./...

View File

@ -1,8 +1,8 @@
# eth-ipfs-state-validator # eth-ipfs-state-validator
[![Go Report Card](https://goreportcard.com/badge/github.com/cerc-io/eth-ipfs-state-validator)](https://goreportcard.com/report/github.com/cerc-io/eth-ipfs-state-validator) [![Go Report Card](https://goreportcard.com/badge/github.com/vulcanize/eth-ipfs-state-validator)](https://goreportcard.com/report/github.com/vulcanize/eth-ipfs-state-validator)
> Uses [ipfs-ethdb](https://github.com/cerc-io/ipfs-ethdb/tree/master/postgres) to validate completeness of IPFS Ethereum state data > Uses [ipfs-ethdb](https://github.com/vulcanize/ipfs-ethdb/tree/master/postgres) to validate completeness of IPFS Ethereum state data
## Background ## Background
@ -42,7 +42,7 @@ Postgres DB config:
```toml ```toml
[database] [database]
name = "cerc_public" name = "vulcanize_public"
hostname = "localhost" hostname = "localhost"
user = "postgres" user = "postgres"
password = "" password = ""
@ -50,7 +50,7 @@ Postgres DB config:
``` ```
## Maintainers ## Maintainers
@cerc-io @vulcanize
@AFDudley @AFDudley
@i-norden @i-norden

View File

@ -85,7 +85,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location")
rootCmd.PersistentFlags().String("logfile", "", "file path for logging") rootCmd.PersistentFlags().String("logfile", "", "file path for logging")
rootCmd.PersistentFlags().String("database-name", "cerc_public", "database name") rootCmd.PersistentFlags().String("database-name", "vulcanize_public", "database name")
rootCmd.PersistentFlags().Int("database-port", 5432, "database port") rootCmd.PersistentFlags().Int("database-port", 5432, "database port")
rootCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname") rootCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname")
rootCmd.PersistentFlags().String("database-user", "", "database user") rootCmd.PersistentFlags().String("database-user", "", "database user")

View File

@ -24,7 +24,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg" validator "github.com/vulcanize/eth-ipfs-state-validator/v4/pkg"
) )
// validateTrieCmd represents the validateTrie command // validateTrieCmd represents the validateTrie command
@ -59,41 +59,33 @@ It can operate at three levels:
} }
func validateTrie() { func validateTrie() {
params := validator.Params{ numWorkers := viper.GetUint("validator.workers")
Workers: viper.GetUint("validator.workers"), v, err := newValidator(numWorkers)
RecoveryFormat: viper.GetString("validator.recoveryFormat"),
}
v, err := newValidator(params)
if err != nil { if err != nil {
logWithCommand.Fatal(err) logWithCommand.Fatal(err)
} }
stateRootStr := viper.GetString("validator.stateRoot") stateRootStr := viper.GetString("validator.stateRoot")
storageRootStr := viper.GetString("validator.storageRoot") storageRootStr := viper.GetString("validator.storageRoot")
contractAddrStr := viper.GetString("validator.address") contractAddrStr := viper.GetString("validator.address")
switch strings.ToLower(viper.GetString("validator.type")) {
case "f", "full":
if stateRootStr == "" {
logWithCommand.Fatal("must provide a state root for full state validation")
}
stateRoot := common.HexToHash(stateRootStr)
if err = v.ValidateTrie(stateRoot); err != nil {
logWithCommand.Fatalf("State for root %s is not complete\r\nerr: %v", stateRoot.String(), err)
}
logWithCommand.Infof("State for root %s is complete", stateRoot.String())
case "state":
if stateRootStr == "" { if stateRootStr == "" {
logWithCommand.Fatal("must provide a state root for state trie validation") logWithCommand.Fatal("must provide a state root for state trie validation")
} }
stateRoot := common.HexToHash(stateRootStr) stateRoot := common.HexToHash(stateRootStr)
traversal := strings.ToLower(viper.GetString("validator.type"))
switch traversal {
case "f", "full":
logWithCommand.
WithField("root", stateRoot).
Debug("Validating full state")
if err = v.ValidateTrie(stateRoot); err != nil {
logWithCommand.Fatalf("Validation failed: %v", err)
}
logWithCommand.Infof("State for root %s is complete", stateRoot)
case "state":
logWithCommand.
WithField("root", stateRoot).
Debug("Validating state trie")
if err = v.ValidateStateTrie(stateRoot); err != nil { if err = v.ValidateStateTrie(stateRoot); err != nil {
logWithCommand.Fatalf("Validation failed: %s", err) logWithCommand.Fatalf("State trie for root %s is not complete\r\nerr: %v", stateRoot.String(), err)
} }
logWithCommand.Infof("State trie for root %s is complete", stateRoot) logWithCommand.Infof("State trie for root %s is complete", stateRoot.String())
case "storage": case "storage":
if storageRootStr == "" { if storageRootStr == "" {
logWithCommand.Fatal("must provide a storage root for storage trie validation") logWithCommand.Fatal("must provide a storage root for storage trie validation")
@ -103,36 +95,30 @@ func validateTrie() {
} }
storageRoot := common.HexToHash(storageRootStr) storageRoot := common.HexToHash(storageRootStr)
addr := common.HexToAddress(contractAddrStr) addr := common.HexToAddress(contractAddrStr)
logWithCommand. if err = v.ValidateStorageTrie(addr, storageRoot); err != nil {
WithField("contract", addr). logWithCommand.Fatalf("Storage trie for contract %s and root %s not complete\r\nerr: %v", addr.String(), storageRoot.String(), err)
WithField("storage root", storageRoot).
Debug("Validating storage trie")
if err = v.ValidateStorageTrie(stateRoot, addr, storageRoot); err != nil {
logWithCommand.Fatal("Validation failed", err)
} }
logWithCommand.Infof("Storage trie for contract %s and root %s is complete", addr, storageRoot) logWithCommand.Infof("Storage trie for contract %s and root %s is complete", addr.String(), storageRoot.String())
default:
logWithCommand.Fatal("Invalid traversal level:", traversal)
} }
stats := v.GetCacheStats() stats := v.GetCacheStats()
logWithCommand.Debugf("groupcache stats %+v", stats) logWithCommand.Debugf("groupcache stats %+v", stats)
} }
func newValidator(params validator.Params) (*validator.Validator, error) { func newValidator(workers uint) (*validator.Validator, error) {
ipfsPath := viper.GetString("ipfs.path") ipfsPath := viper.GetString("ipfs.path")
if ipfsPath == "" { if ipfsPath == "" {
db, err := validator.NewDB() db, err := validator.NewDB()
if err != nil { if err != nil {
logWithCommand.Fatal(err) logWithCommand.Fatal(err)
} }
return validator.NewPGIPFSValidator(db, params), nil return validator.NewPGIPFSValidator(db, workers), nil
} }
bs, err := validator.InitIPFSBlockService(ipfsPath) bs, err := validator.InitIPFSBlockService(ipfsPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return validator.NewIPFSValidator(bs, params), nil return validator.NewIPFSValidator(bs, workers), nil
} }
func init() { func init() {
@ -144,13 +130,11 @@ func init() {
validateTrieCmd.PersistentFlags().String("address", "", "Contract address for the storage trie we wish to validate; for storage validation") validateTrieCmd.PersistentFlags().String("address", "", "Contract address for the storage trie we wish to validate; for storage validation")
validateTrieCmd.PersistentFlags().String("ipfs-path", "", "Path to IPFS repository; if provided operations move through the IPFS repo otherwise Postgres connection params are expected in the provided config") validateTrieCmd.PersistentFlags().String("ipfs-path", "", "Path to IPFS repository; if provided operations move through the IPFS repo otherwise Postgres connection params are expected in the provided config")
validateTrieCmd.PersistentFlags().Int("workers", 4, "number of concurrent workers to use") validateTrieCmd.PersistentFlags().Int("workers", 4, "number of concurrent workers to use")
validateTrieCmd.PersistentFlags().String("recovery-format", validator.DefaultRecoveryFormat, "format pattern for recovery files")
viper.BindPFlag("validator.stateRoot", validateTrieCmd.PersistentFlags().Lookup("state-root")) viper.BindPFlag("validator.stateRoot", validateTrieCmd.PersistentFlags().Lookup("state-root"))
viper.BindPFlag("validator.type", validateTrieCmd.PersistentFlags().Lookup("type")) viper.BindPFlag("validator.type", validateTrieCmd.PersistentFlags().Lookup("type"))
viper.BindPFlag("validator.storageRoot", validateTrieCmd.PersistentFlags().Lookup("storage-root")) viper.BindPFlag("validator.storageRoot", validateTrieCmd.PersistentFlags().Lookup("storage-root"))
viper.BindPFlag("validator.address", validateTrieCmd.PersistentFlags().Lookup("address")) viper.BindPFlag("validator.address", validateTrieCmd.PersistentFlags().Lookup("address"))
viper.BindPFlag("validator.workers", validateTrieCmd.PersistentFlags().Lookup("workers")) viper.BindPFlag("validator.workers", validateTrieCmd.PersistentFlags().Lookup("workers"))
viper.BindPFlag("validator.recoveryFormat", validateTrieCmd.PersistentFlags().Lookup("recovery-format"))
viper.BindPFlag("ipfs.path", validateTrieCmd.PersistentFlags().Lookup("ipfs-path")) viper.BindPFlag("ipfs.path", validateTrieCmd.PersistentFlags().Lookup("ipfs-path"))
} }

View File

@ -1,5 +1,5 @@
[database] [database]
name = "cerc_public" name = "vulcanize_public"
hostname = "localhost" hostname = "localhost"
port = 5432 port = 5432
user = "postgres" user = "postgres"

View File

@ -1,4 +1,4 @@
[database] [database]
name = "cerc_testing" name = "vulcanize_testing"
hostname = "localhost" hostname = "localhost"
port = 5432 port = 5432

386
go.mod
View File

@ -1,265 +1,239 @@
module github.com/cerc-io/eth-ipfs-state-validator/v5 module github.com/vulcanize/eth-ipfs-state-validator/v4
go 1.21 go 1.18
require ( require (
github.com/cerc-io/eth-iterator-utils v0.2.0 github.com/ethereum/go-ethereum v1.10.23
github.com/cerc-io/ipfs-ethdb/v5 v5.1.0-alpha github.com/ipfs/go-blockservice v0.4.0
github.com/cerc-io/ipld-eth-statedb v0.1.0 github.com/ipfs/go-cid v0.2.0
github.com/ethereum/go-ethereum v1.13.14 github.com/ipfs/go-ipfs-blockstore v1.2.0
github.com/holiman/uint256 v1.2.4 github.com/ipfs/go-ipfs-ds-help v1.1.0
github.com/ipfs/boxo v0.19.0 github.com/ipfs/kubo v0.14.0
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/kubo v0.27.0
github.com/jmoiron/sqlx v1.3.5 github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.6
github.com/mailgun/groupcache/v2 v2.3.0 github.com/mailgun/groupcache/v2 v2.3.0
github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-multihash v0.2.0
github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.30.0 github.com/onsi/gomega v1.19.0
github.com/sirupsen/logrus v1.9.0 github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.4.0
github.com/spf13/viper v1.18.2 github.com/spf13/viper v1.11.0
golang.org/x/sync v0.7.0 github.com/vulcanize/ipfs-ethdb/v4 v4.0.7-alpha
) )
require ( require (
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
github.com/DataDog/zstd v1.5.5 // indirect github.com/Stebalien/go-bitfield v0.0.1 // indirect
github.com/Jorropo/jsync v1.0.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd v0.22.1 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
github.com/cerc-io/plugeth-statediff v0.2.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cockroachdb/errors v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cheekybits/genny v1.0.0 // indirect
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/containerd/cgroups v1.0.3 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/cskr/pubsub v1.0.2 // indirect github.com/cskr/pubsub v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/docker/go-units v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/elastic/gosigar v0.14.2 // indirect github.com/elastic/gosigar v0.14.2 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
github.com/flynn/noise v1.1.0 // indirect github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
github.com/georgysavva/scany v0.2.9 // indirect
github.com/getsentry/sentry-go v0.22.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gopacket v1.1.19 // indirect github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/huin/goupnp v1.3.0 // indirect github.com/huin/goupnp v1.0.3 // indirect
github.com/inconshreveable/log15 v2.16.0+incompatible // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect
github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-bitswap v0.8.0 // indirect
github.com/ipfs/go-block-format v0.0.3 // indirect
github.com/ipfs/go-cidutil v0.1.0 // indirect github.com/ipfs/go-cidutil v0.1.0 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect github.com/ipfs/go-datastore v0.5.1 // indirect
github.com/ipfs/go-delegated-routing v0.3.0 // indirect
github.com/ipfs/go-ds-measure v0.2.0 // indirect github.com/ipfs/go-ds-measure v0.2.0 // indirect
github.com/ipfs/go-fetcher v1.6.1 // indirect
github.com/ipfs/go-filestore v1.2.0 //indirect
github.com/ipfs/go-fs-lock v0.0.7 // indirect github.com/ipfs/go-fs-lock v0.0.7 // indirect
github.com/ipfs/go-graphsync v0.13.1 // indirect
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect github.com/ipfs/go-ipfs-files v0.1.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect
github.com/ipfs/go-ipld-cbor v0.1.0 // indirect github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect
github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
github.com/ipfs/go-ipfs-provider v0.7.1 // indirect
github.com/ipfs/go-ipfs-routing v0.2.1 // indirect
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
github.com/ipfs/go-ipld-cbor v0.0.5 // indirect
github.com/ipfs/go-ipld-format v0.4.0 // indirect
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
github.com/ipfs/go-ipns v0.1.2 // indirect
github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-log v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipfs/go-merkledag v0.6.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect github.com/ipfs/go-mfs v0.2.1 // indirect
github.com/ipfs/go-unixfsnode v1.9.0 // indirect github.com/ipfs/go-namesys v0.5.0 // indirect
github.com/ipld/go-car/v2 v2.13.1 // indirect github.com/ipfs/go-path v0.3.0 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect github.com/ipfs/go-peertaskqueue v0.7.1 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/ipfs/go-unixfs v0.4.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/ipfs/go-unixfsnode v1.4.0 // indirect
github.com/jackc/pgconn v1.14.3 // indirect github.com/ipfs/go-verifcid v0.0.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/ipfs/interface-go-ipfs-core v0.7.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/ipld/edelweiss v0.1.4 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/ipld/go-codec-dagpb v1.4.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/ipld/go-ipld-prime v0.17.0 // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/jackc/puddle v1.3.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect github.com/jbenet/goprocess v0.1.4 // indirect
github.com/klauspost/compress v1.17.6 // indirect github.com/klauspost/compress v1.15.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect github.com/koron/go-ssdp v0.0.2 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-doh-resolver v0.4.0 // indirect github.com/libp2p/go-doh-resolver v0.4.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-eventbus v0.2.1 // indirect
github.com/libp2p/go-libp2p v0.33.0 // indirect github.com/libp2p/go-flow-metrics v0.0.3 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p v0.20.3 // indirect
github.com/libp2p/go-libp2p-kad-dht v0.24.4 // indirect github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-core v0.16.1 // indirect
github.com/libp2p/go-libp2p-pubsub v0.10.0 // indirect github.com/libp2p/go-libp2p-discovery v0.7.0 // indirect
github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect github.com/libp2p/go-libp2p-kad-dht v0.16.0 // indirect
github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect
github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // indirect github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect
github.com/libp2p/go-libp2p-peerstore v0.6.0 // indirect
github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect
github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect
github.com/libp2p/go-libp2p-record v0.1.3 // indirect
github.com/libp2p/go-libp2p-resource-manager v0.3.0 // indirect
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
github.com/libp2p/go-libp2p-swarm v0.11.0 // indirect
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-nat v0.2.0 // indirect github.com/libp2p/go-msgio v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-nat v0.1.0 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-netroute v0.2.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/go-openssl v0.0.7 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
github.com/libp2p/zeroconf/v2 v2.1.1 // indirect
github.com/lucas-clemente/quic-go v0.27.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/miekg/dns v1.1.58 // indirect github.com/miekg/dns v1.1.48 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base32 v0.0.4 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multiaddr v0.12.2 // indirect github.com/multiformats/go-multiaddr v0.5.0 // indirect
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multibase v0.1.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multicodec v0.5.0 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-multistream v0.3.3 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiformats/go-varint v0.0.6 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/openrelayxyz/plugeth-utils v1.5.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pelletier/go-toml v1.9.4 // indirect
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
github.com/pganalyze/pg_query_go/v4 v4.2.1 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.8 // indirect
github.com/pion/ice/v2 v2.3.11 // indirect
github.com/pion/interceptor v0.1.25 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.9 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.13 // indirect
github.com/pion/rtp v1.8.3 // indirect
github.com/pion/sctp v1.8.9 // indirect
github.com/pion/sdp/v3 v3.0.6 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect
github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.4 // indirect
github.com/pion/turn/v2 v2.1.4 // indirect
github.com/pion/webrtc/v3 v3.2.23 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/common v0.33.0 // indirect
github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/tsdb v0.10.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/raulk/clock v1.1.0 // indirect
github.com/quic-go/quic-go v0.41.0 // indirect github.com/raulk/go-watchdog v1.2.0 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/samber/lo v1.39.0 // indirect
github.com/segmentio/fasthash v1.0.3 // indirect github.com/segmentio/fasthash v1.0.3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.2.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/tidwall/gjson v1.14.0 // indirect
github.com/supranational/blst v0.3.11 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tidwall/pretty v1.2.0 // indirect
github.com/thoas/go-funk v0.9.3 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/vulcanize/go-eth-state-node-iterator v1.1.4
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect github.com/wI2L/jsondiff v0.2.0 // indirect
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20240109153615-66e95c3e8a87 // indirect
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
go.opencensus.io v0.24.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel/metric v1.25.0 // indirect go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.25.0 // indirect go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.uber.org/dig v1.17.1 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/fx v1.20.1 // indirect go.uber.org/dig v1.14.0 // indirect
go.uber.org/mock v0.4.0 // indirect go.uber.org/fx v1.16.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.21.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/crypto v0.22.0 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
golang.org/x/net v0.24.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.19.0 // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.1.10 // indirect
golang.org/x/tools v0.20.0 // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/protobuf v1.28.0 // indirect
gonum.org/v1/gonum v0.14.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect
google.golang.org/protobuf v1.32.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.2 // indirect lukechampine.com/blake3 v1.1.7 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
) )
replace github.com/ethereum/go-ethereum v1.10.23 => github.com/vulcanize/go-ethereum v1.10.23-statediff-4.2.0-alpha

2049
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ package main
import ( import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/cerc-io/eth-ipfs-state-validator/v5/cmd" "github.com/vulcanize/eth-ipfs-state-validator/v4/cmd"
) )
func main() { func main() {

View File

@ -18,8 +18,6 @@ package validator
import ( import (
"fmt" "fmt"
"os"
"strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -34,6 +32,13 @@ const (
DATABASE_PASSWORD = "DATABASE_PASSWORD" DATABASE_PASSWORD = "DATABASE_PASSWORD"
) )
// NewDB returns a new sqlx.DB from config/cli/env variables
func NewDB() (*sqlx.DB, error) {
c := Config{}
c.Init()
return sqlx.Connect("postgres", c.ConnString())
}
type Config struct { type Config struct {
Hostname string Hostname string
Name string Name string
@ -42,13 +47,6 @@ type Config struct {
Port int Port int
} }
// NewDB returns a new sqlx.DB from config/cli/env variables
func NewDB() (*sqlx.DB, error) {
c := Config{}
LoadViper(&c)
return sqlx.Connect("postgres", c.ConnString())
}
func (c *Config) ConnString() string { func (c *Config) ConnString() string {
if len(c.User) > 0 && len(c.Password) > 0 { if len(c.User) > 0 && len(c.Password) > 0 {
return fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?sslmode=disable", return fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?sslmode=disable",
@ -61,30 +59,7 @@ func (c *Config) ConnString() string {
return fmt.Sprintf("postgresql://%s:%d/%s?sslmode=disable", c.Hostname, c.Port, c.Name) return fmt.Sprintf("postgresql://%s:%d/%s?sslmode=disable", c.Hostname, c.Port, c.Name)
} }
func LoadEnv(c *Config) error { func (c *Config) Init() {
if val := os.Getenv(DATABASE_NAME); val != "" {
c.Name = val
}
if val := os.Getenv(DATABASE_HOSTNAME); val != "" {
c.Hostname = val
}
if val := os.Getenv(DATABASE_PORT); val != "" {
port, err := strconv.Atoi(val)
if err != nil {
return err
}
c.Port = port
}
if val := os.Getenv(DATABASE_USER); val != "" {
c.User = val
}
if val := os.Getenv(DATABASE_PASSWORD); val != "" {
c.Password = val
}
return nil
}
func LoadViper(c *Config) {
viper.BindEnv("database.name", DATABASE_NAME) viper.BindEnv("database.name", DATABASE_NAME)
viper.BindEnv("database.hostname", DATABASE_HOSTNAME) viper.BindEnv("database.hostname", DATABASE_HOSTNAME)
viper.BindEnv("database.port", DATABASE_PORT) viper.BindEnv("database.port", DATABASE_PORT)

View File

@ -19,7 +19,7 @@ package validator_test
import ( import (
"testing" "testing"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@ -1,9 +0,0 @@
package validator
type TraversalType = string
const (
fullTraversal = "full"
stateTraversal = "state"
storageTraversal = "storage"
)

View File

@ -19,11 +19,42 @@ package validator
import ( import (
"context" "context"
"github.com/ipfs/boxo/blockservice" "github.com/ipfs/go-blockservice"
"github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
dshelp "github.com/ipfs/go-ipfs-ds-help"
"github.com/ipfs/kubo/core" "github.com/ipfs/kubo/core"
"github.com/ipfs/kubo/repo/fsrepo" "github.com/ipfs/kubo/repo/fsrepo"
"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) {
c, err := RawdataToCid(codec, raw, mh)
if err != nil {
return "", err
}
dbKey := dshelp.MultihashToDsKey(c.Hash())
prefixedKey := blockstore.BlockPrefix.String() + dbKey.String()
_, err = tx.Exec(`INSERT INTO public.blocks (key, data, block_number) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING`, prefixedKey, raw, blockNumber)
return c.String(), err
}
// RawdataToCid takes the desired codec, multihash type, and a slice of bytes
// and returns the proper cid of the object.
func RawdataToCid(codec uint64, rawdata []byte, multiHash uint64) (cid.Cid, error) {
c, err := cid.Prefix{
Codec: codec,
Version: 1,
MhType: multiHash,
MhLength: -1,
}.Sum(rawdata)
if err != nil {
return cid.Cid{}, err
}
return c, nil
}
// InitIPFSBlockService is used to configure and return a BlockService using an ipfs repo path (e.g. ~/.ipfs) // InitIPFSBlockService is used to configure and return a BlockService using an ipfs repo path (e.g. ~/.ipfs)
func InitIPFSBlockService(ipfsPath string) (blockservice.BlockService, error) { func InitIPFSBlockService(ipfsPath string) (blockservice.BlockService, error) {
r, openErr := fsrepo.Open(ipfsPath) r, openErr := fsrepo.Open(ipfsPath)
@ -41,3 +72,9 @@ func InitIPFSBlockService(ipfsPath string) (blockservice.BlockService, error) {
} }
return ipfsNode.Blocks, nil return ipfsNode.Blocks, nil
} }
// ResetTestDB drops all rows in the test db public.blocks table
func ResetTestDB(db *sqlx.DB) error {
_, err := db.Exec("DELETE FROM public.blocks")
return err
}

View File

@ -1,39 +0,0 @@
package validator_test
import (
"github.com/ipfs/go-cid"
"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) error {
c, err := RawdataToCid(codec, raw, mh)
if err != nil {
return 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
// and returns the proper cid of the object.
func RawdataToCid(codec uint64, rawdata []byte, multiHash uint64) (cid.Cid, error) {
c, err := cid.Prefix{
Codec: codec,
Version: 1,
MhType: multiHash,
MhLength: -1,
}.Sum(rawdata)
if err != nil {
return cid.Cid{}, err
}
return c, nil
}
// ResetTestDB truncates all used tables from the test DB
func ResetTestDB(db *sqlx.DB) error {
_, err := db.Exec("TRUNCATE ipld.blocks")
return err
}

View File

@ -18,66 +18,40 @@ package validator
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"os" "sync"
"os/signal"
"syscall"
"time" "time"
"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/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ipfs/boxo/blockservice" "github.com/ethereum/go-ethereum/trie"
"github.com/ipfs/go-blockservice"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/mailgun/groupcache/v2" "github.com/mailgun/groupcache/v2"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
iterutils "github.com/cerc-io/eth-iterator-utils" nodeiter "github.com/vulcanize/go-eth-state-node-iterator"
"github.com/cerc-io/eth-iterator-utils/tracker" ipfsethdb "github.com/vulcanize/ipfs-ethdb/v4"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5" pgipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres"
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"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/triedb"
) )
// Validator is used for validating Ethereum state and storage tries on PG-IPFS // Validator is used for validating Ethereum state and storage tries on PG-IPFS
type Validator struct { type Validator struct {
kvs ethdb.KeyValueStore kvs ethdb.KeyValueStore
trieDB *triedb.Database trieDB *trie.Database
stateDatabase state.Database stateDatabase state.Database
db *pgipfsethdb.Database db *pgipfsethdb.Database
params Params iterWorkers uint
} }
type Params struct { var emptyCodeHash = crypto.Keccak256(nil)
Workers uint
RecoveryFormat string // %s substituted with traversal type
}
var (
DefaultRecoveryFormat = "./recover_validate_%s"
emptyCodeHash = crypto.Keccak256(nil)
)
type KVSWithAncient struct {
kvs ethdb.KeyValueStore
ethdb.Database
}
func NewKVSDatabaseWithAncient(kvs ethdb.KeyValueStore) ethdb.Database {
return &KVSWithAncient{
kvs: kvs,
}
}
// NewPGIPFSValidator returns a new trie validator ontop of a connection pool for an IPFS backing Postgres database // NewPGIPFSValidator returns a new trie validator ontop of a connection pool for an IPFS backing Postgres database
func NewPGIPFSValidator(db *sqlx.DB, par Params) *Validator { func NewPGIPFSValidator(db *sqlx.DB, workers uint) *Validator {
kvs := pgipfsethdb.NewKeyValueStore(db, pgipfsethdb.CacheConfig{ kvs := pgipfsethdb.NewKeyValueStore(db, pgipfsethdb.CacheConfig{
Name: "kv", Name: "kv",
Size: 16 * 1000 * 1000, // 16MB Size: 16 * 1000 * 1000, // 16MB
@ -90,13 +64,15 @@ func NewPGIPFSValidator(db *sqlx.DB, par Params) *Validator {
ExpiryDuration: time.Hour * 8, // 8 hours ExpiryDuration: time.Hour * 8, // 8 hours
}) })
normalizeParams(&par) if workers == 0 {
workers = 1
}
return &Validator{ return &Validator{
kvs: kvs, kvs: kvs,
trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil), trieDB: trie.NewDatabase(kvs),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
db: database.(*pgipfsethdb.Database), db: database.(*pgipfsethdb.Database),
params: par, iterWorkers: workers,
} }
} }
@ -105,15 +81,17 @@ func (v *Validator) GetCacheStats() groupcache.Stats {
} }
// NewIPFSValidator returns a new trie validator ontop of an IPFS blockservice // NewIPFSValidator returns a new trie validator ontop of an IPFS blockservice
func NewIPFSValidator(bs blockservice.BlockService, par Params) *Validator { func NewIPFSValidator(bs blockservice.BlockService, workers uint) *Validator {
kvs := ipfsethdb.NewKeyValueStore(bs) kvs := ipfsethdb.NewKeyValueStore(bs)
database := ipfsethdb.NewDatabase(bs) database := ipfsethdb.NewDatabase(bs)
normalizeParams(&par) if workers == 0 {
workers = 1
}
return &Validator{ return &Validator{
kvs: kvs, kvs: kvs,
trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil), trieDB: trie.NewDatabase(kvs),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
params: par, iterWorkers: workers,
} }
} }
@ -123,19 +101,76 @@ func NewIPFSValidator(bs blockservice.BlockService, par Params) *Validator {
func NewValidator(kvs ethdb.KeyValueStore, database ethdb.Database) *Validator { func NewValidator(kvs ethdb.KeyValueStore, database ethdb.Database) *Validator {
return &Validator{ return &Validator{
kvs: kvs, kvs: kvs,
trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil), trieDB: trie.NewDatabase(kvs),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
} }
} }
// Ensure params are valid // Traverses each iterator in a separate goroutine.
func normalizeParams(p *Params) { // If storage = true, also traverse storage tries for each leaf.
if p.Workers == 0 { func (v *Validator) iterateAsync(iters []trie.NodeIterator, storage bool) error {
p.Workers = 1 var wg sync.WaitGroup
errors := make(chan error)
for _, it := range iters {
wg.Add(1)
go func(it trie.NodeIterator) {
defer wg.Done()
for it.Next(true) {
// Iterate through entire state trie. it.Next() will return false when we have
// either completed iteration of the entire trie or run into an error (e.g. a
// missing node). If we are able to iterate through the entire trie without error
// then the trie is complete.
// If storage is not requested, or the state trie node is an internal entry, leave as is
if !storage || !it.Leaf() {
continue
} }
if len(p.RecoveryFormat) == 0 { // Otherwise we've reached an account node, initiate data iteration
p.RecoveryFormat = DefaultRecoveryFormat var account types.StateAccount
if err := rlp.Decode(bytes.NewReader(it.LeafBlob()), &account); err != nil {
errors <- err
break
} }
dataTrie, err := v.stateDatabase.OpenStorageTrie(common.BytesToHash(it.LeafKey()), account.Root)
if err != nil {
errors <- err
break
}
dataIt := dataTrie.NodeIterator(nil)
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
addrHash := common.BytesToHash(it.LeafKey())
_, err := v.stateDatabase.ContractCode(addrHash, common.BytesToHash(account.CodeHash))
if err != nil {
errors <- fmt.Errorf("code %x: %v", account.CodeHash, err)
break
}
}
for dataIt.Next(true) {
}
if err = dataIt.Error(); err != nil {
errors <- err
break
}
}
if it.Error() != nil {
errors <- it.Error()
}
}(it)
}
done := make(chan struct{})
go func() {
wg.Wait()
done <- struct{}{}
}()
var err error
select {
case err = <-errors:
case <-done:
close(errors)
}
return err
} }
// ValidateTrie returns an error if the state and storage tries for the provided state root cannot be confirmed as complete // ValidateTrie returns an error if the state and storage tries for the provided state root cannot be confirmed as complete
@ -145,8 +180,8 @@ func (v *Validator) ValidateTrie(stateRoot common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, true) } iters := nodeiter.SubtrieIterators(t, v.iterWorkers)
return iterateTracked(t, fmt.Sprintf(v.params.RecoveryFormat, fullTraversal), v.params.Workers, iterate) return v.iterateAsync(iters, true)
} }
// ValidateStateTrie returns an error if the state trie for the provided state root cannot be confirmed as complete // ValidateStateTrie returns an error if the state trie for the provided state root cannot be confirmed as complete
@ -157,21 +192,20 @@ func (v *Validator) ValidateStateTrie(stateRoot common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, false) } iters := nodeiter.SubtrieIterators(t, v.iterWorkers)
return iterateTracked(t, fmt.Sprintf(v.params.RecoveryFormat, stateTraversal), v.params.Workers, iterate) return v.iterateAsync(iters, false)
} }
// ValidateStorageTrie returns an error if the storage trie for the provided storage root and contract address cannot be confirmed as complete // ValidateStorageTrie returns an error if the storage trie for the provided storage root and contract address cannot be confirmed as complete
func (v *Validator) ValidateStorageTrie(stateRoot common.Hash, address common.Address, storageRoot common.Hash) error { func (v *Validator) ValidateStorageTrie(address common.Address, storageRoot common.Hash) error {
// Generate the state.NodeIterator for this root // Generate the state.NodeIterator for this root
addrHash := crypto.Keccak256Hash(address.Bytes()) addrHash := crypto.Keccak256Hash(address.Bytes())
// Note: the last argument is the redundant state trie, but will be needed for Verkle tries t, err := v.stateDatabase.OpenStorageTrie(addrHash, storageRoot)
storage, err := v.stateDatabase.OpenStorageTrie(stateRoot, addrHash, storageRoot, nil)
if err != nil { if err != nil {
return err return err
} }
iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, false) } iters := nodeiter.SubtrieIterators(t, v.iterWorkers)
return iterateTracked(storage, fmt.Sprintf(v.params.RecoveryFormat, storageTraversal), v.params.Workers, iterate) return v.iterateAsync(iters, false)
} }
// Close implements io.Closer // Close implements io.Closer
@ -181,111 +215,3 @@ func (v *Validator) Close() error {
groupcache.DeregisterGroup("db") groupcache.DeregisterGroup("db")
return nil return nil
} }
// Traverses one iterator fully
// If storage = true, also traverse storage tries for each leaf.
func (v *Validator) iterate(ctx context.Context, stateRoot common.Hash, it trie.NodeIterator, storage bool) error {
// Iterate through entire state trie. it.Next() will return false when we have
// either completed iteration of the entire trie or run into an error (e.g. a
// missing node). If we are able to iterate through the entire trie without error
// then the trie is complete.
for it.Next(true) {
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// This block adapted from geth - core/state/iterator.go
// If storage is not requested, or the state trie node is an internal entry, skip
if !storage || !it.Leaf() {
continue
}
// Otherwise we've reached an account node, initiate data iteration
var account types.StateAccount
if err := rlp.Decode(bytes.NewReader(it.LeafBlob()), &account); err != nil {
return err
}
// Note: the last argument is the redundant state trie, but will be needed for Verkle tries
dataTrie, err := v.stateDatabase.OpenStorageTrie(stateRoot, common.BytesToHash(it.LeafKey()), account.Root, nil)
if err != nil {
return err
}
dataIt, err := dataTrie.NodeIterator(nil)
if err != nil {
return err
}
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
_, err := v.stateDatabase.ContractCode(common.Address{}, common.BytesToHash(account.CodeHash))
if err != nil {
return fmt.Errorf("code hash %x: %w (path %x)", account.CodeHash, err, iterutils.HexToKeyBytes(it.Path()))
}
}
for dataIt.Next(true) {
}
if dataIt.Error() != nil {
return fmt.Errorf("data iterator error (path %x): %w", iterutils.HexToKeyBytes(dataIt.Path()), dataIt.Error())
}
}
return it.Error()
}
// Traverses each iterator in a separate goroutine.
// Dumps to a recovery file on failure or interrupt.
func iterateTracked(
tree state.Trie,
recoveryFile string,
iterCount uint,
fn func(context.Context, trie.NodeIterator) error,
) error {
tracker := tracker.New(recoveryFile, iterCount)
halt := func() {
if err := tracker.CloseAndSave(); err != nil {
log.Errorf("failed to write recovery file: %v", err)
}
}
// attempt to restore from recovery file if it exists
iters, _, err := tracker.Restore(tree.NodeIterator)
if err != nil {
return err
}
if iterCount < uint(len(iters)) {
return fmt.Errorf("recovered too many iterators: got %d, expected %d", len(iters), iterCount)
}
if iters == nil { // nothing restored
iters, err = iterutils.SubtrieIterators(tree.NodeIterator, iterCount)
if err != nil {
return err
}
for i, it := range iters {
iters[i] = tracker.Tracked(it)
}
} else {
log.Debugf("restored %d iterators from: %s", len(iters), recoveryFile)
}
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigChan
log.Errorf("Signal received (%v), stopping", sig)
cancel()
}()
defer halt()
for _, it := range iters {
func(it trie.NodeIterator) {
g.Go(func() error {
return fn(ctx, it)
})
}(it)
}
return g.Wait()
}

View File

@ -17,21 +17,21 @@
package validator_test package validator_test
import ( import (
"os" "fmt"
"path/filepath" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"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/crypto"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
cid "github.com/ipfs/go-cid/_rsrch/cidiface" cid "github.com/ipfs/go-cid/_rsrch/cidiface"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg" validator "github.com/vulcanize/eth-ipfs-state-validator/v4/pkg"
pgipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres"
) )
var ( var (
@ -66,10 +66,9 @@ var (
mockCode = []byte{1, 2, 3, 4, 5} mockCode = []byte{1, 2, 3, 4, 5}
codeHash = crypto.Keccak256Hash(mockCode) codeHash = crypto.Keccak256Hash(mockCode)
codePath = common.Hex2Bytes("6114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45")
contractAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ contractAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 1, Nonce: 1,
Balance: uint256.NewInt(0), Balance: big.NewInt(0),
CodeHash: codeHash.Bytes(), CodeHash: codeHash.Bytes(),
Root: crypto.Keccak256Hash(storageBranchRootNode), Root: crypto.Keccak256Hash(storageBranchRootNode),
}) })
@ -80,7 +79,7 @@ var (
minerAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ minerAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 0, Nonce: 0,
Balance: uint256.NewInt(1000), Balance: big.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -91,7 +90,7 @@ var (
account1, _ = rlp.EncodeToBytes(&types.StateAccount{ account1, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 2, Nonce: 2,
Balance: uint256.NewInt(1000), Balance: big.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -102,7 +101,7 @@ var (
account2, _ = rlp.EncodeToBytes(&types.StateAccount{ account2, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 0, Nonce: 0,
Balance: uint256.NewInt(1000), Balance: big.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -113,7 +112,7 @@ var (
bankAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ bankAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 2, Nonce: 2,
Balance: uint256.NewInt(1000), Balance: big.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -189,84 +188,63 @@ var (
storageBranchRootNode, storageBranchRootNode,
slot1StorageLeafNode, slot1StorageLeafNode,
} }
missingStateNodePath = common.Hex2Bytes("0e")
missingStorageNodePath = common.Hex2Bytes("02")
) )
var ( var (
v *validator.Validator v *validator.Validator
db *sqlx.DB db *sqlx.DB
err error err error
tmp string
config = validator.Config{
Hostname: "localhost",
Name: "cerc_testing",
User: "vdbm",
Password: "password",
Port: 8077,
}
) )
var _ = Describe("PG-IPFS Validator", func() { var _ = Describe("PG-IPFS Validator", func() {
BeforeEach(func() { BeforeEach(func() {
err = validator.LoadEnv(&config) db, err = pgipfsethdb.TestDB()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
db, err = sqlx.Connect("postgres", config.ConnString()) v = validator.NewPGIPFSValidator(db, 4)
Expect(err).ToNot(HaveOccurred())
tmp, err = os.MkdirTemp("", "test_validator")
Expect(err).ToNot(HaveOccurred())
params := validator.Params{Workers: 4, RecoveryFormat: filepath.Join(tmp, "recover_%s")}
v = validator.NewPGIPFSValidator(db, params)
}) })
AfterEach(func() { AfterEach(func() {
os.RemoveAll(tmp)
v.Close() v.Close()
db.Close()
}) })
Describe("ValidateTrie", func() { Describe("ValidateTrie", func() {
AfterEach(func() { AfterEach(func() {
err = ResetTestDB(db) err = validator.ResetTestDB(db)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Returns an error if the state root node is missing", func() { It("Returns an error the state root node is missing", func() {
// we write code to ethdb, there should probably be an EthCode IPLD codec // 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 // but there isn't, and we don't need one here since blockstore keys are mh-derived
loadTrie(missingRootStateNodes, trieStorageNodes, mockCode) 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("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
}) })
It("Returns an error if the storage root node is missing", func() { It("Returns an error if the storage root node is missing", func() {
loadTrie(trieStateNodes, missingRootStorageNodes, mockCode) loadTrie(append(trieStateNodes, mockCode), missingRootStorageNodes)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
}) })
It("Returns an error if the state trie is missing node(s)", func() { It("Returns an error if the state trie is missing node(s)", func() {
loadTrie(missingNodeStateNodes, trieStorageNodes, mockCode) loadTrie(append(missingNodeStateNodes, mockCode), trieStorageNodes)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
Expect(err.Error()).To(ContainSubstring("path %x", missingStateNodePath))
}) })
It("Returns an error if the storage trie is missing node(s)", func() { It("Returns an error if the storage trie is missing node(s)", func() {
loadTrie(trieStateNodes, missingNodeStorageNodes, mockCode) loadTrie(append(trieStateNodes, mockCode), missingNodeStorageNodes)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
Expect(err.Error()).To(ContainSubstring("path %x", missingStorageNodePath))
}) })
It("Returns an error if contract code is missing", func() { It("Returns an error if contract code is missing", func() {
loadTrie(trieStateNodes, trieStorageNodes) loadTrie(trieStateNodes, trieStorageNodes)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("%x", codeHash)) subStr := fmt.Sprintf("code %s: not found", codeHash.Hex()[2:])
Expect(err.Error()).To(ContainSubstring("%x", codePath)) 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, mockCode) loadTrie(append(trieStateNodes, mockCode), trieStorageNodes)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
@ -274,7 +252,7 @@ var _ = Describe("PG-IPFS Validator", func() {
Describe("ValidateStateTrie", func() { Describe("ValidateStateTrie", func() {
AfterEach(func() { AfterEach(func() {
err = ResetTestDB(db) err = validator.ResetTestDB(db)
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() {
@ -288,7 +266,6 @@ var _ = Describe("PG-IPFS Validator", func() {
err = v.ValidateStateTrie(stateRoot) err = v.ValidateStateTrie(stateRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
Expect(err.Error()).To(ContainSubstring("path %x", missingStateNodePath))
}) })
It("Returns no error if the entire state trie can be validated", func() { It("Returns no error if the entire state trie can be validated", func() {
loadTrie(trieStateNodes, nil) loadTrie(trieStateNodes, nil)
@ -299,43 +276,38 @@ var _ = Describe("PG-IPFS Validator", func() {
Describe("ValidateStorageTrie", func() { Describe("ValidateStorageTrie", func() {
AfterEach(func() { AfterEach(func() {
err = ResetTestDB(db) err = validator.ResetTestDB(db)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Returns an error if the storage root node is missing", func() { It("Returns an error the storage root node is missing", func() {
loadTrie(nil, missingRootStorageNodes) loadTrie(nil, missingRootStorageNodes)
err = v.ValidateStorageTrie(common.Hash{}, contractAddr, storageRoot) err = v.ValidateStorageTrie(contractAddr, storageRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
}) })
It("Returns an error if the entire storage trie cannot be validated", func() { It("Returns an error if the entire storage trie cannot be validated", func() {
loadTrie(nil, missingNodeStorageNodes) loadTrie(nil, missingNodeStorageNodes)
err = v.ValidateStorageTrie(common.Hash{}, contractAddr, storageRoot) err = v.ValidateStorageTrie(contractAddr, storageRoot)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("missing trie node")) Expect(err.Error()).To(ContainSubstring("missing trie node"))
Expect(err.Error()).To(ContainSubstring("path %x", missingStorageNodePath))
}) })
It("Returns no error if the entire storage trie can be validated", func() { It("Returns no error if the entire storage trie can be validated", func() {
loadTrie(nil, trieStorageNodes) loadTrie(nil, trieStorageNodes)
err = v.ValidateStorageTrie(common.Hash{}, contractAddr, storageRoot) err = v.ValidateStorageTrie(contractAddr, storageRoot)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
}) })
}) })
func loadTrie(stateNodes, storageNodes [][]byte, contractCode ...[]byte) { func loadTrie(stateNodes, storageNodes [][]byte) {
tx, err := db.Beginx() tx, err := db.Beginx()
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
for _, node := range stateNodes { for _, node := range stateNodes {
err := PublishRaw(tx, cid.EthStateTrie, multihash.KECCAK_256, node, blockNumber) _, err := validator.PublishRaw(tx, cid.EthStateTrie, multihash.KECCAK_256, node, blockNumber)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
} }
for _, node := range storageNodes { for _, node := range storageNodes {
err := PublishRaw(tx, cid.EthStorageTrie, multihash.KECCAK_256, node, blockNumber) _, err := validator.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()) Expect(err).ToNot(HaveOccurred())
} }
err = tx.Commit() err = tx.Commit()

View File

@ -1,28 +0,0 @@
# Containers to run backing DB for testing
services:
migrations:
restart: on-failure
depends_on:
- ipld-eth-db
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v5.2.1-alpha
environment:
DATABASE_USER: "vdbm"
DATABASE_NAME: "cerc_testing"
DATABASE_PASSWORD: "password"
DATABASE_HOSTNAME: "ipld-eth-db"
DATABASE_PORT: 5432
ipld-eth-db:
container_name: test-ipld-eth-db
image: timescale/timescaledb:latest-pg14
restart: always
command: ["postgres", "-c", "log_statement=all"]
environment:
POSTGRES_USER: "vdbm"
POSTGRES_DB: "cerc_testing"
POSTGRES_PASSWORD: "password"
ports:
- "127.0.0.1:8077:5432"
volumes:
- ./statediff/indexer/database/file:/file_indexer