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

blockchain: Add UtxoBackend interface. #2652

Merged
merged 12 commits into from
May 25, 2021
22 changes: 12 additions & 10 deletions blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,6 @@ type BlockChain struct {
deploymentVers map[string]uint32
db database.DB
dbInfo *databaseInfo
utxoDb database.DB
utxoDbInfo *utxoDatabaseInfo
chainParams *chaincfg.Params
timeSource MedianTimeSource
notifications NotificationCallback
Expand Down Expand Up @@ -2110,10 +2108,10 @@ type Config struct {
// This field is required.
DB database.DB

// UtxoDB defines the database which houses the UTXO set.
// UtxoBackend defines the backend which houses the UTXO set.
//
// This field is required.
UtxoDB database.DB
UtxoBackend UtxoBackend

// ChainParams identifies which chain parameters the chain is associated
// with.
Expand Down Expand Up @@ -2183,8 +2181,8 @@ func New(ctx context.Context, config *Config) (*BlockChain, error) {
if config.DB == nil {
return nil, AssertError("blockchain.New database is nil")
}
if config.UtxoDB == nil {
return nil, AssertError("blockchain.New UTXO database is nil")
if config.UtxoBackend == nil {
return nil, AssertError("blockchain.New UTXO backend is nil")
}
if config.ChainParams == nil {
return nil, AssertError("blockchain.New chain parameters nil")
Expand Down Expand Up @@ -2226,7 +2224,6 @@ func New(ctx context.Context, config *Config) (*BlockChain, error) {
checkpointsByHeight: checkpointsByHeight,
deploymentVers: deploymentVers,
db: config.DB,
utxoDb: config.UtxoDB,
chainParams: params,
timeSource: config.TimeSource,
notifications: config.Notifications,
Expand All @@ -2251,13 +2248,13 @@ func New(ctx context.Context, config *Config) (*BlockChain, error) {
// Initialize the chain state from the passed database. When the db
// does not yet contain any chain state, both it and the chain state
// will be initialized to contain only the genesis block.
if err := b.initChainState(ctx); err != nil {
if err := b.initChainState(ctx, config.UtxoBackend); err != nil {
return nil, err
}

// Initialize the UTXO state. This entails running any database migrations as
// necessary as well as initializing the UTXO cache.
if err := b.initUtxoState(ctx); err != nil {
if err := b.utxoCache.Initialize(ctx, &b, b.bestChain.tip()); err != nil {
return nil, err
}

Expand All @@ -2275,8 +2272,13 @@ func New(ctx context.Context, config *Config) (*BlockChain, error) {
"%d, block index: %d, spend journal: %d", b.dbInfo.version,
b.dbInfo.compVer, b.dbInfo.bidxVer, b.dbInfo.stxoVer)

// Fetch and log the UTXO backend versioning info.
utxoDbInfo, err := config.UtxoBackend.FetchInfo()
if err != nil {
return nil, err
}
log.Infof("UTXO database version info: version: %d, compression: %d, utxo "+
"set: %d", b.utxoDbInfo.version, b.utxoDbInfo.compVer, b.utxoDbInfo.utxoVer)
"set: %d", utxoDbInfo.version, utxoDbInfo.compVer, utxoDbInfo.utxoVer)

b.index.RLock()
bestHdr := b.index.bestHeader
Expand Down
6 changes: 4 additions & 2 deletions blockchain/chainio.go
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,9 @@ func loadBlockIndex(dbTx database.Tx, genesisHash *chainhash.Hash, index *blockI
// initChainState attempts to load and initialize the chain state from the
// database. When the db does not yet contain any chain state, both it and the
// chain state are initialized to the genesis block.
func (b *BlockChain) initChainState(ctx context.Context) error {
func (b *BlockChain) initChainState(ctx context.Context,
utxoBackend UtxoBackend) error {

// Update database versioning scheme if needed.
err := b.db.Update(func(dbTx database.Tx) error {
// No versioning upgrade is needed if the dbinfo bucket does not
Expand Down Expand Up @@ -1387,7 +1389,7 @@ func (b *BlockChain) initChainState(ctx context.Context) error {
// block database info is loaded, but before block database migrations are
// run, since setting the initial UTXO set version depends on the block
// database version as that is where it originally resided.
if err := b.initUtxoDbInfo(ctx); err != nil {
if err := utxoBackend.InitInfo(b.dbInfo.version); err != nil {
return err
}

Expand Down
18 changes: 7 additions & 11 deletions blockchain/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,16 @@ func chainSetup(dbName string, params *chaincfg.Params) (*BlockChain, func(), er
}

// Create the main chain instance.
utxoBackend := NewLevelDbUtxoBackend(utxoDb)
chain, err := New(context.Background(),
&Config{
DB: db,
UtxoDB: utxoDb,
UtxoBackend: utxoBackend,
ChainParams: &paramsCopy,
TimeSource: NewMedianTime(),
SigCache: sigCache,
UtxoCache: NewUtxoCache(&UtxoCacheConfig{
DB: utxoDb,
Backend: utxoBackend,
FlushBlockDB: func() error {
// Don't flush to disk since it is slow and this is used in a lot of
// tests.
Expand Down Expand Up @@ -787,24 +788,19 @@ func (g *chaingenHarness) ExpectTip(tipName string) {
}

// ExpectUtxoSetState expects the provided block to be the last flushed block in
// the utxo set state in the database.
// the utxo set state in the utxo backend.
func (g *chaingenHarness) ExpectUtxoSetState(blockName string) {
g.t.Helper()

// Fetch the utxo set state from the database.
var gotState *utxoSetState
err := g.chain.utxoDb.View(func(dbTx database.Tx) error {
var err error
gotState, err = dbFetchUtxoSetState(dbTx)
return err
})
// Fetch the utxo set state from the utxo backend.
gotState, err := g.chain.utxoCache.FetchBackendState()
if err != nil {
g.t.Fatalf("unexpected error fetching utxo set state: %v", err)
}

// Validate that the state matches the expected state.
block := g.BlockByName(blockName)
wantState := &utxoSetState{
wantState := &UtxoSetState{
lastFlushHeight: block.Header.Height,
lastFlushHash: block.BlockHash(),
}
Expand Down
2 changes: 1 addition & 1 deletion blockchain/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func ExampleBlockChain_ProcessBlock() {
ChainParams: mainNetParams,
TimeSource: blockchain.NewMedianTime(),
UtxoCache: blockchain.NewUtxoCache(&blockchain.UtxoCacheConfig{
DB: db,
Backend: blockchain.NewLevelDbUtxoBackend(db),
FlushBlockDB: func() error {
return nil
},
Expand Down
5 changes: 3 additions & 2 deletions blockchain/fullblocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,16 @@ func chainSetup(dbName string, params *chaincfg.Params) (*blockchain.BlockChain,
}

// Create the main chain instance.
utxoBackend := blockchain.NewLevelDbUtxoBackend(utxoDb)
chain, err := blockchain.New(context.Background(),
&blockchain.Config{
DB: db,
UtxoDB: utxoDb,
UtxoBackend: utxoBackend,
ChainParams: &paramsCopy,
TimeSource: blockchain.NewMedianTime(),
SigCache: sigCache,
UtxoCache: blockchain.NewUtxoCache(&blockchain.UtxoCacheConfig{
DB: utxoDb,
Backend: utxoBackend,
FlushBlockDB: func() error {
// Don't flush to disk since it is slow and this is used in a lot of
// tests.
Expand Down
56 changes: 22 additions & 34 deletions blockchain/stakeext.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package blockchain

import (
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/database/v2"
"github.com/decred/dcrd/dcrutil/v4"
"github.com/decred/dcrd/txscript/v4"
"github.com/decred/dcrd/txscript/v4/stdaddr"
Expand Down Expand Up @@ -111,27 +110,22 @@ func (b *BlockChain) TicketsWithAddress(address stdaddr.Address, isTreasuryEnabl

encodedAddr := address.String()
var ticketsWithAddr []chainhash.Hash
err := b.utxoDb.View(func(dbTx database.Tx) error {
for _, hash := range tickets {
outpoint := wire.OutPoint{Hash: hash, Index: 0, Tree: wire.TxTreeStake}
utxo, err := b.utxoCache.FetchEntry(dbTx, outpoint)
if err != nil {
return err
}

_, addrs, _, err := txscript.ExtractPkScriptAddrs(utxo.ScriptVersion(),
utxo.PkScript(), b.chainParams, isTreasuryEnabled)
if err != nil {
return err
}
if addrs[0].String() == encodedAddr {
ticketsWithAddr = append(ticketsWithAddr, hash)
}

for _, hash := range tickets {
outpoint := wire.OutPoint{Hash: hash, Index: 0, Tree: wire.TxTreeStake}
utxo, err := b.utxoCache.FetchEntry(outpoint)
if err != nil {
return nil, err
}

_, addrs, _, err := txscript.ExtractPkScriptAddrs(utxo.ScriptVersion(),
utxo.PkScript(), b.chainParams, isTreasuryEnabled)
if err != nil {
return nil, err
}
if addrs[0].String() == encodedAddr {
ticketsWithAddr = append(ticketsWithAddr, hash)
}
return nil
})
if err != nil {
return nil, err
}

return ticketsWithAddr, nil
Expand Down Expand Up @@ -223,20 +217,14 @@ func (b *BlockChain) TicketPoolValue() (dcrutil.Amount, error) {
b.chainLock.RUnlock()

var amt int64
err := b.utxoDb.View(func(dbTx database.Tx) error {
for _, hash := range sn.LiveTickets() {
outpoint := wire.OutPoint{Hash: hash, Index: 0, Tree: wire.TxTreeStake}
utxo, err := b.utxoCache.FetchEntry(dbTx, outpoint)
if err != nil {
return err
}

amt += utxo.Amount()
for _, hash := range sn.LiveTickets() {
outpoint := wire.OutPoint{Hash: hash, Index: 0, Tree: wire.TxTreeStake}
utxo, err := b.utxoCache.FetchEntry(outpoint)
if err != nil {
return 0, err
}
return nil
})
if err != nil {
return 0, err

amt += utxo.Amount()
}
return dcrutil.Amount(amt), nil
}
Loading