Skip to content

Commit 39c646d

Browse files
committed
feat: genesis custom initial for fork logic
1 parent f829981 commit 39c646d

File tree

7 files changed

+121
-77
lines changed

7 files changed

+121
-77
lines changed

Diff for: blocksync/reactor_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@ func newReactor(
7272
}
7373

7474
blockDB := dbm.NewMemDB()
75-
stateDB := dbm.NewMemDB()
76-
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
77-
DiscardABCIResponses: false,
78-
})
75+
// stateDB := dbm.NewMemDB()
76+
// stateStore := sm.NewStore(stateDB, sm.StoreOptions{
77+
// DiscardABCIResponses: false,
78+
// })
7979
blockStore := store.NewBlockStore(blockDB)
8080

81-
state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
81+
// state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
82+
state, err := sm.MakeGenesisState(genDoc)
8283
if err != nil {
8384
panic(fmt.Errorf("error constructing state from genesis file: %w", err))
8485
}
@@ -100,7 +101,7 @@ func newReactor(
100101
// pool.height is determined from the store.
101102
blockSync := true
102103
db := dbm.NewMemDB()
103-
stateStore = sm.NewStore(db, sm.StoreOptions{
104+
stateStore := sm.NewStore(db, sm.StoreOptions{
104105
DiscardABCIResponses: false,
105106
})
106107
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),

Diff for: consensus/byzantine_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
5454
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
5555
DiscardABCIResponses: false,
5656
})
57-
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
57+
state, err := sm.MakeGenesisState(genDoc)
58+
require.NoError(t, err)
59+
require.NoError(t, stateStore.Save(state))
5860
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
5961
defer os.RemoveAll(thisConfig.RootDir)
6062
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0o700) // dir for wal

Diff for: consensus/common_test.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,11 @@ func randConsensusNet(nValidators int, testName string, tickerFunc func() Timeou
757757
configRootDirs := make([]string, 0, nValidators)
758758
for i := 0; i < nValidators; i++ {
759759
stateDB := dbm.NewMemDB() // each state needs its own db
760-
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
761-
DiscardABCIResponses: false,
762-
})
763-
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
760+
// stateStore := sm.NewStore(stateDB, sm.StoreOptions{
761+
// DiscardABCIResponses: false,
762+
// })
763+
// state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
764+
state, _ := sm.MakeGenesisState(genDoc)
764765
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
765766
configRootDirs = append(configRootDirs, thisConfig.RootDir)
766767
for _, opt := range configOpts {
@@ -796,11 +797,12 @@ func randConsensusNetWithPeers(
796797
var peer0Config *cfg.Config
797798
configRootDirs := make([]string, 0, nPeers)
798799
for i := 0; i < nPeers; i++ {
799-
stateDB := dbm.NewMemDB() // each state needs its own db
800-
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
801-
DiscardABCIResponses: false,
802-
})
803-
state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
800+
// stateDB := dbm.NewMemDB() // each state needs its own db
801+
// stateStore := sm.NewStore(stateDB, sm.StoreOptions{
802+
// DiscardABCIResponses: false,
803+
// })
804+
// state, _ := stateStore.LoadFromDBOrGenesisDoc(genDoc)
805+
state, _ := sm.MakeGenesisState(genDoc)
804806
thisConfig := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
805807
configRootDirs = append(configRootDirs, thisConfig.RootDir)
806808
ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0o700) // dir for wal

Diff for: node/node.go

+92-53
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ import (
2121
cfg "github.com/cometbft/cometbft/config"
2222
cs "github.com/cometbft/cometbft/consensus"
2323
"github.com/cometbft/cometbft/crypto"
24+
"github.com/cometbft/cometbft/crypto/tmhash"
2425
"github.com/cometbft/cometbft/evidence"
2526
"github.com/cometbft/cometbft/light"
2627

27-
cmtjson "github.com/cometbft/cometbft/libs/json"
28+
// cmtjson "github.com/cometbft/cometbft/libs/json"
2829
"github.com/cometbft/cometbft/libs/log"
2930
cmtpubsub "github.com/cometbft/cometbft/libs/pubsub"
3031
"github.com/cometbft/cometbft/libs/service"
@@ -247,10 +248,14 @@ func BootstrapState(ctx context.Context, config *cfg.Config, dbProvider DBProvid
247248
return fmt.Errorf("state not empty, trying to initialize non empty state")
248249
}
249250

250-
genState, _, err := LoadStateFromDBOrGenesisDocProvider(stateDB, DefaultGenesisDocProviderFunc(config))
251-
if err != nil {
252-
return err
253-
}
251+
// genState, _, err := LoadStateFromDBOrGenesisDocProvider(stateDB, DefaultGenesisDocProviderFunc(config))
252+
// if err != nil {
253+
// return err
254+
// }
255+
256+
genDoc, _ := DefaultGenesisDocProviderFunc(config)()
257+
258+
genState, err := LoadStateFromDBOrGenesisDoc(stateStore, stateDB, genDoc)
254259

255260
stateProvider, err := statesync.NewLightClientStateProvider(
256261
ctx,
@@ -873,11 +878,19 @@ func NewNodeWithContext(ctx context.Context,
873878
DiscardABCIResponses: config.Storage.DiscardABCIResponses,
874879
})
875880

876-
state, genDoc, err := LoadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider)
881+
// state, genDoc, err := LoadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider)
882+
genDoc, err := genesisDocProvider()
877883
if err != nil {
878884
return nil, err
879885
}
880886

887+
err = genDoc.ValidateAndComplete()
888+
if err != nil {
889+
return nil, fmt.Errorf("error in genesis doc: %w", err)
890+
}
891+
892+
state, err := LoadStateFromDBOrGenesisDoc(stateStore, stateDB, genDoc)
893+
881894
csMetrics, p2pMetrics, memplMetrics, smMetrics, abciMetrics := metricsProvider(genDoc.ChainID)
882895

883896
// Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query).
@@ -1540,68 +1553,94 @@ func makeNodeInfo(
15401553

15411554
//------------------------------------------------------------------------------
15421555

1543-
var genesisDocKey = []byte("genesisDoc")
1556+
var genesisDocHashKey = []byte("genesisDocHash")
15441557

1545-
// LoadStateFromDBOrGenesisDocProvider attempts to load the state from the
1558+
// LoadStateFromDBOrGenesisDoc attempts to load the state from the
15461559
// database, or creates one using the given genesisDocProvider. On success this also
15471560
// returns the genesis doc loaded through the given provider.
1548-
func LoadStateFromDBOrGenesisDocProvider(
1561+
func LoadStateFromDBOrGenesisDoc(
1562+
stateStore sm.Store,
15491563
stateDB dbm.DB,
1550-
genesisDocProvider GenesisDocProvider,
1551-
) (sm.State, *types.GenesisDoc, error) {
1552-
// Get genesis doc
1553-
genDoc, err := loadGenesisDoc(stateDB)
1554-
if err != nil {
1555-
genDoc, err = genesisDocProvider()
1556-
if err != nil {
1557-
return sm.State{}, nil, err
1558-
}
1559-
// save genesis doc to prevent a certain class of user errors (e.g. when it
1560-
// was changed, accidentally or not). Also good for audit trail.
1561-
if err := saveGenesisDoc(stateDB, genDoc); err != nil {
1562-
return sm.State{}, nil, err
1563-
}
1564-
}
1565-
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
1566-
DiscardABCIResponses: false,
1567-
})
1568-
state, err := stateStore.LoadFromDBOrGenesisDoc(genDoc)
1564+
genDoc *types.GenesisDoc,
1565+
) (sm.State, error) {
1566+
// 1. Verify genesisDoc hash in db if exists
1567+
genDocHash, err := stateDB.Get(genesisDocHashKey)
15691568
if err != nil {
1570-
return sm.State{}, nil, err
1569+
return sm.State{}, err
15711570
}
1572-
return state, genDoc, nil
1573-
}
15741571

1575-
// panics if failed to unmarshal bytes
1576-
func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) {
1577-
b, err := db.Get(genesisDocKey)
1578-
if err != nil {
1579-
panic(err)
1580-
}
1581-
if len(b) == 0 {
1582-
return nil, errors.New("genesis doc not found")
1583-
}
1584-
var genDoc *types.GenesisDoc
1585-
err = cmtjson.Unmarshal(b, &genDoc)
1586-
if err != nil {
1587-
panic(fmt.Sprintf("Failed to load genesis doc due to unmarshaling error: %v (bytes: %X)", err, b))
1572+
validatorsHash := genDoc.ValidatorHash()
1573+
1574+
incomingGenDocHash := tmhash.Sum(validatorsHash)
1575+
1576+
fmt.Println("Loaded genesis doc", "chain_id", genDoc.ChainID, "app_hash", genDoc.AppHash)
1577+
fmt.Println("incomingGenDocHash: ", incomingGenDocHash)
1578+
fmt.Println("genDocHash: ", genDocHash)
1579+
1580+
if len(genDocHash) != 0 && !bytes.Equal(genDocHash, incomingGenDocHash) {
1581+
return sm.State{}, fmt.Errorf("genesis doc hash in db does not match loaded genesis doc")
15881582
}
1589-
return genDoc, nil
1590-
}
15911583

1592-
// panics if failed to marshal the given genesis document
1593-
func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) error {
1594-
b, err := cmtjson.Marshal(genDoc)
1584+
// 2. Attempt to load state form the database
1585+
state, err := stateStore.Load()
15951586
if err != nil {
1596-
return fmt.Errorf("failed to save genesis doc due to marshaling error: %w", err)
1587+
return sm.State{}, err
15971588
}
1598-
if err := db.SetSync(genesisDocKey, b); err != nil {
1599-
return err
1589+
1590+
if state.IsEmpty() {
1591+
// 3. If it's not there, derive it from the genesis doc
1592+
state, err = sm.MakeGenesisState(genDoc)
1593+
if err != nil {
1594+
return sm.State{}, err
1595+
}
1596+
1597+
// 4. save the gensis document to the state store so
1598+
// its fetchable by other callers.
1599+
if err := stateStore.Save(state); err != nil {
1600+
return sm.State{}, err
1601+
}
1602+
1603+
// 5. Save the genDoc hash in the store if it doesn't already exist for future verification
1604+
if len(genDocHash) == 0 {
1605+
if err := stateDB.SetSync(genesisDocHashKey, incomingGenDocHash); err != nil {
1606+
return sm.State{}, fmt.Errorf("failed to save genesis doc hash to db: %w", err)
1607+
}
1608+
}
16001609
}
16011610

1602-
return nil
1611+
return state, nil
16031612
}
16041613

1614+
// // panics if failed to unmarshal bytes
1615+
// func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) {
1616+
// b, err := db.Get(genesisDocKey)
1617+
// if err != nil {
1618+
// panic(err)
1619+
// }
1620+
// if len(b) == 0 {
1621+
// return nil, errors.New("genesis doc not found")
1622+
// }
1623+
// var genDoc *types.GenesisDoc
1624+
// err = cmtjson.Unmarshal(b, &genDoc)
1625+
// if err != nil {
1626+
// panic(fmt.Sprintf("Failed to load genesis doc due to unmarshaling error: %v (bytes: %X)", err, b))
1627+
// }
1628+
// return genDoc, nil
1629+
// }
1630+
1631+
// // panics if failed to marshal the given genesis document
1632+
// func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) error {
1633+
// b, err := cmtjson.Marshal(genDoc)
1634+
// if err != nil {
1635+
// return fmt.Errorf("failed to save genesis doc due to marshaling error: %w", err)
1636+
// }
1637+
// if err := db.SetSync(genesisDocKey, b); err != nil {
1638+
// return err
1639+
// }
1640+
1641+
// return nil
1642+
// }
1643+
16051644
func createAndStartPrivValidatorSocketClient(
16061645
listenAddr,
16071646
chainID string,

Diff for: state/state_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, sm.State) {
3232
DiscardABCIResponses: false,
3333
})
3434
require.NoError(t, err)
35-
state, err := stateStore.LoadFromDBOrGenesisFile(config.GenesisFile())
35+
state, err := sm.MakeGenesisStateFromFile(config.GenesisFile())
3636
assert.NoError(t, err, "expected no error on LoadStateFromDBOrGenesisFile")
3737
err = stateStore.Save(state)
3838
require.NoError(t, err)

Diff for: state/store.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ var offlineStateSyncHeight = []byte("offlineStateSyncHeightKey")
5151
// It is used to retrieve current state and save and load ABCI responses,
5252
// validators and consensus parameters
5353
type Store interface {
54-
// LoadFromDBOrGenesisFile loads the most recent state.
55-
// If the chain is new it will use the genesis file from the provided genesis file path as the current state.
56-
LoadFromDBOrGenesisFile(string) (State, error)
57-
// LoadFromDBOrGenesisDoc loads the most recent state.
58-
// If the chain is new it will use the genesis doc as the current state.
59-
LoadFromDBOrGenesisDoc(*types.GenesisDoc) (State, error)
54+
// // LoadFromDBOrGenesisFile loads the most recent state.
55+
// // If the chain is new it will use the genesis file from the provided genesis file path as the current state.
56+
// LoadFromDBOrGenesisFile(string) (State, error)
57+
// // LoadFromDBOrGenesisDoc loads the most recent state.
58+
// // If the chain is new it will use the genesis doc as the current state.
59+
// LoadFromDBOrGenesisDoc(*types.GenesisDoc) (State, error)
6060
// Load loads the current state of the blockchain
6161
Load() (State, error)
6262
// LoadValidators loads the validator set at a given height

Diff for: state/store_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func BenchmarkLoadValidators(b *testing.B) {
5656
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
5757
DiscardABCIResponses: false,
5858
})
59-
state, err := stateStore.LoadFromDBOrGenesisFile(config.GenesisFile())
59+
state, err := sm.MakeGenesisStateFromFile(config.GenesisFile())
6060
if err != nil {
6161
b.Fatal(err)
6262
}

0 commit comments

Comments
 (0)