8000 Re-implement removal of genesis persistence in state db by sergio-mena · Pull Request #1295 · cometbft/cometbft · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Re-implement removal of genesis persistence in state db #1295

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

Merged
merged 7 commits into from
Sep 1, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `[node]` Remove genesis persistence in state db, replaced by a hash
([cometbft/cometbft\#1017](https://github.com/cometbft/cometbft/pull/1017),
[cometbft/cometbft\#1295](https://github.com/cometbft/cometbft/pull/1295))
70 changes: 70 additions & 0 deletions node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ import (
"github.com/cometbft/cometbft/abci/example/kvstore"
cfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/crypto/ed25519"
"github.com/cometbft/cometbft/crypto/tmhash"
"github.com/cometbft/cometbft/evidence"
"github.com/cometbft/cometbft/internal/test"
cmtjson "github.com/cometbft/cometbft/libs/json"
"github.com/cometbft/cometbft/libs/log"
cmtos "github.com/cometbft/cometbft/libs/os"
cmtrand "github.com/cometbft/cometbft/libs/rand"
mempl "github.com/cometbft/cometbft/mempool"
"github.com/cometbft/cometbft/p2p"
Expand Down Expand Up @@ -465,6 +468,73 @@ func TestNodeNewNodeCustomReactors(t *testing.T) {
assert.Contains(t, channels, cr.Channels[0].ID)
}

func TestNodeNewNodeGenesisHashMismatch(t *testing.T) {
config := test.ResetTestRoot("node_new_node_genesis_hash")
defer os.RemoveAll(config.RootDir)

// Use goleveldb so we can reuse the same db for the second NewNode()
config.DBBackend = string(dbm.GoLevelDBBackend)

nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
require.NoError(t, err)

n, err := NewNode(
context.Background(),
config,
privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
nodeKey,
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
DefaultGenesisDocProviderFunc(config),
cfg.DefaultDBProvider,
DefaultMetricsProvider(config.Instrumentation),
log.TestingLogger(),
)
require.NoError(t, err)

// Start and stop to close the db for later reading
err = n.Start()
require.NoError(t, err)

err = n.Stop()
require.NoError(t, err)

// Ensure the genesis doc hash is saved to db
stateDB, err := cfg.DefaultDBProvider(&cfg.DBContext{ID: "state", Config: config})
require.NoError(t, err)

genDocHash, err := stateDB.Get(genesisDocHashKey)
require.NoError(t, err)
require.NotNil(t, genDocHash, "genesis doc hash should be saved in db")
require.Len(t, genDocHash, tmhash.Size)

err = stateDB.Close()
require.NoError(t, err)

// Modify the genesis file chain ID to get a different hash
genBytes := cmtos.MustReadFile(config.GenesisFile())
var genesisDoc types.GenesisDoc
err = cmtjson.Unmarshal(genBytes, &genesisDoc)
require.NoError(t, err)

genesisDoc.ChainID = "different-chain-id"
err = genesisDoc.SaveAs(config.GenesisFile())
require.NoError(t, err)

_, err = NewNode(
context.Background(),
config,
privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
nodeKey,
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
DefaultGenesisDocProviderFunc(config),
cfg.DefaultDBProvider,
DefaultMetricsProvider(config.Instrumentation),
log.TestingLogger(),
)
require.Error(t, err, "NewNode should error when genesisDoc is changed")
require.Equal(t, "genesis doc hash in db does not match loaded genesis doc", err.Error())
}

func state(nVals int, height int64) (sm.State, dbm.DB, []types.PrivValidator) {
privVals := make([]types.PrivValidator, nVals)
vals := make([]types.GenesisValidator, nVals)
Expand Down
69 changes: 28 additions & 41 deletions node/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package node
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"strings"
Expand All @@ -18,6 +17,7 @@ import (
cfg "github.com/cometbft/cometbft/config"
cs "github.com/cometbft/cometbft/consensus"
"github.com/cometbft/cometbft/crypto"
"github.com/cometbft/cometbft/crypto/tmhash"
"github.com/cometbft/cometbft/evidence"
"github.com/cometbft/cometbft/statesync"

Expand Down Expand Up @@ -529,7 +529,8 @@ func startStateSync(

//------------------------------------------------------------------------------

var genesisDocKey = []byte("genesisDoc")
// var genesisDocKey = []byte("genesisDoc")
var genesisDocHashKey = []byte("genesisDocHash")

// LoadStateFromDBOrGenesisDocProvider attempts to load the state from the
// database, or creates one using the given genesisDocProvider. On success this also
Expand All @@ -538,22 +539,34 @@ func LoadStateFromDBOrGenesisDocProvider(
stateDB dbm.DB,
genesisDocProvider GenesisDocProvider,
) (sm.State, *types.GenesisDoc, error) {
// Get genesis doc
genDoc, err := loadGenesisDoc(stateDB)
// Get genesis doc hash
genDocHash, err := stateDB.Get(genesisDocHashKey)
if err != nil {
genDoc, err = genesisDocProvider()
if err != nil {
return sm.State{}, nil, err
}
return sm.State{}, nil, fmt.Errorf("error retrieving genesis doc hash: %w", err)
}
genDoc, err := genesisDocProvider()
if err != nil {
return sm.State{}, nil, err
}

err = genDoc.ValidateAndComplete()
if err != nil {
return sm.State{}, nil, fmt.Errorf("error in genesis doc: %w", err)
if err := genDoc.ValidateAndComplete(); err != nil {
return sm.State{}, nil, fmt.Errorf("error in genesis doc: %w", err)
}

genDocBytes, err := cmtjson.Marshal(genDoc)
if err != nil {
return sm.State{}, nil, fmt.Errorf("failed to save genesis doc hash due to marshaling error: %w", err)
}

incomingGenDocHash := tmhash.Sum(genDocBytes)
if len(genDocHash) == 0 {
// Save the genDoc hash in the store if it doesn't already exist for future verification
if err := stateDB.SetSync(genesisDocHashKey, incomingGenDocHash); err != nil {
return sm.State{}, nil, fmt.Errorf("failed to save genesis doc hash to db: %w", err)
}
// save genesis doc to prevent a certain class of user errors (e.g. when it
// was changed, accidentally or not). Also good for audit trail.
if err := saveGenesisDoc(stateDB, genDoc); err != nil {
return sm.State{}, nil, err
} else {
if !bytes.Equal(genDocHash, incomingGenDocHash) {
return sm.State{}, nil, fmt.Errorf("genesis doc hash in db does not match loaded genesis doc")
}
}
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
Expand All @@ -566,32 +579,6 @@ func LoadStateFromDBOrGenesisDocProvider(
return state, genDoc, nil
}

// panics if failed to unmarshal bytes
func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) {
b, err := db.Get(genesisDocKey)
if err != nil {
panic(err)
}
if len(b) == 0 {
return nil, errors.New("genesis doc not found")
}
var genDoc *types.GenesisDoc
err = cmtjson.Unmarshal(b, &genDoc)
if err != nil {
panic(fmt.Sprintf("Failed to load genesis doc due to unmarshaling error: %v (bytes: %X)", err, b))
}
return genDoc, nil
}

// panics if failed to marshal the given genesis document
func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) error {
b, err := cmtjson.Marshal(genDoc)
if err != nil {
return fmt.Errorf("failed to save genesis doc due to marshaling error: %w", err)
}
return db.SetSync(genesisDocKey, b)
}

func createAndStartPrivValidatorSocketClient(
listenAddr,
chainID string,
Expand Down
0