Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix network validation during database upgrade case. #856

Merged
merged 2 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions idb/dummy/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,8 @@ func (db *dummyIndexerDb) Health(ctx context.Context) (state idb.Health, err err
func (db *dummyIndexerDb) GetNetworkState() (state idb.NetworkState, err error) {
return idb.NetworkState{}, nil
}

// SetNetworkState is part of idb.IndexerDB
func (db *dummyIndexerDb) SetNetworkState(genesis bookkeeping.Genesis) error {
return nil
}
1 change: 1 addition & 0 deletions idb/idb.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ type IndexerDb interface {
GetNextRoundToAccount() (uint64, error)
GetSpecialAccounts(ctx context.Context) (transactions.SpecialAddresses, error)
GetNetworkState() (NetworkState, error)
SetNetworkState(genesis bookkeeping.Genesis) error

GetBlock(ctx context.Context, round uint64, options GetBlockOptions) (blockHeader bookkeeping.BlockHeader, transactions []TxnRow, err error)

Expand Down
14 changes: 14 additions & 0 deletions idb/mocks/IndexerDb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions idb/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -2312,3 +2312,11 @@ func (db *IndexerDb) GetNetworkState() (idb.NetworkState, error) {
}
return networkState, nil
}

// SetNetworkState is part of idb.IndexerDB
func (db *IndexerDb) SetNetworkState(genesis bookkeeping.Genesis) error {
networkState := types.NetworkState{
GenesisHash: crypto.HashObj(genesis),
}
return db.setNetworkState(nil, &networkState)
}
21 changes: 21 additions & 0 deletions idb/postgres/postgres_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/algorand/go-algorand/data/basics"
"github.com/algorand/go-algorand/data/transactions"
"github.com/algorand/go-algorand/protocol"
"github.com/algorand/go-codec/codec"
"github.com/algorand/indexer/importer"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"
Expand Down Expand Up @@ -1942,6 +1943,10 @@ func TestGenesisHashCheckAtDBSetup(t *testing.T) {
assert.Contains(t, err.Error(), "genesis hash not matching")
}

type ImportState struct {
NextRoundToAccount uint64 `codec:"next_account_round"`
}

// Test that if genesis hash at initial import is different from what is in db metastate
// indexer does not start.
func TestGenesisHashCheckAtInitialImport(t *testing.T) {
Expand All @@ -1951,11 +1956,27 @@ func TestGenesisHashCheckAtInitialImport(t *testing.T) {
db, _, err := OpenPostgres(connStr, idb.IndexerDbOptions{}, nil)
require.NoError(t, err)
defer db.Close()
// test db upgrade
// set next round to account
state := ImportState{NextRoundToAccount: 1}
var buf []byte
jsonCodecHandle := new(codec.JsonHandle)
enc := codec.NewEncoderBytes(&buf, jsonCodecHandle)
enc.MustEncode(state)
db.setMetastate(nil, schema.StateMetastateKey, string(buf))
// network state not initialized
networkState, err := db.getNetworkState(context.Background(), nil)
require.ErrorIs(t, err, idb.ErrorNotInitialized)
logger := logrus.New()
genesisReader := bytes.NewReader(protocol.EncodeJSON(genesis))
imported, err := importer.EnsureInitialImport(db, genesisReader, logger)
require.NoError(t, err)
require.True(t, true, imported)
// network state should be set
networkState, err = db.getNetworkState(context.Background(), nil)
require.NoError(t, err)
require.Equal(t, networkState.GenesisHash, crypto.HashObj(genesis))

// change genesis value
genesis.Network = "testnest"
genesisReader = bytes.NewReader(protocol.EncodeJSON(genesis))
Expand Down
15 changes: 11 additions & 4 deletions importer/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"archive/tar"
"compress/bzip2"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -267,10 +268,6 @@ func GetGenesisFile(genesisJSONPath string, client *algod.Client, l *log.Logger)
}

func checkGenesisHash(db idb.IndexerDb, genesisReader io.Reader) error {
network, err := db.GetNetworkState()
if err != nil {
return fmt.Errorf("unable to fetch network state from db %w", err)
}
var genesis bookkeeping.Genesis
gbytes, err := ioutil.ReadAll(genesisReader)
if err != nil {
Expand All @@ -280,6 +277,16 @@ func checkGenesisHash(db idb.IndexerDb, genesisReader io.Reader) error {
if err != nil {
return fmt.Errorf("error decoding genesis, %w", err)
}
network, err := db.GetNetworkState()
if errors.Is(err, idb.ErrorNotInitialized) {
err = db.SetNetworkState(genesis)
if err != nil {
return fmt.Errorf("error setting network state %w", err)
}
return nil
} else if err != nil {
return fmt.Errorf("unable to fetch network state from db %w", err)
}
if network.GenesisHash != crypto.HashObj(genesis) {
return fmt.Errorf("genesis hash not matching")
}
Expand Down