Compare commits

..

39 Commits

Author SHA1 Message Date
23e838f9ac Geth 1.13 (Deneb/Cancun) update (#7)
Reviewed-on: cerc-io/eth-ipfs-state-validator#7
Reviewed-by: Thomas E Lackey <telackey@noreply.git.vdb.to>
2024-05-29 10:41:25 +00:00
cdff0776fd Fix signal handling (#3)
Reviewed-on: cerc-io/eth-ipfs-state-validator#3
2023-10-03 13:32:32 +00:00
e1ab6a17b8 Update to plugeth-statediff 0.1.4 (#2)
Reviewed-on: cerc-io/eth-ipfs-state-validator#2
Co-authored-by: Thomas E Lackey <telackey@bozemanpass.com>
Co-committed-by: Thomas E Lackey <telackey@bozemanpass.com>
2023-09-30 05:50:06 +00:00
471da6be82 Refactor to use plugeth-statediff (#1)
Reviewed-on: cerc-io/eth-ipfs-state-validator#1
2023-09-20 06:28:06 +00:00
5eeeecf667
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
2023-05-18 22:46:51 -05:00
f09675a0f3
Update to v5 schema (#72) 2023-04-29 01:40:03 -05:00
Ian Norden
cc53aa02b2
Merge pull request #69 from cerc-io/ian/v4_dev
update deps
2023-03-31 08:46:04 -05:00
i-norden
0671028e81 update deps 2023-03-31 08:39:41 -05:00
Michael
63c11188a3
Merge pull request #67 from cerc-io/upgrade_go_1_19
bump kubo version  allowing go 1.19
2023-03-17 14:32:26 -04:00
Michael Shaw
05946fc063 run build and tests on go 1.19 2023-03-17 14:28:50 -04:00
Michael Shaw
07b5ceb36c bump kubo version to eliminate quic-go 0.27.1 for 0.33.0, allowing go 1.19 2023-03-17 14:26:27 -04:00
Michael
bb8f4574cb
Merge pull request #65 from cerc-io/rebase-1.11.4-wip
version update for geth 1.11.4 statediffing 4.3.9
2023-03-17 13:28:35 -04:00
Michael Shaw
106255d17a version update for geth 1.11.4 statediffing 4.3.9 2023-03-17 13:17:22 -04:00
Michael
c7693c4d60
Merge pull request #64 from cerc-io/v4.0.12-tests-version-bump
go mod tidy
2023-03-16 11:40:55 -04:00
Michael Shaw
ed08f73a25 go mod tidy 2023-03-16 11:32:13 -04:00
Ian Norden
47fbfc5d67
Merge pull request #63 from cerc-io/roy/fix-unit-tests-again
Add missing file to fix unit test refactor
2023-03-16 08:19:02 -05:00
3e2e8bc295 Add missing file to fix unit tests 2023-03-16 08:28:52 +08:00
Michael
058a1ae3cc
Merge pull request #62 from cerc-io/rebase-1.11.2-wip
Rebase 1.11.2 wip
2023-03-15 18:20:01 -04:00
Michael Shaw
5db20e537f go mod and sum updated for geth 1.11.2 4.3.7 statediffing 2023-03-15 17:36:11 -04:00
Michael Shaw
8f5cee5be6 interface changes from ethdb.Database and state/storage validation, run db container(s) for go test -v ./... in CICD 2023-03-15 17:35:44 -04:00
Michael Shaw
31c3436624 go mod and sum updated for geth 1.11.2 4.3.7 statediffing 2023-03-15 16:54:04 -04:00
Michael
c32409b210
Merge pull request #61 from cerc-io/ABastionOfSanity-patch-2
Create basic-build-test.yml
Only does go build at this point.  go test in separate PR, as more complicated.
2023-03-15 16:43:49 -04:00
Michael
1285590a54
Update basic-build-test.yml
just build to get workflow integrated.
Will flesh out more complicated testing scenario (needs db containers) in separate PR
2023-03-15 16:34:37 -04:00
Michael
22724f64ae
Create basic-build-test.yml 2023-03-15 16:08:09 -04:00
Michael
449376ee1e
Merge pull request #60 from cerc-io/unit_tests_fix
fix broken unit tests
2023-03-15 16:02:53 -04:00
i-norden
7935334888 fix unit tests 2023-03-15 14:09:43 -05:00
Ian Norden
9930065d40
Merge pull request #45 from roysc/improve-logging
Improve logging on failed traversal
2023-03-10 10:24:00 -06:00
efeb7ff7e6 clean up 2023-03-10 23:48:28 +08:00
32f174de16 refactor config 2023-03-10 15:54:22 +08:00
cc1f054632 Improve logging on failure 2023-03-10 14:16:58 +08:00
Michael
edecb9d1cc
Merge pull request #46 from cerc-io/v4.0.10-wip
dependency updates for geth 1.10.26
2022-11-07 13:46:42 -05:00
Michael Shaw
97e7ea67c1 dependency updates for geth 1.10.26 2022-11-07 13:35:40 -05:00
1e7528e339
Merge pull request #41 from roysc/with-recovery
Fix module versions
2022-10-21 08:24:55 -05:00
f5a0e32c44 Fix module versions 2022-10-21 06:23:48 -07:00
Michael
2c21e86452
Merge pull request #44 from cerc-io/geth-1.10.25-wip
dependency updates for geth 1.10.25 rebase
2022-09-23 14:08:15 -04:00
Michael Shaw
b37de4fc32 dependency updates for geth 1.10.25 rebase 2022-09-23 14:07:11 -04:00
Michael
74f49e0e8b
Cerc refactor (#43)
* pointing to unpublished versions

* pointing to unpublished versions

* updated for bumped go-eth-state-node-iterator and other cerc refactors
2022-09-14 15:01:21 -04:00
de813d73e6
Merge pull request #39 from roysc/with-recovery
Track and restore iterator state
2022-09-07 00:22:26 -05:00
defc4c8c06 Track and recover iteration state 2022-09-07 07:21:59 +02:00
17 changed files with 1309 additions and 1750 deletions

38
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,38 @@
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/vulcanize/eth-ipfs-state-validator)](https://goreportcard.com/report/github.com/vulcanize/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)
> Uses [ipfs-ethdb](https://github.com/vulcanize/ipfs-ethdb/tree/master/postgres) to validate completeness of IPFS Ethereum state data > Uses [ipfs-ethdb](https://github.com/cerc-io/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 = "vulcanize_public" name = "cerc_public"
hostname = "localhost" hostname = "localhost"
user = "postgres" user = "postgres"
password = "" password = ""
@ -50,7 +50,7 @@ Postgres DB config:
``` ```
## Maintainers ## Maintainers
@vulcanize @cerc-io
@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", "vulcanize_public", "database name") rootCmd.PersistentFlags().String("database-name", "cerc_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/vulcanize/eth-ipfs-state-validator/v4/pkg" validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
) )
// validateTrieCmd represents the validateTrie command // validateTrieCmd represents the validateTrie command
@ -59,33 +59,41 @@ It can operate at three levels:
} }
func validateTrie() { func validateTrie() {
numWorkers := viper.GetUint("validator.workers") params := validator.Params{
v, err := newValidator(numWorkers) Workers: viper.GetUint("validator.workers"),
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")) {
if stateRootStr == "" {
logWithCommand.Fatal("must provide a state root for state trie validation")
}
stateRoot := common.HexToHash(stateRootStr)
traversal := strings.ToLower(viper.GetString("validator.type"))
switch traversal {
case "f", "full": case "f", "full":
if stateRootStr == "" { logWithCommand.
logWithCommand.Fatal("must provide a state root for full state validation") WithField("root", stateRoot).
} Debug("Validating full state")
stateRoot := common.HexToHash(stateRootStr)
if err = v.ValidateTrie(stateRoot); err != nil { if err = v.ValidateTrie(stateRoot); err != nil {
logWithCommand.Fatalf("State for root %s is not complete\r\nerr: %v", stateRoot.String(), err) logWithCommand.Fatalf("Validation failed: %v", err)
} }
logWithCommand.Infof("State for root %s is complete", stateRoot.String()) logWithCommand.Infof("State for root %s is complete", stateRoot)
case "state": case "state":
if stateRootStr == "" { logWithCommand.
logWithCommand.Fatal("must provide a state root for state trie validation") WithField("root", stateRoot).
} Debug("Validating state trie")
stateRoot := common.HexToHash(stateRootStr)
if err = v.ValidateStateTrie(stateRoot); err != nil { if err = v.ValidateStateTrie(stateRoot); err != nil {
logWithCommand.Fatalf("State trie for root %s is not complete\r\nerr: %v", stateRoot.String(), err) logWithCommand.Fatalf("Validation failed: %s", err)
} }
logWithCommand.Infof("State trie for root %s is complete", stateRoot.String()) logWithCommand.Infof("State trie for root %s is complete", stateRoot)
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")
@ -95,30 +103,36 @@ func validateTrie() {
} }
storageRoot := common.HexToHash(storageRootStr) storageRoot := common.HexToHash(storageRootStr)
addr := common.HexToAddress(contractAddrStr) addr := common.HexToAddress(contractAddrStr)
if err = v.ValidateStorageTrie(addr, storageRoot); err != nil { logWithCommand.
logWithCommand.Fatalf("Storage trie for contract %s and root %s not complete\r\nerr: %v", addr.String(), storageRoot.String(), err) WithField("contract", addr).
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.String(), storageRoot.String()) logWithCommand.Infof("Storage trie for contract %s and root %s is complete", addr, storageRoot)
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(workers uint) (*validator.Validator, error) { func newValidator(params validator.Params) (*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, workers), nil return validator.NewPGIPFSValidator(db, params), 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, workers), nil return validator.NewIPFSValidator(bs, params), nil
} }
func init() { func init() {
@ -130,11 +144,13 @@ 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 = "vulcanize_public" name = "cerc_public"
hostname = "localhost" hostname = "localhost"
port = 5432 port = 5432
user = "postgres" user = "postgres"

View File

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

386
go.mod
View File

@ -1,239 +1,265 @@
module github.com/vulcanize/eth-ipfs-state-validator/v4 module github.com/cerc-io/eth-ipfs-state-validator/v5
go 1.18 go 1.21
require ( require (
github.com/ethereum/go-ethereum v1.10.23 github.com/cerc-io/eth-iterator-utils v0.2.0
github.com/ipfs/go-blockservice v0.4.0 github.com/cerc-io/ipfs-ethdb/v5 v5.1.0-alpha
github.com/ipfs/go-cid v0.2.0 github.com/cerc-io/ipld-eth-statedb v0.1.0
github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ethereum/go-ethereum v1.13.14
github.com/ipfs/go-ipfs-ds-help v1.1.0 github.com/holiman/uint256 v1.2.4
github.com/ipfs/kubo v0.14.0 github.com/ipfs/boxo v0.19.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.6 github.com/lib/pq v1.10.9
github.com/mailgun/groupcache/v2 v2.3.0 github.com/mailgun/groupcache/v2 v2.3.0
github.com/multiformats/go-multihash v0.2.0 github.com/multiformats/go-multihash v0.2.3
github.com/onsi/ginkgo v1.16.5 github.com/onsi/ginkgo/v2 v2.15.0
github.com/onsi/gomega v1.19.0 github.com/onsi/gomega v1.30.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.4.0 github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.11.0 github.com/spf13/viper v1.18.2
github.com/vulcanize/ipfs-ethdb/v4 v4.0.7-alpha golang.org/x/sync v0.7.0
) )
require ( require (
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
github.com/Stebalien/go-bitfield v0.0.1 // indirect github.com/DataDog/zstd v1.5.5 // indirect
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect github.com/Jorropo/jsync v1.0.1 // indirect
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect github.com/VictoriaMetrics/fastcache v1.12.2 // 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 v0.22.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cerc-io/plugeth-statediff v0.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/containerd/cgroups v1.0.3 // indirect github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // 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/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect
github.com/docker/go-units v0.4.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect github.com/docker/go-units v0.5.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.0.0 // indirect github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect github.com/gabriel-vasile/mimetype v1.4.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.2.6 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // 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.2 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // 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/uuid v1.3.0 // indirect github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/gorilla/websocket v1.5.1 // 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 v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/golang-lru v1.0.2 // 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.0.3 // indirect github.com/huin/goupnp v1.3.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/log15 v2.16.0+incompatible // 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.0.0 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect
github.com/ipfs/go-bitswap v0.8.0 // indirect github.com/ipfs/go-block-format v0.2.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.5.1 // indirect github.com/ipfs/go-datastore v0.6.0 // 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-exchange-interface v0.2.0 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
github.com/ipfs/go-ipfs-files v0.1.1 // indirect github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect
github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect
github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect github.com/ipfs/go-ipld-cbor v0.1.0 // indirect
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect github.com/ipfs/go-ipld-format v0.6.0 // indirect
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect github.com/ipfs/go-ipld-legacy v0.2.1 // 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-mfs v0.2.1 // indirect github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
github.com/ipfs/go-namesys v0.5.0 // indirect github.com/ipfs/go-unixfsnode v1.9.0 // indirect
github.com/ipfs/go-path v0.3.0 // indirect github.com/ipld/go-car/v2 v2.13.1 // indirect
github.com/ipfs/go-peertaskqueue v0.7.1 // indirect github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipfs/go-unixfs v0.4.0 // indirect github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/ipfs/go-unixfsnode v1.4.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/ipfs/go-verifcid v0.0.1 // indirect github.com/jackc/pgconn v1.14.3 // indirect
github.com/ipfs/interface-go-ipfs-core v0.7.0 // indirect github.com/jackc/pgio v1.0.0 // indirect
github.com/ipld/edelweiss v0.1.4 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/ipld/go-codec-dagpb v1.4.0 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/ipld/go-ipld-prime v0.17.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // 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.15.1 // indirect github.com/klauspost/compress v1.17.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/koron/go-ssdp v0.0.2 // indirect github.com/koron/go-ssdp v0.0.4 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/kr/pretty v0.3.1 // 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-eventbus v0.2.1 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.0.3 // indirect github.com/libp2p/go-libp2p v0.33.0 // indirect
github.com/libp2p/go-libp2p v0.20.3 // indirect github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect github.com/libp2p/go-libp2p-kad-dht v0.24.4 // indirect
github.com/libp2p/go-libp2p-core v0.16.1 // indirect github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect
github.com/libp2p/go-libp2p-discovery v0.7.0 // indirect github.com/libp2p/go-libp2p-pubsub v0.10.0 // indirect
github.com/libp2p/go-libp2p-kad-dht v0.16.0 // indirect github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect
github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // 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-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.3.0 // indirect
github.com/libp2p/go-msgio v0.2.0 // indirect github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-nat v0.1.0 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect
github.com/libp2p/go-openssl v0.0.7 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect
github.com/libp2p/go-reuseport v0.2.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect github.com/magiconair/properties v1.8.7 // 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-isatty v0.0.14 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/miekg/dns v1.1.48 // indirect github.com/miekg/dns v1.1.58 // 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.0 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/mitchellh/mapstructure v1.5.0 // 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.0.4 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.5.0 // indirect github.com/multiformats/go-multiaddr v0.12.2 // 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.1.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.5.0 // indirect github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multistream v0.3.3 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect github.com/multiformats/go-varint v0.0.7 // 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.0.2 // indirect github.com/opencontainers/runtime-spec v1.2.0 // 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 v1.9.4 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // 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/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect github.com/polydawn/refmt v0.89.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/common v0.33.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/common v0.47.0 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/raulk/clock v1.1.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/raulk/go-watchdog v1.2.0 // indirect github.com/quic-go/quic-go v0.41.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/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/shopspring/decimal v1.2.0 // 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.8.2 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.6.0 // 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/subosito/gotenv v1.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/stretchr/testify v1.9.0 // indirect
github.com/tidwall/gjson v1.14.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/supranational/blst v0.3.11 // indirect
github.com/tidwall/pretty v1.2.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/thoas/go-funk v0.9.3 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/vulcanize/go-eth-state-node-iterator v1.1.4 github.com/tklauser/numcpus v0.6.1 // indirect
github.com/wI2L/jsondiff v0.2.0 // indirect github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // 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-gen v0.0.0-20210219115102-f37d292932f2 // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // 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/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.24.0 // indirect
go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/otel v1.25.0 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect go.opentelemetry.io/otel/metric v1.25.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect go.opentelemetry.io/otel/trace v1.25.0 // indirect
go.uber.org/atomic v1.9.0 // indirect go.uber.org/dig v1.17.1 // indirect
go.uber.org/dig v1.14.0 // indirect go.uber.org/fx v1.20.1 // indirect
go.uber.org/fx v1.16.0 // indirect go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.8.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.21.0 // indirect go.uber.org/zap v1.27.0 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/crypto v0.22.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/term v0.19.0 // indirect
golang.org/x/tools v0.1.10 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect golang.org/x/tools v0.20.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect gonum.org/v1/gonum v0.14.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.1.7 // indirect lukechampine.com/blake3 v1.2.2 // 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/vulcanize/eth-ipfs-state-validator/v4/cmd" "github.com/cerc-io/eth-ipfs-state-validator/v5/cmd"
) )
func main() { func main() {

View File

@ -18,6 +18,8 @@ package validator
import ( import (
"fmt" "fmt"
"os"
"strconv"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -32,13 +34,6 @@ 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
@ -47,6 +42,13 @@ 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",
@ -59,7 +61,30 @@ 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 (c *Config) Init() { func LoadEnv(c *Config) error {
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" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

9
pkg/types.go Normal file
View File

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

View File

@ -19,42 +19,11 @@ package validator
import ( import (
"context" "context"
"github.com/ipfs/go-blockservice" "github.com/ipfs/boxo/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)
@ -72,9 +41,3 @@ 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
}

39
pkg/util_test.go Normal file
View File

@ -0,0 +1,39 @@
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,40 +18,66 @@ package validator
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"sync" "os"
"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/ethereum/go-ethereum/trie" "github.com/ipfs/boxo/blockservice"
"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"
nodeiter "github.com/vulcanize/go-eth-state-node-iterator" iterutils "github.com/cerc-io/eth-iterator-utils"
ipfsethdb "github.com/vulcanize/ipfs-ethdb/v4" "github.com/cerc-io/eth-iterator-utils/tracker"
pgipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres" ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5"
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 *trie.Database trieDB *triedb.Database
stateDatabase state.Database stateDatabase state.Database
db *pgipfsethdb.Database db *pgipfsethdb.Database
iterWorkers uint params Params
} }
var emptyCodeHash = crypto.Keccak256(nil) type Params struct {
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, workers uint) *Validator { func NewPGIPFSValidator(db *sqlx.DB, par Params) *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
@ -64,15 +90,13 @@ func NewPGIPFSValidator(db *sqlx.DB, workers uint) *Validator {
ExpiryDuration: time.Hour * 8, // 8 hours ExpiryDuration: time.Hour * 8, // 8 hours
}) })
if workers == 0 { normalizeParams(&par)
workers = 1
}
return &Validator{ return &Validator{
kvs: kvs, kvs: kvs,
trieDB: trie.NewDatabase(kvs), trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
db: database.(*pgipfsethdb.Database), db: database.(*pgipfsethdb.Database),
iterWorkers: workers, params: par,
} }
} }
@ -81,17 +105,15 @@ 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, workers uint) *Validator { func NewIPFSValidator(bs blockservice.BlockService, par Params) *Validator {
kvs := ipfsethdb.NewKeyValueStore(bs) kvs := ipfsethdb.NewKeyValueStore(bs)
database := ipfsethdb.NewDatabase(bs) database := ipfsethdb.NewDatabase(bs)
if workers == 0 { normalizeParams(&par)
workers = 1
}
return &Validator{ return &Validator{
kvs: kvs, kvs: kvs,
trieDB: trie.NewDatabase(kvs), trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
iterWorkers: workers, params: par,
} }
} }
@ -101,76 +123,19 @@ func NewIPFSValidator(bs blockservice.BlockService, workers uint) *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: trie.NewDatabase(kvs), trieDB: triedb.NewDatabase(NewKVSDatabaseWithAncient(kvs), nil),
stateDatabase: state.NewDatabase(database), stateDatabase: state.NewDatabase(database),
} }
} }
// Traverses each iterator in a separate goroutine. // Ensure params are valid
// If storage = true, also traverse storage tries for each leaf. func normalizeParams(p *Params) {
func (v *Validator) iterateAsync(iters []trie.NodeIterator, storage bool) error { if p.Workers == 0 {
var wg sync.WaitGroup p.Workers = 1
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
}
// 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 {
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)
} }
if len(p.RecoveryFormat) == 0 {
done := make(chan struct{}) p.RecoveryFormat = DefaultRecoveryFormat
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
@ -180,8 +145,8 @@ func (v *Validator) ValidateTrie(stateRoot common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
iters := nodeiter.SubtrieIterators(t, v.iterWorkers) iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, true) }
return v.iterateAsync(iters, true) return iterateTracked(t, fmt.Sprintf(v.params.RecoveryFormat, fullTraversal), v.params.Workers, iterate)
} }
// 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
@ -192,20 +157,21 @@ func (v *Validator) ValidateStateTrie(stateRoot common.Hash) error {
if err != nil { if err != nil {
return err return err
} }
iters := nodeiter.SubtrieIterators(t, v.iterWorkers) iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, false) }
return v.iterateAsync(iters, false) return iterateTracked(t, fmt.Sprintf(v.params.RecoveryFormat, stateTraversal), v.params.Workers, iterate)
} }
// 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(address common.Address, storageRoot common.Hash) error { func (v *Validator) ValidateStorageTrie(stateRoot common.Hash, 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())
t, err := v.stateDatabase.OpenStorageTrie(addrHash, storageRoot) // Note: the last argument is the redundant state trie, but will be needed for Verkle tries
storage, err := v.stateDatabase.OpenStorageTrie(stateRoot, addrHash, storageRoot, nil)
if err != nil { if err != nil {
return err return err
} }
iters := nodeiter.SubtrieIterators(t, v.iterWorkers) iterate := func(ctx context.Context, it trie.NodeIterator) error { return v.iterate(ctx, stateRoot, it, false) }
return v.iterateAsync(iters, false) return iterateTracked(storage, fmt.Sprintf(v.params.RecoveryFormat, storageTraversal), v.params.Workers, iterate)
} }
// Close implements io.Closer // Close implements io.Closer
@ -215,3 +181,111 @@ 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 (
"fmt" "os"
"math/big" "path/filepath"
"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" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
validator "github.com/vulcanize/eth-ipfs-state-validator/v4/pkg" validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
pgipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres"
) )
var ( var (
@ -66,9 +66,10 @@ 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: big.NewInt(0), Balance: uint256.NewInt(0),
CodeHash: codeHash.Bytes(), CodeHash: codeHash.Bytes(),
Root: crypto.Keccak256Hash(storageBranchRootNode), Root: crypto.Keccak256Hash(storageBranchRootNode),
}) })
@ -79,7 +80,7 @@ var (
minerAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ minerAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 0, Nonce: 0,
Balance: big.NewInt(1000), Balance: uint256.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -90,7 +91,7 @@ var (
account1, _ = rlp.EncodeToBytes(&types.StateAccount{ account1, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 2, Nonce: 2,
Balance: big.NewInt(1000), Balance: uint256.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -101,7 +102,7 @@ var (
account2, _ = rlp.EncodeToBytes(&types.StateAccount{ account2, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 0, Nonce: 0,
Balance: big.NewInt(1000), Balance: uint256.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -112,7 +113,7 @@ var (
bankAccount, _ = rlp.EncodeToBytes(&types.StateAccount{ bankAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
Nonce: 2, Nonce: 2,
Balance: big.NewInt(1000), Balance: uint256.NewInt(1000),
CodeHash: nullCodeHash.Bytes(), CodeHash: nullCodeHash.Bytes(),
Root: emptyContractRoot, Root: emptyContractRoot,
}) })
@ -188,63 +189,84 @@ 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() {
db, err = pgipfsethdb.TestDB() err = validator.LoadEnv(&config)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
v = validator.NewPGIPFSValidator(db, 4) db, err = sqlx.Connect("postgres", config.ConnString())
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 = validator.ResetTestDB(db) err = 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 if 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(append(missingRootStateNodes, mockCode), trieStorageNodes) loadTrie(missingRootStateNodes, trieStorageNodes, mockCode)
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(append(trieStateNodes, mockCode), missingRootStorageNodes) loadTrie(trieStateNodes, missingRootStorageNodes, mockCode)
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(append(missingNodeStateNodes, mockCode), trieStorageNodes) loadTrie(missingNodeStateNodes, trieStorageNodes, mockCode)
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(append(trieStateNodes, mockCode), missingNodeStorageNodes) loadTrie(trieStateNodes, missingNodeStorageNodes, mockCode)
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())
subStr := fmt.Sprintf("code %s: not found", codeHash.Hex()[2:]) Expect(err.Error()).To(ContainSubstring("%x", codeHash))
Expect(err.Error()).To(ContainSubstring(subStr)) Expect(err.Error()).To(ContainSubstring("%x", codePath))
}) })
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(append(trieStateNodes, mockCode), trieStorageNodes) loadTrie(trieStateNodes, trieStorageNodes, mockCode)
err = v.ValidateTrie(stateRoot) err = v.ValidateTrie(stateRoot)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
@ -252,7 +274,7 @@ var _ = Describe("PG-IPFS Validator", func() {
Describe("ValidateStateTrie", func() { Describe("ValidateStateTrie", func() {
AfterEach(func() { AfterEach(func() {
err = validator.ResetTestDB(db) err = 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() {
@ -266,6 +288,7 @@ 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)
@ -276,38 +299,43 @@ var _ = Describe("PG-IPFS Validator", func() {
Describe("ValidateStorageTrie", func() { Describe("ValidateStorageTrie", func() {
AfterEach(func() { AfterEach(func() {
err = validator.ResetTestDB(db) err = ResetTestDB(db)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("Returns an error the storage root node is missing", func() { It("Returns an error if the storage root node is missing", func() {
loadTrie(nil, missingRootStorageNodes) loadTrie(nil, missingRootStorageNodes)
err = v.ValidateStorageTrie(contractAddr, storageRoot) err = v.ValidateStorageTrie(common.Hash{}, 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(contractAddr, storageRoot) err = v.ValidateStorageTrie(common.Hash{}, 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(contractAddr, storageRoot) err = v.ValidateStorageTrie(common.Hash{}, contractAddr, storageRoot)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
}) })
}) })
func loadTrie(stateNodes, storageNodes [][]byte) { func loadTrie(stateNodes, storageNodes [][]byte, contractCode ...[]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 := validator.PublishRaw(tx, cid.EthStateTrie, multihash.KECCAK_256, node, blockNumber) err := 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 := validator.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()) Expect(err).ToNot(HaveOccurred())
} }
err = tx.Commit() err = tx.Commit()

28
test/compose.yml Normal file
View File

@ -0,0 +1,28 @@
# 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