diff --git a/blockchain/chain.go b/blockchain/chain.go index 4856d24102..ae705781cd 100644 --- a/blockchain/chain.go +++ b/blockchain/chain.go @@ -86,27 +86,52 @@ type orphanBlock struct { // However, the returned snapshot must be treated as immutable since it is // shared by all callers. type BestState struct { - Hash chainhash.Hash // The hash of the block. - Height int64 // The height of the block. - Bits uint32 // The difficulty bits of the block. - BlockSize uint64 // The size of the block. - NumTxns uint64 // The number of txns in the block. - TotalTxns uint64 // The total number of txns in the chain. - MedianTime time.Time // Median time as per CalcPastMedianTime. - TotalSubsidy int64 // The total subsidy for the chain. + Hash chainhash.Hash // The hash of the block. + PrevHash chainhash.Hash // The previous block hash. + Height int64 // The height of the block. + Bits uint32 // The difficulty bits of the block. + PoolSize uint32 // The ticket pool size. + NextStakeDiff int64 // The next stake difficulty. + BlockSize uint64 // The size of the block. + NumTxns uint64 // The number of txns in the block. + TotalTxns uint64 // The total number of txns in the chain. + MedianTime time.Time // Median time as per CalcPastMedianTime. + TotalSubsidy int64 // The total subsidy for the chain. + WinningTickets []chainhash.Hash // The eligigle tickets to vote on the next block. + MissedTickets []chainhash.Hash // The missed tickets set to be revoked. + FinalState [6]byte // The calculated state of the lottery. } // newBestState returns a new best stats instance for the given parameters. -func newBestState(node *blockNode, blockSize, numTxns, totalTxns uint64, medianTime time.Time, totalSubsidy int64) *BestState { +func newBestState(node *blockNode, blockSize, numTxns, totalTxns uint64, medianTime time.Time, totalSubsidy int64, nextStakeDiff int64) *BestState { + prevHash := *zeroHash + if node.parent != nil { + prevHash = node.parent.hash + } + + winners := make([]chainhash.Hash, 0) + if node.stakeNode != nil { + winners = node.stakeNode.Winners() + } + + missed := make([]chainhash.Hash, 0) + if node.parent != nil { + missed = node.stakeNode.MissedTickets() + } return &BestState{ - Hash: node.hash, - Height: node.height, - Bits: node.bits, - BlockSize: blockSize, - NumTxns: numTxns, - TotalTxns: totalTxns, - MedianTime: medianTime, - TotalSubsidy: totalSubsidy, + Hash: node.hash, + PrevHash: prevHash, + Height: node.height, + Bits: node.bits, + PoolSize: node.poolSize, + NextStakeDiff: nextStakeDiff, + BlockSize: blockSize, + NumTxns: numTxns, + TotalTxns: totalTxns, + MedianTime: medianTime, + TotalSubsidy: totalSubsidy, + WinningTickets: winners, + MissedTickets: missed, } } @@ -761,9 +786,11 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block, // Calculate the exact subsidy produced by adding the block. subsidy := CalculateAddedSubsidy(block, parent) - blockSize := uint64(block.MsgBlock().Header.Size) - state := newBestState(node, blockSize, numTxns, curTotalTxns+numTxns, - node.CalcPastMedianTime(), curTotalSubsidy+subsidy) + // Calcultate the next stake difficulty. + nextStakeDiff, err := b.calcNextRequiredStakeDifficulty(node) + if err != nil { + return err + } // Get the stake node for this node, filling in any data that // may have yet to have been filled in. In all cases this @@ -774,6 +801,10 @@ func (b *BlockChain) connectBlock(node *blockNode, block, parent *dcrutil.Block, return err } + blockSize := uint64(block.MsgBlock().Header.Size) + state := newBestState(node, blockSize, numTxns, curTotalTxns+numTxns, + node.CalcPastMedianTime(), curTotalSubsidy+subsidy, nextStakeDiff) + // Atomically insert info into the database. err = b.db.Update(func(dbTx database.Tx) error { // Update best block state. @@ -934,10 +965,6 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block, parent *dcrutil.Blo subsidy := CalculateAddedSubsidy(block, parent) newTotalSubsidy := curTotalSubsidy - subsidy - prevNode := node.parent - state := newBestState(prevNode, parentBlockSize, numTxns, newTotalTxns, - prevNode.CalcPastMedianTime(), newTotalSubsidy) - // Prepare the information required to update the stake database // contents. childStakeNode, err := b.fetchStakeNode(node) @@ -949,6 +976,10 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block, parent *dcrutil.Blo return err } + prevNode := node.parent + state := newBestState(prevNode, parentBlockSize, numTxns, newTotalTxns, + prevNode.CalcPastMedianTime(), newTotalSubsidy, node.sbits) + err = b.db.Update(func(dbTx database.Tx) error { // Update best block state. err := dbPutBestState(dbTx, state, node.workSum) diff --git a/blockchain/chainio.go b/blockchain/chainio.go index dbfa61a62c..24c6073087 100644 --- a/blockchain/chainio.go +++ b/blockchain/chainio.go @@ -1463,8 +1463,9 @@ func (b *BlockChain) createChainState() error { // genesis block, use its timestamp for the median time. numTxns := uint64(len(genesisBlock.MsgBlock().Transactions)) blockSize := uint64(genesisBlock.MsgBlock().SerializeSize()) + stateSnapshot := newBestState(node, blockSize, numTxns, numTxns, - time.Unix(node.timestamp, 0), 0) + time.Unix(node.timestamp, 0), 0, b.chainParams.MinimumStakeDiff) // Create the initial the database chain state including creating the // necessary index buckets and inserting the genesis block. @@ -1770,9 +1771,16 @@ func (b *BlockChain) initChainState(interrupt <-chan struct{}) error { block := utilBlock.MsgBlock() blockSize := uint64(block.SerializeSize()) numTxns := uint64(len(block.Transactions)) + + // Calculate the next stake difficulty. + nextStakeDiff, err := b.calcNextRequiredStakeDifficulty(tip) + if err != nil { + return err + } + b.stateSnapshot = newBestState(tip, blockSize, numTxns, state.totalTxns, tip.CalcPastMedianTime(), - state.totalSubsidy) + state.totalSubsidy, nextStakeDiff) return nil })