Skip to content

Commit

Permalink
blockchain: Cleanup and optimize stake node logic.
Browse files Browse the repository at this point in the history
This reworks the stake node handling logic a bit to clean it up,
slightly optimize it, and to make it easier to decouple the chain
processing and connection code from the download logic in the future.

To accomplish this, the fetchStakeNode dependence on the
getReorganizeNodes function is removed in favor of directly iterating
the block nodes in the function as needed.  Not only is this more
efficient, it also allows the function to return stake nodes for
branches regardless of their validation status.  Currently, this is
irrelevant due to the connection and download logic being tightly
coupled.  However, it will be necessary in the future when those are
separated.

Also, the flushing and pruning logic is modified to no longer rely on
the download logic being tightly coupled to the the connection logic.
In particular, a new function named flushBlockIndex is added as a
wrapper to the index flush function which populates stake information in
a node before flushing it to the database as needed, and all flushing
invocations use the wrapper instead.

Finally, the stakeUndoData field is removed since it is only used to
avoid some database loads on reorgs that are large enough to exceed the
pruning depth, which never happens in practice anyway, so there is no
point in using up extra memory for it.
  • Loading branch information
davecgh committed Oct 19, 2018
1 parent 5f6c705 commit 20631a1
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 147 deletions.
3 changes: 1 addition & 2 deletions blockchain/accept.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (b *BlockChain) maybeAcceptBlock(block *dcrutil.Block, flags BehaviorFlags)
b.index.AddNode(newNode)

// Ensure the new block index entry is written to the database.
err = b.index.flush()
err = b.flushBlockIndex()
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -111,7 +111,6 @@ func (b *BlockChain) maybeAcceptBlock(block *dcrutil.Block, flags BehaviorFlags)
if err != nil {
return 0, err
}
newNode.stakeUndoData = newNode.stakeNode.UndoData()
}

// Grab the parent block since it is required throughout the block
Expand Down
3 changes: 1 addition & 2 deletions blockchain/blockindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ type blockNode struct {
// evaluation of sidechains.
stakeNode *stake.Node
newTickets []chainhash.Hash
stakeUndoData stake.UndoTicketDataSlice
ticketsVoted []chainhash.Hash
ticketsRevoked []chainhash.Hash

Expand Down Expand Up @@ -227,7 +226,7 @@ func (node *blockNode) lotteryIV() chainhash.Hash {
// node.
//
// This function is NOT safe for concurrent access. It must only be called when
// initially creating a node.
// initially creating a node or when protected by the chain lock.
func (node *blockNode) populateTicketInfo(spentTickets *stake.SpentTicketsInBlock) {
node.ticketsVoted = spentTickets.VotedTickets
node.ticketsRevoked = spentTickets.RevokedTickets
Expand Down
26 changes: 20 additions & 6 deletions blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,6 @@ func (b *BlockChain) pruneStakeNodes() {
// for example if you're adding an old side chain block.
if node.height > b.bestChain.Tip().height-minMemoryNodes {
node.stakeNode = nil
node.stakeUndoData = nil
node.newTickets = nil
node.ticketsVoted = nil
node.ticketsRevoked = nil
Expand Down Expand Up @@ -696,7 +695,7 @@ func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List
return detachNodes, attachNodes
}

// Do not allow a reorganize to a known invalid chain. Note that all
// Do not allow a reorganize to a known invalid chain. Note that all
// intermediate ancestors other than the direct parent are also checked
// below, however, this check allows extra to work to be avoided in the
// majority of cases since reorgs across multiple unvalidated blocks are
Expand Down Expand Up @@ -784,7 +783,7 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block,

// Write any modified block index entries to the database before
// updating the best state.
if err := b.index.flush(); err != nil {
if err := b.flushBlockIndex(); err != nil {
return err
}

Expand Down Expand Up @@ -929,7 +928,6 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block,
if node.height < b.chainParams.LatestCheckpointHeight() {
parent := b.bestChain.Tip().parent
parent.stakeNode = nil
parent.stakeUndoData = nil
parent.newTickets = nil
parent.ticketsVoted = nil
parent.ticketsRevoked = nil
Expand Down Expand Up @@ -963,7 +961,7 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block, parent *dcrutil.Blo

// Write any modified block index entries to the database before
// updating the best state.
if err := b.index.flush(); err != nil {
if err := b.flushBlockIndex(); err != nil {
return err
}

Expand Down Expand Up @@ -1559,6 +1557,22 @@ func (b *BlockChain) ForceHeadReorganization(formerBest chainhash.Hash, newBest
return err
}

// flushBlockIndex populates any ticket data that has been pruned from modified
// block nodes, writes those nodes to the database and clears the set of
// modified nodes if it succeeds.
func (b *BlockChain) flushBlockIndex() error {
b.index.RLock()
for node := range b.index.modified {
if err := b.maybeFetchTicketInfo(node); err != nil {
b.index.RUnlock()
return err
}
}
b.index.RUnlock()

return b.index.flush()
}

// flushBlockIndexWarnOnly attempts to flush and modified block index nodes to
// the database and will log a warning if it fails.
//
Expand All @@ -1567,7 +1581,7 @@ func (b *BlockChain) ForceHeadReorganization(formerBest chainhash.Hash, newBest
// to be validated again. All other cases must directly call the function on
// the block index and check the error return accordingly.
func (b *BlockChain) flushBlockIndexWarnOnly() {
if err := b.index.flush(); err != nil {
if err := b.flushBlockIndex(); err != nil {
log.Warnf("Unable to flush block index changes to db: %v", err)
}
}
Expand Down
1 change: 0 additions & 1 deletion blockchain/chainio.go
Original file line number Diff line number Diff line change
Expand Up @@ -1749,7 +1749,6 @@ func (b *BlockChain) initChainState() error {
if err != nil {
return err
}
tip.stakeUndoData = tip.stakeNode.UndoData()
tip.newTickets = tip.stakeNode.NewTickets()
}

Expand Down
4 changes: 2 additions & 2 deletions blockchain/stakeext.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ func (b *BlockChain) NextLotteryData() ([]chainhash.Hash, int, [6]byte, error) {
// with the chainLock held for writes.
func (b *BlockChain) lotteryDataForNode(node *blockNode) ([]chainhash.Hash, int, [6]byte, error) {
if node.height < b.chainParams.StakeEnabledHeight {
return []chainhash.Hash{}, 0, [6]byte{}, nil
return nil, 0, [6]byte{}, nil
}
stakeNode, err := b.fetchStakeNode(node)
if err != nil {
return []chainhash.Hash{}, 0, [6]byte{}, err
return nil, 0, [6]byte{}, err
}

return stakeNode.Winners(), stakeNode.PoolSize(), stakeNode.FinalState(), nil
Expand Down
Loading

0 comments on commit 20631a1

Please sign in to comment.