Merge pull request #11 from cerc-io/ian/v5_dev
create database abstraction to make it easier to use different drivers
This commit is contained in:
commit
c7d05bb86e
27
config.go
27
config.go
@ -2,9 +2,13 @@ package ipld_eth_statedb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@ -19,6 +23,20 @@ type Config struct {
|
|||||||
MinConns int
|
MinConns int
|
||||||
MaxConnLifetime time.Duration
|
MaxConnLifetime time.Duration
|
||||||
MaxConnIdleTime time.Duration
|
MaxConnIdleTime time.Duration
|
||||||
|
MaxIdle int
|
||||||
|
}
|
||||||
|
|
||||||
|
// DbConnectionString constructs and returns the connection string from the config (for sqlx driver)
|
||||||
|
func (c Config) DbConnectionString() string {
|
||||||
|
if len(c.Username) > 0 && len(c.Password) > 0 {
|
||||||
|
return fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?sslmode=disable",
|
||||||
|
c.Username, c.Password, c.Hostname, c.Port, c.DatabaseName)
|
||||||
|
}
|
||||||
|
if len(c.Username) > 0 && len(c.Password) == 0 {
|
||||||
|
return fmt.Sprintf("postgresql://%s@%s:%d/%s?sslmode=disable",
|
||||||
|
c.Username, c.Hostname, c.Port, c.DatabaseName)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("postgresql://%s:%d/%s?sslmode=disable", c.Hostname, c.Port, c.DatabaseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPGXPool returns a new pgx conn pool
|
// NewPGXPool returns a new pgx conn pool
|
||||||
@ -30,6 +48,15 @@ func NewPGXPool(ctx context.Context, config Config) (*pgxpool.Pool, error) {
|
|||||||
return pgxpool.ConnectConfig(ctx, pgConf)
|
return pgxpool.ConnectConfig(ctx, pgConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSQLXPool returns a new sqlx conn pool
|
||||||
|
func NewSQLXPool(ctx context.Context, config Config) (*sqlx.DB, error) {
|
||||||
|
db, err := sqlx.ConnectContext(ctx, "postgres", config.DbConnectionString())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
// makePGXConfig creates a pgxpool.Config from the provided Config
|
// makePGXConfig creates a pgxpool.Config from the provided Config
|
||||||
func makePGXConfig(config Config) (*pgxpool.Config, error) {
|
func makePGXConfig(config Config) (*pgxpool.Config, error) {
|
||||||
conf, err := pgxpool.ParseConfig("")
|
conf, err := pgxpool.ParseConfig("")
|
||||||
|
139
database.go
139
database.go
@ -1,135 +1,28 @@
|
|||||||
package ipld_eth_statedb
|
package ipld_eth_statedb
|
||||||
|
|
||||||
import (
|
var _ Database = &DB{}
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
// NewPostgresDB returns a postgres.DB using the provided driver
|
||||||
"github.com/ethereum/go-ethereum/common"
|
func NewPostgresDB(driver Driver) *DB {
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
return &DB{driver}
|
||||||
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
|
||||||
|
|
||||||
util "github.com/cerc-io/ipld-eth-statedb/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Number of codehash->size associations to keep.
|
|
||||||
codeSizeCacheSize = 100000
|
|
||||||
|
|
||||||
// Cache size granted for caching clean code.
|
|
||||||
codeCacheSize = 64 * 1024 * 1024
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// not found error
|
|
||||||
errNotFound = errors.New("not found")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Database interface is a union of the subset of the geth state.Database interface required
|
|
||||||
// to support the vm.StateDB implementation as well as methods specific to this Postgres based implementation
|
|
||||||
type Database interface {
|
|
||||||
ContractCode(codeHash common.Hash) ([]byte, error)
|
|
||||||
ContractCodeSize(codeHash common.Hash) (int, error)
|
|
||||||
StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error)
|
|
||||||
StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Database = &stateDatabase{}
|
// DB implements sql.Database using a configured driver and Postgres statement syntax
|
||||||
|
type DB struct {
|
||||||
type stateDatabase struct {
|
Driver
|
||||||
pgdb *pgxpool.Pool
|
|
||||||
codeSizeCache *lru.Cache
|
|
||||||
codeCache *fastcache.Cache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateDatabaseWithPool returns a new Database implementation using the provided postgres connection pool
|
// GetContractCodeStmt satisfies the Statements interface
|
||||||
func NewStateDatabaseWithPool(pgDb *pgxpool.Pool) (*stateDatabase, error) {
|
func (db *DB) GetContractCodeStmt() string {
|
||||||
csc, _ := lru.New(codeSizeCacheSize)
|
return GetContractCodePgStr
|
||||||
return &stateDatabase{
|
|
||||||
pgdb: pgDb,
|
|
||||||
codeSizeCache: csc,
|
|
||||||
codeCache: fastcache.New(codeCacheSize),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateDatabase returns a new Database implementation using the passed parameters
|
// GetStateAccountStmt satisfies the Statements interface
|
||||||
func NewStateDatabase(ctx context.Context, conf Config) (*stateDatabase, error) {
|
func (db *DB) GetStateAccountStmt() string {
|
||||||
pgDb, err := NewPGXPool(ctx, conf)
|
return GetStateAccount
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return NewStateDatabaseWithPool(pgDb)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCode satisfies Database, it returns the contract code for a given codehash
|
// GetStorageSlotStmt satisfies the Statements interface
|
||||||
func (sd *stateDatabase) ContractCode(codeHash common.Hash) ([]byte, error) {
|
func (db *DB) GetStorageSlotStmt() string {
|
||||||
if code := sd.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
return GetStorageSlot
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
c, err := util.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot derive CID from provided codehash: %s", err.Error())
|
|
||||||
}
|
|
||||||
code := make([]byte, 0)
|
|
||||||
if err := sd.pgdb.QueryRow(context.Background(), GetContractCodePgStr, c).Scan(&code); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(code) > 0 {
|
|
||||||
sd.codeCache.Set(codeHash.Bytes(), code)
|
|
||||||
sd.codeSizeCache.Add(codeHash, len(code))
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
return nil, errNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractCodeSize satisfies Database, it returns the length of the code for a provided codehash
|
|
||||||
func (sd *stateDatabase) ContractCodeSize(codeHash common.Hash) (int, error) {
|
|
||||||
if cached, ok := sd.codeSizeCache.Get(codeHash); ok {
|
|
||||||
return cached.(int), nil
|
|
||||||
}
|
|
||||||
code, err := sd.ContractCode(codeHash)
|
|
||||||
return len(code), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateAccount satisfies Database, it returns the types.StateAccount for a provided address and block hash
|
|
||||||
func (sd *stateDatabase) StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error) {
|
|
||||||
res := StateAccountResult{}
|
|
||||||
err := sd.pgdb.QueryRow(context.Background(), GetStateAccount, addressHash.Hex(), blockHash.Hex()).
|
|
||||||
Scan(&res.Balance, &res.Nonce, &res.CodeHash, &res.StorageRoot, &res.Removed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if res.Removed {
|
|
||||||
// TODO: check expected behavior for deleted/non existing accounts
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
bal := new(big.Int)
|
|
||||||
bal.SetString(res.Balance, 10)
|
|
||||||
return &types.StateAccount{
|
|
||||||
Nonce: res.Nonce,
|
|
||||||
Balance: bal,
|
|
||||||
Root: common.HexToHash(res.StorageRoot),
|
|
||||||
CodeHash: common.HexToHash(res.CodeHash).Bytes(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageValue satisfies Database, it returns the RLP-encoded storage value for the provided address, slot,
|
|
||||||
// and block hash
|
|
||||||
func (sd *stateDatabase) StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error) {
|
|
||||||
res := StorageSlotResult{}
|
|
||||||
err := sd.pgdb.QueryRow(context.Background(), GetStorageSlot,
|
|
||||||
addressHash.Hex(), slotHash.Hex(), blockHash.Hex()).
|
|
||||||
Scan(&res.Value, &res.Removed, &res.StateLeafRemoved)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if res.Removed || res.StateLeafRemoved {
|
|
||||||
// TODO: check expected behavior for deleted/non existing accounts
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return res.Value, nil
|
|
||||||
}
|
}
|
||||||
|
4
go.mod
4
go.mod
@ -7,7 +7,10 @@ require (
|
|||||||
github.com/ethereum/go-ethereum v1.10.26
|
github.com/ethereum/go-ethereum v1.10.26
|
||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
||||||
github.com/ipfs/go-cid v0.2.0
|
github.com/ipfs/go-cid v0.2.0
|
||||||
|
github.com/jackc/pgconn v1.14.0
|
||||||
github.com/jackc/pgx/v4 v4.18.1
|
github.com/jackc/pgx/v4 v4.18.1
|
||||||
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
|
github.com/lib/pq v1.10.6
|
||||||
github.com/multiformats/go-multihash v0.1.0
|
github.com/multiformats/go-multihash v0.1.0
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
)
|
)
|
||||||
@ -25,7 +28,6 @@ require (
|
|||||||
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
|
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
|
||||||
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||||
github.com/jackc/pgconn v1.14.0 // indirect
|
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
github.com/jackc/pgio v1.0.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
||||||
|
33
go.sum
33
go.sum
@ -5,16 +5,19 @@ github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c
|
|||||||
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
|
||||||
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k=
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU=
|
||||||
|
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||||
github.com/cerc-io/go-ethereum v1.10.26-statediff-4.2.2-alpha h1:gesMZEbNU+fcAMctITi+KO/AK80YdTq6TVB5lb4EfnU=
|
github.com/cerc-io/go-ethereum v1.10.26-statediff-4.2.2-alpha h1:gesMZEbNU+fcAMctITi+KO/AK80YdTq6TVB5lb4EfnU=
|
||||||
github.com/cerc-io/go-ethereum v1.10.26-statediff-4.2.2-alpha/go.mod h1:lKBVBWksSwBDR/5D9CAxaGQzDPIS3ueWb6idy7X1Shg=
|
github.com/cerc-io/go-ethereum v1.10.26-statediff-4.2.2-alpha/go.mod h1:lKBVBWksSwBDR/5D9CAxaGQzDPIS3ueWb6idy7X1Shg=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
@ -22,20 +25,29 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
|
||||||
|
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
|
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -54,10 +66,12 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||||
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
@ -90,6 +104,7 @@ github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
|||||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||||
|
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
|
||||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
@ -122,6 +137,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
|||||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
|
github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
|
||||||
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||||
|
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
@ -131,14 +148,18 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
|
||||||
|
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
@ -146,6 +167,8 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||||
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||||
@ -175,14 +198,17 @@ github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS
|
|||||||
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
|
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
|
||||||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -207,6 +233,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
|
|||||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
|
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
@ -279,6 +306,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
|
|||||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -342,6 +370,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@ -350,15 +379,19 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
|||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
34
interfaces.go
Normal file
34
interfaces.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package ipld_eth_statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Database interfaces to support multiple Postgres drivers
|
||||||
|
type Database interface {
|
||||||
|
Driver
|
||||||
|
Statements
|
||||||
|
}
|
||||||
|
|
||||||
|
// Driver interface has all the methods required by a driver implementation to support the sql indexer
|
||||||
|
type Driver interface {
|
||||||
|
QueryRow(ctx context.Context, sql string, args ...interface{}) ScannableRow
|
||||||
|
Exec(ctx context.Context, sql string, args ...interface{}) (Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScannableRow interface to accommodate different concrete row types
|
||||||
|
type ScannableRow interface {
|
||||||
|
Scan(dest ...interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result interface to accommodate different concrete result types
|
||||||
|
type Result interface {
|
||||||
|
RowsAffected() (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statements interface to accommodate different SQL query syntax
|
||||||
|
type Statements interface {
|
||||||
|
GetContractCodeStmt() string
|
||||||
|
GetStateAccountStmt() string
|
||||||
|
GetStorageSlotStmt() string
|
||||||
|
}
|
50
pgx.go
Normal file
50
pgx.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package ipld_eth_statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgconn"
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Driver = &PGXDriver{}
|
||||||
|
|
||||||
|
// PGXDriver driver, implements Driver
|
||||||
|
type PGXDriver struct {
|
||||||
|
ctx context.Context
|
||||||
|
db *pgxpool.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPGXDriver returns a new pgx driver for Postgres
|
||||||
|
func NewPGXDriver(ctx context.Context, config Config) (*PGXDriver, error) {
|
||||||
|
db, err := NewPGXPool(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &PGXDriver{ctx: ctx, db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPGXDriverFromPool returns a new pgx driver for Postgres
|
||||||
|
func NewPGXDriverFromPool(ctx context.Context, db *pgxpool.Pool) (*PGXDriver, error) {
|
||||||
|
return &PGXDriver{ctx: ctx, db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRow satisfies sql.Database
|
||||||
|
func (driver *PGXDriver) QueryRow(ctx context.Context, sql string, args ...interface{}) ScannableRow {
|
||||||
|
return driver.db.QueryRow(ctx, sql, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec satisfies sql.Database
|
||||||
|
func (pgx *PGXDriver) Exec(ctx context.Context, sql string, args ...interface{}) (Result, error) {
|
||||||
|
res, err := pgx.db.Exec(ctx, sql, args...)
|
||||||
|
return resultWrapper{ct: res}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type resultWrapper struct {
|
||||||
|
ct pgconn.CommandTag
|
||||||
|
}
|
||||||
|
|
||||||
|
// RowsAffected satisfies sql.Result
|
||||||
|
func (r resultWrapper) RowsAffected() (int64, error) {
|
||||||
|
return r.ct.RowsAffected(), nil
|
||||||
|
}
|
46
sqlx.go
Normal file
46
sqlx.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package ipld_eth_statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Driver = &SQLXDriver{}
|
||||||
|
|
||||||
|
// SQLXDriver driver, implements Driver
|
||||||
|
type SQLXDriver struct {
|
||||||
|
ctx context.Context
|
||||||
|
db *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSQLXDriver returns a new sqlx driver for Postgres
|
||||||
|
func NewSQLXDriver(ctx context.Context, config Config) (*SQLXDriver, error) {
|
||||||
|
db, err := NewSQLXPool(ctx, config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if config.MaxConns > 0 {
|
||||||
|
db.SetMaxOpenConns(config.MaxConns)
|
||||||
|
}
|
||||||
|
if config.MaxConnLifetime > 0 {
|
||||||
|
db.SetConnMaxLifetime(config.MaxConnLifetime)
|
||||||
|
}
|
||||||
|
db.SetMaxIdleConns(config.MaxIdle)
|
||||||
|
return &SQLXDriver{ctx: ctx, db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSQLXDriverFromPool returns a new sqlx driver for Postgres
|
||||||
|
func NewSQLXDriverFromPool(ctx context.Context, db *sqlx.DB) (*SQLXDriver, error) {
|
||||||
|
return &SQLXDriver{ctx: ctx, db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRow satisfies sql.Database
|
||||||
|
func (driver *SQLXDriver) QueryRow(_ context.Context, sql string, args ...interface{}) ScannableRow {
|
||||||
|
return driver.db.QueryRowx(sql, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec satisfies sql.Database
|
||||||
|
func (driver *SQLXDriver) Exec(_ context.Context, sql string, args ...interface{}) (Result, error) {
|
||||||
|
return driver.db.Exec(sql, args...)
|
||||||
|
}
|
138
state_database.go
Normal file
138
state_database.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package ipld_eth_statedb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
||||||
|
|
||||||
|
util "github.com/cerc-io/ipld-eth-statedb/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Number of codehash->size associations to keep.
|
||||||
|
codeSizeCacheSize = 100000
|
||||||
|
|
||||||
|
// Cache size granted for caching clean code.
|
||||||
|
codeCacheSize = 64 * 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// not found error
|
||||||
|
errNotFound = errors.New("not found")
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateDatabase interface is a union of the subset of the geth state.Database interface required
|
||||||
|
// to support the vm.StateDB implementation as well as methods specific to this Postgres based implementation
|
||||||
|
type StateDatabase interface {
|
||||||
|
ContractCode(codeHash common.Hash) ([]byte, error)
|
||||||
|
ContractCodeSize(codeHash common.Hash) (int, error)
|
||||||
|
StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error)
|
||||||
|
StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ StateDatabase = &stateDatabase{}
|
||||||
|
|
||||||
|
type stateDatabase struct {
|
||||||
|
db Database
|
||||||
|
codeSizeCache *lru.Cache
|
||||||
|
codeCache *fastcache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateDatabaseWithPgxPool returns a new Database implementation using the provided postgres connection pool
|
||||||
|
func NewStateDatabaseWithPgxPool(pgDb *pgxpool.Pool) (*stateDatabase, error) {
|
||||||
|
csc, _ := lru.New(codeSizeCacheSize)
|
||||||
|
return &stateDatabase{
|
||||||
|
db: NewPostgresDB(&PGXDriver{db: pgDb}),
|
||||||
|
codeSizeCache: csc,
|
||||||
|
codeCache: fastcache.New(codeCacheSize),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateDatabaseWithSqlxPool returns a new Database implementation using the passed parameters
|
||||||
|
func NewStateDatabaseWithSqlxPool(db *sqlx.DB) (*stateDatabase, error) {
|
||||||
|
csc, _ := lru.New(codeSizeCacheSize)
|
||||||
|
return &stateDatabase{
|
||||||
|
db: NewPostgresDB(&SQLXDriver{db: db}),
|
||||||
|
codeSizeCache: csc,
|
||||||
|
codeCache: fastcache.New(codeCacheSize),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContractCode satisfies Database, it returns the contract code for a given codehash
|
||||||
|
func (sd *stateDatabase) ContractCode(codeHash common.Hash) ([]byte, error) {
|
||||||
|
if code := sd.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 {
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
c, err := util.Keccak256ToCid(ipld.RawBinary, codeHash.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot derive CID from provided codehash: %s", err.Error())
|
||||||
|
}
|
||||||
|
code := make([]byte, 0)
|
||||||
|
if err := sd.db.QueryRow(context.Background(), GetContractCodePgStr, c.String()).Scan(&code); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(code) > 0 {
|
||||||
|
sd.codeCache.Set(codeHash.Bytes(), code)
|
||||||
|
sd.codeSizeCache.Add(codeHash, len(code))
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
return nil, errNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContractCodeSize satisfies Database, it returns the length of the code for a provided codehash
|
||||||
|
func (sd *stateDatabase) ContractCodeSize(codeHash common.Hash) (int, error) {
|
||||||
|
if cached, ok := sd.codeSizeCache.Get(codeHash); ok {
|
||||||
|
return cached.(int), nil
|
||||||
|
}
|
||||||
|
code, err := sd.ContractCode(codeHash)
|
||||||
|
return len(code), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateAccount satisfies Database, it returns the types.StateAccount for a provided address and block hash
|
||||||
|
func (sd *stateDatabase) StateAccount(addressHash, blockHash common.Hash) (*types.StateAccount, error) {
|
||||||
|
res := StateAccountResult{}
|
||||||
|
err := sd.db.QueryRow(context.Background(), GetStateAccount, addressHash.Hex(), blockHash.Hex()).
|
||||||
|
Scan(&res.Balance, &res.Nonce, &res.CodeHash, &res.StorageRoot, &res.Removed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if res.Removed {
|
||||||
|
// TODO: check expected behavior for deleted/non existing accounts
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
bal := new(big.Int)
|
||||||
|
bal.SetString(res.Balance, 10)
|
||||||
|
return &types.StateAccount{
|
||||||
|
Nonce: res.Nonce,
|
||||||
|
Balance: bal,
|
||||||
|
Root: common.HexToHash(res.StorageRoot),
|
||||||
|
CodeHash: common.HexToHash(res.CodeHash).Bytes(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageValue satisfies Database, it returns the RLP-encoded storage value for the provided address, slot,
|
||||||
|
// and block hash
|
||||||
|
func (sd *stateDatabase) StorageValue(addressHash, slotHash, blockHash common.Hash) ([]byte, error) {
|
||||||
|
res := StorageSlotResult{}
|
||||||
|
err := sd.db.QueryRow(context.Background(), GetStorageSlot,
|
||||||
|
addressHash.Hex(), slotHash.Hex(), blockHash.Hex()).
|
||||||
|
Scan(&res.Value, &res.Removed, &res.StateLeafRemoved)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if res.Removed || res.StateLeafRemoved {
|
||||||
|
// TODO: check expected behavior for deleted/non existing accounts
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return res.Value, nil
|
||||||
|
}
|
@ -133,7 +133,7 @@ func (s *stateObject) touch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetState retrieves a value from the account storage trie.
|
// GetState retrieves a value from the account storage trie.
|
||||||
func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
func (s *stateObject) GetState(db StateDatabase, key common.Hash) common.Hash {
|
||||||
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
||||||
if s.fakeStorage != nil {
|
if s.fakeStorage != nil {
|
||||||
return s.fakeStorage[key]
|
return s.fakeStorage[key]
|
||||||
@ -148,7 +148,7 @@ func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCommittedState retrieves a value from the committed account storage trie.
|
// GetCommittedState retrieves a value from the committed account storage trie.
|
||||||
func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
|
func (s *stateObject) GetCommittedState(db StateDatabase, key common.Hash) common.Hash {
|
||||||
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
// If the fake storage is set, only lookup the state here(in the debugging mode)
|
||||||
if s.fakeStorage != nil {
|
if s.fakeStorage != nil {
|
||||||
return s.fakeStorage[key]
|
return s.fakeStorage[key]
|
||||||
@ -183,7 +183,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetState updates a value in account storage.
|
// SetState updates a value in account storage.
|
||||||
func (s *stateObject) SetState(db Database, key, value common.Hash) {
|
func (s *stateObject) SetState(db StateDatabase, key, value common.Hash) {
|
||||||
// If the fake storage is set, put the temporary state update here.
|
// If the fake storage is set, put the temporary state update here.
|
||||||
if s.fakeStorage != nil {
|
if s.fakeStorage != nil {
|
||||||
s.fakeStorage[key] = value
|
s.fakeStorage[key] = value
|
||||||
@ -270,7 +270,7 @@ func (s *stateObject) Address() common.Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Code returns the contract code associated with this object, if any.
|
// Code returns the contract code associated with this object, if any.
|
||||||
func (s *stateObject) Code(db Database) []byte {
|
func (s *stateObject) Code(db StateDatabase) []byte {
|
||||||
if s.code != nil {
|
if s.code != nil {
|
||||||
return s.code
|
return s.code
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ func (s *stateObject) Code(db Database) []byte {
|
|||||||
// CodeSize returns the size of the contract code associated with this object,
|
// CodeSize returns the size of the contract code associated with this object,
|
||||||
// or zero if none. This method is an almost mirror of Code, but uses a cache
|
// or zero if none. This method is an almost mirror of Code, but uses a cache
|
||||||
// inside the database to avoid loading codes seen recently.
|
// inside the database to avoid loading codes seen recently.
|
||||||
func (s *stateObject) CodeSize(db Database) int {
|
func (s *stateObject) CodeSize(db StateDatabase) int {
|
||||||
if s.code != nil {
|
if s.code != nil {
|
||||||
return len(s.code)
|
return len(s.code)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ type revision struct {
|
|||||||
// * Contracts
|
// * Contracts
|
||||||
// * Accounts
|
// * Accounts
|
||||||
type StateDB struct {
|
type StateDB struct {
|
||||||
db Database
|
db StateDatabase
|
||||||
hasher crypto.KeccakState
|
hasher crypto.KeccakState
|
||||||
|
|
||||||
// originBlockHash is the blockhash for the state we are working on top of
|
// originBlockHash is the blockhash for the state we are working on top of
|
||||||
@ -89,7 +89,7 @@ type StateDB struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new StateDB on the state for the provided blockHash
|
// New creates a new StateDB on the state for the provided blockHash
|
||||||
func New(blockHash common.Hash, db Database) (*StateDB, error) {
|
func New(blockHash common.Hash, db StateDatabase) (*StateDB, error) {
|
||||||
sdb := &StateDB{
|
sdb := &StateDB{
|
||||||
db: db,
|
db: db,
|
||||||
originBlockHash: blockHash,
|
originBlockHash: blockHash,
|
||||||
|
278
statedb_test.go
278
statedb_test.go
@ -7,7 +7,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/lib/pq"
|
||||||
"github.com/multiformats/go-multihash"
|
"github.com/multiformats/go-multihash"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@ -85,14 +85,18 @@ var (
|
|||||||
RemovedNodeStorageCID = "bagmacgzayxjemamg64rtzet6pwznzrydydsqbnstzkbcoo337lmaixmfurya"
|
RemovedNodeStorageCID = "bagmacgzayxjemamg64rtzet6pwznzrydydsqbnstzkbcoo337lmaixmfurya"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSuite(t *testing.T) {
|
func TestPGXSuite(t *testing.T) {
|
||||||
testConfig, err := getTestConfig()
|
testConfig, err := getTestConfig()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pool, err := statedb.NewPGXPool(testCtx, testConfig)
|
pool, err := statedb.NewPGXPool(testCtx, testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
driver, err := statedb.NewPGXDriverFromPool(context.Background(), pool)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
database := statedb.NewPostgresDB(driver)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
tx, err := pool.Begin(testCtx)
|
tx, err := pool.Begin(testCtx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -108,15 +112,15 @@ func TestSuite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.NoError(t, tx.Commit(testCtx))
|
require.NoError(t, tx.Commit(testCtx))
|
||||||
})
|
})
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash.String(), BlockParentHash.String(), BlockNumber.Uint64()))
|
require.NoError(t, insertHeaderCID(database, BlockHash.String(), BlockParentHash.String(), BlockNumber.Uint64()))
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash2.String(), BlockHash.String(), BlockNumber2))
|
require.NoError(t, insertHeaderCID(database, BlockHash2.String(), BlockHash.String(), BlockNumber2))
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash3.String(), BlockHash2.String(), BlockNumber3))
|
require.NoError(t, insertHeaderCID(database, BlockHash3.String(), BlockHash2.String(), BlockNumber3))
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash4.String(), BlockHash3.String(), BlockNumber4))
|
require.NoError(t, insertHeaderCID(database, BlockHash4.String(), BlockHash3.String(), BlockNumber4))
|
||||||
require.NoError(t, insertHeaderCID(pool, NonCanonicalHash4.String(), BlockHash3.String(), BlockNumber4))
|
require.NoError(t, insertHeaderCID(database, NonCanonicalHash4.String(), BlockHash3.String(), BlockNumber4))
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash5.String(), BlockHash4.String(), BlockNumber5))
|
require.NoError(t, insertHeaderCID(database, BlockHash5.String(), BlockHash4.String(), BlockNumber5))
|
||||||
require.NoError(t, insertHeaderCID(pool, NonCanonicalHash5.String(), NonCanonicalHash4.String(), BlockNumber5))
|
require.NoError(t, insertHeaderCID(database, NonCanonicalHash5.String(), NonCanonicalHash4.String(), BlockNumber5))
|
||||||
require.NoError(t, insertHeaderCID(pool, BlockHash6.String(), BlockHash5.String(), BlockNumber6))
|
require.NoError(t, insertHeaderCID(database, BlockHash6.String(), BlockHash5.String(), BlockNumber6))
|
||||||
require.NoError(t, insertStateCID(pool, stateModel{
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
BlockNumber: BlockNumber.Uint64(),
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
BlockHash: BlockHash.String(),
|
BlockHash: BlockHash.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -128,7 +132,7 @@ func TestSuite(t *testing.T) {
|
|||||||
StorageRoot: Account.Root.String(),
|
StorageRoot: Account.Root.String(),
|
||||||
Removed: false,
|
Removed: false,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStateCID(pool, stateModel{
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
BlockNumber: BlockNumber4,
|
BlockNumber: BlockNumber4,
|
||||||
BlockHash: NonCanonicalHash4.String(),
|
BlockHash: NonCanonicalHash4.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -140,7 +144,7 @@ func TestSuite(t *testing.T) {
|
|||||||
StorageRoot: Account.Root.String(),
|
StorageRoot: Account.Root.String(),
|
||||||
Removed: false,
|
Removed: false,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStateCID(pool, stateModel{
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
BlockNumber: BlockNumber5,
|
BlockNumber: BlockNumber5,
|
||||||
BlockHash: BlockHash5.String(),
|
BlockHash: BlockHash5.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -148,7 +152,7 @@ func TestSuite(t *testing.T) {
|
|||||||
Diff: true,
|
Diff: true,
|
||||||
Removed: true,
|
Removed: true,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStorageCID(pool, storageModel{
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
BlockNumber: BlockNumber.Uint64(),
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
BlockHash: BlockHash.String(),
|
BlockHash: BlockHash.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -158,7 +162,7 @@ func TestSuite(t *testing.T) {
|
|||||||
Value: StoredValueRLP,
|
Value: StoredValueRLP,
|
||||||
Removed: false,
|
Removed: false,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStorageCID(pool, storageModel{
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
BlockNumber: BlockNumber2,
|
BlockNumber: BlockNumber2,
|
||||||
BlockHash: BlockHash2.String(),
|
BlockHash: BlockHash2.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -168,7 +172,7 @@ func TestSuite(t *testing.T) {
|
|||||||
Value: []byte{},
|
Value: []byte{},
|
||||||
Removed: true,
|
Removed: true,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStorageCID(pool, storageModel{
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
BlockNumber: BlockNumber3,
|
BlockNumber: BlockNumber3,
|
||||||
BlockHash: BlockHash3.String(),
|
BlockHash: BlockHash3.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -178,7 +182,7 @@ func TestSuite(t *testing.T) {
|
|||||||
Value: StoredValueRLP2,
|
Value: StoredValueRLP2,
|
||||||
Removed: false,
|
Removed: false,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertStorageCID(pool, storageModel{
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
BlockNumber: BlockNumber4,
|
BlockNumber: BlockNumber4,
|
||||||
BlockHash: NonCanonicalHash4.String(),
|
BlockHash: NonCanonicalHash4.String(),
|
||||||
LeafKey: AccountLeafKey.String(),
|
LeafKey: AccountLeafKey.String(),
|
||||||
@ -188,9 +192,9 @@ func TestSuite(t *testing.T) {
|
|||||||
Value: NonCanonStoredValueRLP,
|
Value: NonCanonStoredValueRLP,
|
||||||
Removed: false,
|
Removed: false,
|
||||||
}))
|
}))
|
||||||
require.NoError(t, insertContractCode(pool))
|
require.NoError(t, insertContractCode(database))
|
||||||
|
|
||||||
db, err := statedb.NewStateDatabaseWithPool(pool)
|
db, err := statedb.NewStateDatabaseWithPgxPool(pool)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("Database", func(t *testing.T) {
|
t.Run("Database", func(t *testing.T) {
|
||||||
@ -303,7 +307,229 @@ func TestSuite(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertHeaderCID(db *pgxpool.Pool, blockHash, parentHash string, blockNumber uint64) error {
|
func TestSQLXSuite(t *testing.T) {
|
||||||
|
testConfig, err := getTestConfig()
|
||||||
|
require.NoError(t, err)
|
||||||
|
pool, err := statedb.NewSQLXPool(testCtx, testConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
driver, err := statedb.NewSQLXDriverFromPool(context.Background(), pool)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
database := statedb.NewPostgresDB(driver)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
tx, err := pool.Begin()
|
||||||
|
require.NoError(t, err)
|
||||||
|
statements := []string{
|
||||||
|
`DELETE FROM eth.header_cids`,
|
||||||
|
`DELETE FROM eth.state_cids`,
|
||||||
|
`DELETE FROM eth.storage_cids`,
|
||||||
|
`DELETE FROM ipld.blocks`,
|
||||||
|
}
|
||||||
|
for _, stm := range statements {
|
||||||
|
_, err = tx.Exec(stm)
|
||||||
|
require.NoErrorf(t, err, "Exec(`%s`)", stm)
|
||||||
|
}
|
||||||
|
require.NoError(t, tx.Commit())
|
||||||
|
})
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash.String(), BlockParentHash.String(), BlockNumber.Uint64()))
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash2.String(), BlockHash.String(), BlockNumber2))
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash3.String(), BlockHash2.String(), BlockNumber3))
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash4.String(), BlockHash3.String(), BlockNumber4))
|
||||||
|
require.NoError(t, insertHeaderCID(database, NonCanonicalHash4.String(), BlockHash3.String(), BlockNumber4))
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash5.String(), BlockHash4.String(), BlockNumber5))
|
||||||
|
require.NoError(t, insertHeaderCID(database, NonCanonicalHash5.String(), NonCanonicalHash4.String(), BlockNumber5))
|
||||||
|
require.NoError(t, insertHeaderCID(database, BlockHash6.String(), BlockHash5.String(), BlockNumber6))
|
||||||
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
|
BlockHash: BlockHash.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
CID: AccountCID.String(),
|
||||||
|
Diff: true,
|
||||||
|
Balance: Account.Balance.Uint64(),
|
||||||
|
Nonce: Account.Nonce,
|
||||||
|
CodeHash: AccountCodeHash.String(),
|
||||||
|
StorageRoot: Account.Root.String(),
|
||||||
|
Removed: false,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
|
BlockNumber: BlockNumber4,
|
||||||
|
BlockHash: NonCanonicalHash4.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
CID: AccountCID.String(),
|
||||||
|
Diff: true,
|
||||||
|
Balance: big.NewInt(123).Uint64(),
|
||||||
|
Nonce: Account.Nonce,
|
||||||
|
CodeHash: AccountCodeHash.String(),
|
||||||
|
StorageRoot: Account.Root.String(),
|
||||||
|
Removed: false,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStateCID(database, stateModel{
|
||||||
|
BlockNumber: BlockNumber5,
|
||||||
|
BlockHash: BlockHash5.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
CID: RemovedNodeStateCID,
|
||||||
|
Diff: true,
|
||||||
|
Removed: true,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
|
BlockNumber: BlockNumber.Uint64(),
|
||||||
|
BlockHash: BlockHash.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
StorageLeafKey: StorageLeafKey.String(),
|
||||||
|
StorageCID: StorageCID.String(),
|
||||||
|
Diff: true,
|
||||||
|
Value: StoredValueRLP,
|
||||||
|
Removed: false,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
|
BlockNumber: BlockNumber2,
|
||||||
|
BlockHash: BlockHash2.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
StorageLeafKey: StorageLeafKey.String(),
|
||||||
|
StorageCID: RemovedNodeStorageCID,
|
||||||
|
Diff: true,
|
||||||
|
Value: []byte{},
|
||||||
|
Removed: true,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
|
BlockNumber: BlockNumber3,
|
||||||
|
BlockHash: BlockHash3.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
StorageLeafKey: StorageLeafKey.String(),
|
||||||
|
StorageCID: StorageCID.String(),
|
||||||
|
Diff: true,
|
||||||
|
Value: StoredValueRLP2,
|
||||||
|
Removed: false,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertStorageCID(database, storageModel{
|
||||||
|
BlockNumber: BlockNumber4,
|
||||||
|
BlockHash: NonCanonicalHash4.String(),
|
||||||
|
LeafKey: AccountLeafKey.String(),
|
||||||
|
StorageLeafKey: StorageLeafKey.String(),
|
||||||
|
StorageCID: StorageCID.String(),
|
||||||
|
Diff: true,
|
||||||
|
Value: NonCanonStoredValueRLP,
|
||||||
|
Removed: false,
|
||||||
|
}))
|
||||||
|
require.NoError(t, insertContractCode(database))
|
||||||
|
|
||||||
|
db, err := statedb.NewStateDatabaseWithSqlxPool(pool)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("Database", func(t *testing.T) {
|
||||||
|
size, err := db.ContractCodeSize(AccountCodeHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(AccountCode), size)
|
||||||
|
|
||||||
|
code, err := db.ContractCode(AccountCodeHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, AccountCode, code)
|
||||||
|
|
||||||
|
acct, err := db.StateAccount(AccountLeafKey, BlockHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &Account, acct)
|
||||||
|
|
||||||
|
acct2, err := db.StateAccount(AccountLeafKey, BlockHash2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &Account, acct2)
|
||||||
|
|
||||||
|
acct3, err := db.StateAccount(AccountLeafKey, BlockHash3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &Account, acct3)
|
||||||
|
|
||||||
|
// check that we don't get the non-canonical account
|
||||||
|
acct4, err := db.StateAccount(AccountLeafKey, BlockHash4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, &Account, acct4)
|
||||||
|
|
||||||
|
acct5, err := db.StateAccount(AccountLeafKey, BlockHash5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, acct5)
|
||||||
|
|
||||||
|
acct6, err := db.StateAccount(AccountLeafKey, BlockHash6)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, acct6)
|
||||||
|
|
||||||
|
val, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, StoredValueRLP, val)
|
||||||
|
|
||||||
|
val2, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, val2)
|
||||||
|
|
||||||
|
val3, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, StoredValueRLP2, val3)
|
||||||
|
|
||||||
|
// this checks that we don't get the non-canonical result
|
||||||
|
val4, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, StoredValueRLP2, val4)
|
||||||
|
|
||||||
|
// this checks that when the entire account was deleted, we return nil result for storage slot
|
||||||
|
val5, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, val5)
|
||||||
|
|
||||||
|
val6, err := db.StorageValue(AccountLeafKey, StorageLeafKey, BlockHash6)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, val6)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("StateDB", func(t *testing.T) {
|
||||||
|
sdb, err := statedb.New(BlockHash, db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
checkAccountUnchanged := func() {
|
||||||
|
require.Equal(t, Account.Balance, sdb.GetBalance(AccountAddress))
|
||||||
|
require.Equal(t, Account.Nonce, sdb.GetNonce(AccountAddress))
|
||||||
|
require.Equal(t, StoredValue, sdb.GetState(AccountAddress, StorageLeafKey))
|
||||||
|
require.Equal(t, AccountCodeHash, sdb.GetCodeHash(AccountAddress))
|
||||||
|
require.Equal(t, AccountCode, sdb.GetCode(AccountAddress))
|
||||||
|
require.Equal(t, len(AccountCode), sdb.GetCodeSize(AccountAddress))
|
||||||
|
}
|
||||||
|
|
||||||
|
require.True(t, sdb.Exist(AccountAddress))
|
||||||
|
checkAccountUnchanged()
|
||||||
|
|
||||||
|
id := sdb.Snapshot()
|
||||||
|
|
||||||
|
newStorage := crypto.Keccak256Hash([]byte{5, 4, 3, 2, 1})
|
||||||
|
newCode := []byte{1, 3, 3, 7}
|
||||||
|
|
||||||
|
sdb.SetBalance(AccountAddress, big.NewInt(300))
|
||||||
|
sdb.AddBalance(AccountAddress, big.NewInt(200))
|
||||||
|
sdb.SubBalance(AccountAddress, big.NewInt(100))
|
||||||
|
sdb.SetNonce(AccountAddress, 42)
|
||||||
|
sdb.SetState(AccountAddress, StorageLeafKey, newStorage)
|
||||||
|
sdb.SetCode(AccountAddress, newCode)
|
||||||
|
|
||||||
|
require.Equal(t, big.NewInt(400), sdb.GetBalance(AccountAddress))
|
||||||
|
require.Equal(t, uint64(42), sdb.GetNonce(AccountAddress))
|
||||||
|
require.Equal(t, newStorage, sdb.GetState(AccountAddress, StorageLeafKey))
|
||||||
|
require.Equal(t, newCode, sdb.GetCode(AccountAddress))
|
||||||
|
|
||||||
|
sdb.AddSlotToAccessList(AccountAddress, StorageLeafKey)
|
||||||
|
require.True(t, sdb.AddressInAccessList(AccountAddress))
|
||||||
|
hasAddr, hasSlot := sdb.SlotInAccessList(AccountAddress, StorageLeafKey)
|
||||||
|
require.True(t, hasAddr)
|
||||||
|
require.True(t, hasSlot)
|
||||||
|
|
||||||
|
sdb.RevertToSnapshot(id)
|
||||||
|
|
||||||
|
checkAccountUnchanged()
|
||||||
|
require.False(t, sdb.AddressInAccessList(AccountAddress))
|
||||||
|
hasAddr, hasSlot = sdb.SlotInAccessList(AccountAddress, StorageLeafKey)
|
||||||
|
require.False(t, hasAddr)
|
||||||
|
require.False(t, hasSlot)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertHeaderCID(db statedb.Database, blockHash, parentHash string, blockNumber uint64) error {
|
||||||
cid, err := util.Keccak256ToCid(ipld.MEthHeader, common.HexToHash(blockHash).Bytes())
|
cid, err := util.Keccak256ToCid(ipld.MEthHeader, common.HexToHash(blockHash).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -329,7 +555,7 @@ func insertHeaderCID(db *pgxpool.Pool, blockHash, parentHash string, blockNumber
|
|||||||
blockHash,
|
blockHash,
|
||||||
parentHash,
|
parentHash,
|
||||||
cid.String(),
|
cid.String(),
|
||||||
0, []string{}, 0,
|
0, pq.StringArray([]string{}), 0,
|
||||||
Header.Root.String(),
|
Header.Root.String(),
|
||||||
Header.TxHash.String(),
|
Header.TxHash.String(),
|
||||||
Header.ReceiptHash.String(),
|
Header.ReceiptHash.String(),
|
||||||
@ -354,7 +580,7 @@ type stateModel struct {
|
|||||||
Removed bool
|
Removed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertStateCID(db *pgxpool.Pool, cidModel stateModel) error {
|
func insertStateCID(db statedb.Database, cidModel stateModel) error {
|
||||||
sql := `INSERT INTO eth.state_cids (
|
sql := `INSERT INTO eth.state_cids (
|
||||||
block_number,
|
block_number,
|
||||||
header_id,
|
header_id,
|
||||||
@ -393,7 +619,7 @@ type storageModel struct {
|
|||||||
Removed bool
|
Removed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertStorageCID(db *pgxpool.Pool, cidModel storageModel) error {
|
func insertStorageCID(db statedb.Database, cidModel storageModel) error {
|
||||||
sql := `INSERT INTO eth.storage_cids (
|
sql := `INSERT INTO eth.storage_cids (
|
||||||
block_number,
|
block_number,
|
||||||
header_id,
|
header_id,
|
||||||
@ -417,9 +643,9 @@ func insertStorageCID(db *pgxpool.Pool, cidModel storageModel) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertContractCode(db *pgxpool.Pool) error {
|
func insertContractCode(db statedb.Database) error {
|
||||||
sql := `INSERT INTO ipld.blocks (block_number, key, data) VALUES ($1, $2, $3)`
|
sql := `INSERT INTO ipld.blocks (block_number, key, data) VALUES ($1, $2, $3)`
|
||||||
_, err := db.Exec(testCtx, sql, BlockNumber.Uint64(), AccountCodeCID, AccountCode)
|
_, err := db.Exec(testCtx, sql, BlockNumber.Uint64(), AccountCodeCID.String(), AccountCode)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user