Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Commit

Permalink
blockchain: Add median time to state snapshot.
Browse files Browse the repository at this point in the history
This adds a new field to the best chain state snapshot for the
calculated past median time as returned by the calcPastMedianTime
function.  This is useful since it provides fast access to it without
having to acquire the chain lock which is needed to recalculate it.

This will ultimately allow the associated exported function to be
removed since it only exists to be able to calculate this exact value,
however this commit only introduces the new field in order to keep the
changes minimal.
  • Loading branch information
davecgh committed Aug 23, 2016
1 parent bfe2ba4 commit c57c18c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 19 deletions.
48 changes: 32 additions & 16 deletions blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,23 +128,25 @@ func removeChildNode(children []*blockNode, node *blockNode) []*blockNode {
// 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 int32 // 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.
Hash *chainhash.Hash // The hash of the block.
Height int32 // 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.
}

// newBestState returns a new best stats instance for the given parameters.
func newBestState(node *blockNode, blockSize, numTxns, totalTxns uint64) *BestState {
func newBestState(node *blockNode, blockSize, numTxns, totalTxns uint64, medianTime time.Time) *BestState {
return &BestState{
Hash: node.hash,
Height: node.height,
Bits: node.bits,
BlockSize: blockSize,
NumTxns: numTxns,
TotalTxns: totalTxns,
Hash: node.hash,
Height: node.height,
Bits: node.bits,
BlockSize: blockSize,
NumTxns: numTxns,
TotalTxns: totalTxns,
MedianTime: medianTime,
}
}

Expand Down Expand Up @@ -779,17 +781,24 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *U
"spent transaction out information")
}

// Calculate the median time for the block.
medianTime, err := b.calcPastMedianTime(node)
if err != nil {
return err
}

// Generate a new best state snapshot that will be used to update the
// database and later memory if all database updates are successful.
b.stateLock.RLock()
curTotalTxns := b.stateSnapshot.TotalTxns
b.stateLock.RUnlock()
numTxns := uint64(len(block.MsgBlock().Transactions))
blockSize := uint64(block.MsgBlock().SerializeSize())
state := newBestState(node, blockSize, numTxns, curTotalTxns+numTxns)
state := newBestState(node, blockSize, numTxns, curTotalTxns+numTxns,
medianTime)

// Atomically insert info into the database.
err := b.db.Update(func(dbTx database.Tx) error {
err = b.db.Update(func(dbTx database.Tx) error {
// Update best block state.
err := dbPutBestState(dbTx, state, node.workSum)
if err != nil {
Expand Down Expand Up @@ -892,6 +901,12 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
return err
}

// Calculate the median time for the previous block.
medianTime, err := b.calcPastMedianTime(prevNode)
if err != nil {
return err
}

// Load the previous block since some details for it are needed below.
var prevBlock *btcutil.Block
err = b.db.View(func(dbTx database.Tx) error {
Expand All @@ -911,7 +926,8 @@ func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view
numTxns := uint64(len(prevBlock.MsgBlock().Transactions))
blockSize := uint64(prevBlock.MsgBlock().SerializeSize())
newTotalTxns := curTotalTxns - uint64(len(block.MsgBlock().Transactions))
state := newBestState(prevNode, blockSize, numTxns, newTotalTxns)
state := newBestState(prevNode, blockSize, numTxns, newTotalTxns,
medianTime)

err = b.db.Update(func(dbTx database.Tx) error {
// Update best block state.
Expand Down
14 changes: 11 additions & 3 deletions blockchain/chainio.go
Original file line number Diff line number Diff line change
Expand Up @@ -1058,10 +1058,12 @@ func (b *BlockChain) createChainState() error {
// Add the new node to the index which is used for faster lookups.
b.index[*node.hash] = node

// Initialize the state related to the best block.
// Initialize the state related to the best block. Since it is the
// genesis block, use its timestamp for the median time.
numTxns := uint64(len(genesisBlock.MsgBlock().Transactions))
blockSize := uint64(genesisBlock.MsgBlock().SerializeSize())
b.stateSnapshot = newBestState(b.bestNode, blockSize, numTxns, numTxns)
b.stateSnapshot = newBestState(b.bestNode, blockSize, numTxns, numTxns,
b.bestNode.timestamp)

// Create the initial the database chain state including creating the
// necessary index buckets and inserting the genesis block.
Expand Down Expand Up @@ -1159,11 +1161,17 @@ func (b *BlockChain) initChainState() error {
b.index[*node.hash] = node
b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node)

// Calculate the median time for the block.
medianTime, err := b.calcPastMedianTime(node)
if err != nil {
return err
}

// Initialize the state related to the best block.
blockSize := uint64(len(blockBytes))
numTxns := uint64(len(block.Transactions))
b.stateSnapshot = newBestState(b.bestNode, blockSize, numTxns,
state.totalTxns)
state.totalTxns, medianTime)

isStateInitialized = true
return nil
Expand Down

0 comments on commit c57c18c

Please sign in to comment.