blockchain: Don't require chain for db upgrades.
This modifies the database upgrade logic to avoid needing the chain and moves it earlier in the initialization process just after the initial database creation (if needed), but prior the final struct instance population from the database. It is much simpler logic to have an already upgraded database prior to populating the initial chain state so all of the initial setup happens in one place.
This commit is contained in:
parent
eaa59edc88
commit
a0fc0806ec
@ -2008,11 +2008,6 @@ func New(config *Config) (*BlockChain, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Apply any upgrades as needed.
|
||||
if err := b.upgrade(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.subsidyCache = NewSubsidyCache(b.bestNode.height, b.chainParams)
|
||||
b.pruner = newChainPruner(&b)
|
||||
|
||||
|
||||
@ -1435,6 +1435,11 @@ func (b *BlockChain) initChainState() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade the database as needed.
|
||||
if err := upgradeDB(b.db, b.chainParams, b.dbInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attempt to load the chain state from the database.
|
||||
err = b.db.View(func(dbTx database.Tx) error {
|
||||
// Fetch the stored chain state from the database metadata.
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/decred/dcrd/blockchain/internal/progresslog"
|
||||
"github.com/decred/dcrd/blockchain/stake"
|
||||
"github.com/decred/dcrd/chaincfg"
|
||||
"github.com/decred/dcrd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/database"
|
||||
"github.com/decred/dcrd/dcrutil"
|
||||
@ -83,17 +84,26 @@ func ticketsRevokedInBlock(bl *dcrutil.Block) []chainhash.Hash {
|
||||
|
||||
// upgradeToVersion2 upgrades a version 1 blockchain to version 2, allowing
|
||||
// use of the new on-disk ticket database.
|
||||
func (b *BlockChain) upgradeToVersion2() error {
|
||||
func upgradeToVersion2(db database.DB, chainParams *chaincfg.Params, dbInfo *databaseInfo) error {
|
||||
// Hardcoded so updates to the global values do not affect old upgrades.
|
||||
chainStateKeyName := []byte("chainstate")
|
||||
|
||||
log.Infof("Initializing upgrade to database version 2")
|
||||
best := b.BestSnapshot()
|
||||
progressLogger := progresslog.NewBlockProgressLogger("Upgraded", log)
|
||||
|
||||
// The upgrade is atomic, so there is no need to set the flag that
|
||||
// the database is undergoing an upgrade here. Get the stake node
|
||||
// for the genesis block, and then begin connecting stake nodes
|
||||
// incrementally.
|
||||
err := b.db.Update(func(dbTx database.Tx) error {
|
||||
bestStakeNode, errLocal := stake.InitDatabaseState(dbTx, b.chainParams)
|
||||
err := db.Update(func(dbTx database.Tx) error {
|
||||
// Fetch the stored best chain state from the database metadata.
|
||||
serializedData := dbTx.Metadata().Get(chainStateKeyName)
|
||||
best, err := deserializeBestChainState(serializedData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bestStakeNode, errLocal := stake.InitDatabaseState(dbTx, chainParams)
|
||||
if errLocal != nil {
|
||||
return errLocal
|
||||
}
|
||||
@ -103,7 +113,7 @@ func (b *BlockChain) upgradeToVersion2() error {
|
||||
return errLocal
|
||||
}
|
||||
|
||||
for i := int64(1); i <= best.Height; i++ {
|
||||
for i := int64(1); i <= int64(best.height); i++ {
|
||||
block, errLocal := dbFetchBlockByHeight(dbTx, i)
|
||||
if errLocal != nil {
|
||||
return errLocal
|
||||
@ -111,8 +121,8 @@ func (b *BlockChain) upgradeToVersion2() error {
|
||||
|
||||
// If we need the tickets, fetch them too.
|
||||
var newTickets []chainhash.Hash
|
||||
if i >= b.chainParams.StakeEnabledHeight {
|
||||
matureHeight := i - int64(b.chainParams.TicketMaturity)
|
||||
if i >= chainParams.StakeEnabledHeight {
|
||||
matureHeight := i - int64(chainParams.TicketMaturity)
|
||||
matureBlock, errLocal := dbFetchBlockByHeight(dbTx, matureHeight)
|
||||
if errLocal != nil {
|
||||
return errLocal
|
||||
@ -140,27 +150,18 @@ func (b *BlockChain) upgradeToVersion2() error {
|
||||
|
||||
// Write the top block stake node to the database.
|
||||
errLocal = stake.WriteConnectedBestNode(dbTx, bestStakeNode,
|
||||
best.Hash)
|
||||
best.hash)
|
||||
if errLocal != nil {
|
||||
return errLocal
|
||||
}
|
||||
|
||||
// Write the best block node when we reach it.
|
||||
if i == best.Height {
|
||||
b.bestNode.stakeNode = bestStakeNode
|
||||
b.bestNode.stakeUndoData = bestStakeNode.UndoData()
|
||||
b.bestNode.newTickets = newTickets
|
||||
b.bestNode.ticketsVoted = ticketsVotedInBlock(block)
|
||||
b.bestNode.ticketsRevoked = ticketsRevokedInBlock(block)
|
||||
}
|
||||
|
||||
progressLogger.LogBlockHeight(block.MsgBlock(), parent.MsgBlock())
|
||||
parent = block
|
||||
}
|
||||
|
||||
// Write the new database version.
|
||||
b.dbInfo.version = 2
|
||||
return dbPutDatabaseInfo(dbTx, b.dbInfo)
|
||||
dbInfo.version = 2
|
||||
return dbPutDatabaseInfo(dbTx, dbInfo)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -171,15 +172,15 @@ func (b *BlockChain) upgradeToVersion2() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// upgrade applies all possible upgrades to the blockchain database iteratively,
|
||||
// updating old clients to the newest version.
|
||||
func (b *BlockChain) upgrade() error {
|
||||
if b.dbInfo.version == 1 {
|
||||
err := b.upgradeToVersion2()
|
||||
if err != nil {
|
||||
// upgradeDB upgrades old database versions to the newest version by applying
|
||||
// all possible upgrades iteratively.
|
||||
//
|
||||
// NOTE: The passed database info will be updated with the latest versions.
|
||||
func upgradeDB(db database.DB, chainParams *chaincfg.Params, dbInfo *databaseInfo) error {
|
||||
if dbInfo.version == 1 {
|
||||
if err := upgradeToVersion2(db, chainParams, dbInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user