lbcd/blockchain/chain.go
Dave Collins 6a54323258
blockchain: Store side chain blocks in database.
This modifies the blockchain code to store all blocks that have passed
proof-of-work and contextual validity tests in the database even if they
may ultimately fail to connect.

This eliminates the need to store those blocks in memory, allows them to
be available as orphans later even if they were never part of the main
chain, and helps pave the way toward being able to separate the download
logic from the connection logic.
2017-01-31 10:25:43 -06:00

1772 lines
63 KiB
Go

// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"container/list"
"fmt"
"math/big"
"sort"
"sync"
"time"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
const (
// maxOrphanBlocks is the maximum number of orphan blocks that can be
// queued.
maxOrphanBlocks = 100
)
// blockNode represents a block within the block chain and is primarily used to
// aid in selecting the best chain to be the main chain. The main chain is
// stored into the block database.
type blockNode struct {
// parent is the parent block for this node.
parent *blockNode
// children contains the child nodes for this node. Typically there
// will only be one, but sometimes there can be more than one and that
// is when the best chain selection algorithm is used.
children []*blockNode
// hash is the double sha 256 of the block.
hash *chainhash.Hash
// parentHash is the double sha 256 of the parent block. This is kept
// here over simply relying on parent.hash directly since block nodes
// are sparse and the parent node might not be in memory when its hash
// is needed.
parentHash *chainhash.Hash
// height is the position in the block chain.
height int32
// workSum is the total amount of work in the chain up to and including
// this node.
workSum *big.Int
// inMainChain denotes whether the block node is currently on the
// the main chain or not. This is used to help find the common
// ancestor when switching chains.
inMainChain bool
// Some fields from block headers to aid in best chain selection.
version int32
bits uint32
timestamp time.Time
}
// newBlockNode returns a new block node for the given block header. It is
// completely disconnected from the chain and the workSum value is just the work
// for the passed block. The work sum is updated accordingly when the node is
// inserted into a chain.
func newBlockNode(blockHeader *wire.BlockHeader, blockHash *chainhash.Hash, height int32) *blockNode {
// Make a copy of the hash so the node doesn't keep a reference to part
// of the full block/block header preventing it from being garbage
// collected.
prevHash := blockHeader.PrevBlock
node := blockNode{
hash: blockHash,
parentHash: &prevHash,
workSum: CalcWork(blockHeader.Bits),
height: height,
version: blockHeader.Version,
bits: blockHeader.Bits,
timestamp: blockHeader.Timestamp,
}
return &node
}
// orphanBlock represents a block that we don't yet have the parent for. It
// is a normal block plus an expiration time to prevent caching the orphan
// forever.
type orphanBlock struct {
block *btcutil.Block
expiration time.Time
}
// removeChildNode deletes node from the provided slice of child block
// nodes. It ensures the final pointer reference is set to nil to prevent
// potential memory leaks. The original slice is returned unmodified if node
// is invalid or not in the slice.
//
// This function MUST be called with the chain state lock held (for writes).
func removeChildNode(children []*blockNode, node *blockNode) []*blockNode {
if node == nil {
return children
}
// An indexing for loop is intentionally used over a range here as range
// does not reevaluate the slice on each iteration nor does it adjust
// the index for the modified slice.
for i := 0; i < len(children); i++ {
if children[i].hash.IsEqual(node.hash) {
copy(children[i:], children[i+1:])
children[len(children)-1] = nil
return children[:len(children)-1]
}
}
return children
}
// BestState houses information about the current best block and other info
// related to the state of the main chain as it exists from the point of view of
// the current best block.
//
// The BestSnapshot method can be used to obtain access to this information
// in a concurrent safe manner and the data will not be changed out from under
// the caller when chain state changes occur as the function name implies.
// 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.
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, medianTime time.Time) *BestState {
return &BestState{
Hash: node.hash,
Height: node.height,
Bits: node.bits,
BlockSize: blockSize,
NumTxns: numTxns,
TotalTxns: totalTxns,
MedianTime: medianTime,
}
}
// BlockChain provides functions for working with the bitcoin block chain.
// It includes functionality such as rejecting duplicate blocks, ensuring blocks
// follow all rules, orphan handling, checkpoint handling, and best chain
// selection with reorganization.
type BlockChain struct {
// The following fields are set when the instance is created and can't
// be changed afterwards, so there is no need to protect them with a
// separate mutex.
checkpoints []chaincfg.Checkpoint
checkpointsByHeight map[int32]*chaincfg.Checkpoint
db database.DB
chainParams *chaincfg.Params
timeSource MedianTimeSource
notifications NotificationCallback
sigCache *txscript.SigCache
indexManager IndexManager
// The following fields are calculated based upon the provided chain
// parameters. They are also set when the instance is created and
// can't be changed afterwards, so there is no need to protect them with
// a separate mutex.
//
// minMemoryNodes is the minimum number of consecutive nodes needed
// in memory in order to perform all necessary validation. It is used
// to determine when it's safe to prune nodes from memory without
// causing constant dynamic reloading. This is typically the same value
// as blocksPerRetarget, but it is separated here for tweakability and
// testability.
minRetargetTimespan int64 // target timespan / adjustment factor
maxRetargetTimespan int64 // target timespan * adjustment factor
blocksPerRetarget int32 // target timespan / target time per block
minMemoryNodes int32
// chainLock protects concurrent access to the vast majority of the
// fields in this struct below this point.
chainLock sync.RWMutex
// These fields are configuration parameters that can be toggled at
// runtime. They are protected by the chain lock.
noVerify bool
// These fields are related to the memory block index. They are
// protected by the chain lock.
bestNode *blockNode
index map[chainhash.Hash]*blockNode
depNodes map[chainhash.Hash][]*blockNode
// These fields are related to handling of orphan blocks. They are
// protected by a combination of the chain lock and the orphan lock.
orphanLock sync.RWMutex
orphans map[chainhash.Hash]*orphanBlock
prevOrphans map[chainhash.Hash][]*orphanBlock
oldestOrphan *orphanBlock
// These fields are related to checkpoint handling. They are protected
// by the chain lock.
nextCheckpoint *chaincfg.Checkpoint
checkpointBlock *btcutil.Block
// The state is used as a fairly efficient way to cache information
// about the current best chain state that is returned to callers when
// requested. It operates on the principle of MVCC such that any time a
// new block becomes the best block, the state pointer is replaced with
// a new struct and the old state is left untouched. In this way,
// multiple callers can be pointing to different best chain states.
// This is acceptable for most callers because the state is only being
// queried at a specific point in time.
//
// In addition, some of the fields are stored in the database so the
// chain state can be quickly reconstructed on load.
stateLock sync.RWMutex
stateSnapshot *BestState
// The following caches are used to efficiently keep track of the
// current deployment threshold state of each rule change deployment.
//
// This information is stored in the database so it can be quickly
// reconstructed on load.
//
// warningCaches caches the current deployment threshold state for blocks
// in each of the **possible** deployments. This is used in order to
// detect when new unrecognized rule changes are being voted on and/or
// have been activated such as will be the case when older versions of
// the software are being used
//
// deploymentCaches caches the current deployment threshold state for
// blocks in each of the actively defined deployments.
warningCaches []thresholdStateCache
deploymentCaches []thresholdStateCache
// The following fields are used to determine if certain warnings have
// already been shown.
//
// unknownRulesWarned refers to warnings due to unknown rules being
// activated.
//
// unknownVersionsWarned refers to warnings due to unknown versions
// being mined.
unknownRulesWarned bool
unknownVersionsWarned bool
}
// DisableVerify provides a mechanism to disable transaction script validation
// which you DO NOT want to do in production as it could allow double spends
// and other undesirable things. It is provided only for debug purposes since
// script validation is extremely intensive and when debugging it is sometimes
// nice to quickly get the chain.
//
// This function is safe for concurrent access.
func (b *BlockChain) DisableVerify(disable bool) {
b.chainLock.Lock()
b.noVerify = disable
b.chainLock.Unlock()
}
// HaveBlock returns whether or not the chain instance has the block represented
// by the passed hash. This includes checking the various places a block can
// be like part of the main chain, on a side chain, or in the orphan pool.
//
// This function is safe for concurrent access.
func (b *BlockChain) HaveBlock(hash *chainhash.Hash) (bool, error) {
b.chainLock.RLock()
exists, err := b.blockExists(hash)
b.chainLock.RUnlock()
if err != nil {
return false, err
}
return exists || b.IsKnownOrphan(hash), nil
}
// IsKnownOrphan returns whether the passed hash is currently a known orphan.
// Keep in mind that only a limited number of orphans are held onto for a
// limited amount of time, so this function must not be used as an absolute
// way to test if a block is an orphan block. A full block (as opposed to just
// its hash) must be passed to ProcessBlock for that purpose. However, calling
// ProcessBlock with an orphan that already exists results in an error, so this
// function provides a mechanism for a caller to intelligently detect *recent*
// duplicate orphans and react accordingly.
//
// This function is safe for concurrent access.
func (b *BlockChain) IsKnownOrphan(hash *chainhash.Hash) bool {
// Protect concurrent access. Using a read lock only so multiple
// readers can query without blocking each other.
b.orphanLock.RLock()
_, exists := b.orphans[*hash]
b.orphanLock.RUnlock()
return exists
}
// GetOrphanRoot returns the head of the chain for the provided hash from the
// map of orphan blocks.
//
// This function is safe for concurrent access.
func (b *BlockChain) GetOrphanRoot(hash *chainhash.Hash) *chainhash.Hash {
// Protect concurrent access. Using a read lock only so multiple
// readers can query without blocking each other.
b.orphanLock.RLock()
defer b.orphanLock.RUnlock()
// Keep looping while the parent of each orphaned block is
// known and is an orphan itself.
orphanRoot := hash
prevHash := hash
for {
orphan, exists := b.orphans[*prevHash]
if !exists {
break
}
orphanRoot = prevHash
prevHash = &orphan.block.MsgBlock().Header.PrevBlock
}
return orphanRoot
}
// removeOrphanBlock removes the passed orphan block from the orphan pool and
// previous orphan index.
func (b *BlockChain) removeOrphanBlock(orphan *orphanBlock) {
// Protect concurrent access.
b.orphanLock.Lock()
defer b.orphanLock.Unlock()
// Remove the orphan block from the orphan pool.
orphanHash := orphan.block.Hash()
delete(b.orphans, *orphanHash)
// Remove the reference from the previous orphan index too. An indexing
// for loop is intentionally used over a range here as range does not
// reevaluate the slice on each iteration nor does it adjust the index
// for the modified slice.
prevHash := &orphan.block.MsgBlock().Header.PrevBlock
orphans := b.prevOrphans[*prevHash]
for i := 0; i < len(orphans); i++ {
hash := orphans[i].block.Hash()
if hash.IsEqual(orphanHash) {
copy(orphans[i:], orphans[i+1:])
orphans[len(orphans)-1] = nil
orphans = orphans[:len(orphans)-1]
i--
}
}
b.prevOrphans[*prevHash] = orphans
// Remove the map entry altogether if there are no longer any orphans
// which depend on the parent hash.
if len(b.prevOrphans[*prevHash]) == 0 {
delete(b.prevOrphans, *prevHash)
}
}
// addOrphanBlock adds the passed block (which is already determined to be
// an orphan prior calling this function) to the orphan pool. It lazily cleans
// up any expired blocks so a separate cleanup poller doesn't need to be run.
// It also imposes a maximum limit on the number of outstanding orphan
// blocks and will remove the oldest received orphan block if the limit is
// exceeded.
func (b *BlockChain) addOrphanBlock(block *btcutil.Block) {
// Remove expired orphan blocks.
for _, oBlock := range b.orphans {
if time.Now().After(oBlock.expiration) {
b.removeOrphanBlock(oBlock)
continue
}
// Update the oldest orphan block pointer so it can be discarded
// in case the orphan pool fills up.
if b.oldestOrphan == nil || oBlock.expiration.Before(b.oldestOrphan.expiration) {
b.oldestOrphan = oBlock
}
}
// Limit orphan blocks to prevent memory exhaustion.
if len(b.orphans)+1 > maxOrphanBlocks {
// Remove the oldest orphan to make room for the new one.
b.removeOrphanBlock(b.oldestOrphan)
b.oldestOrphan = nil
}
// Protect concurrent access. This is intentionally done here instead
// of near the top since removeOrphanBlock does its own locking and
// the range iterator is not invalidated by removing map entries.
b.orphanLock.Lock()
defer b.orphanLock.Unlock()
// Insert the block into the orphan map with an expiration time
// 1 hour from now.
expiration := time.Now().Add(time.Hour)
oBlock := &orphanBlock{
block: block,
expiration: expiration,
}
b.orphans[*block.Hash()] = oBlock
// Add to previous hash lookup index for faster dependency lookups.
prevHash := &block.MsgBlock().Header.PrevBlock
b.prevOrphans[*prevHash] = append(b.prevOrphans[*prevHash], oBlock)
return
}
// loadBlockNode loads the block identified by hash from the block database,
// creates a block node from it, and updates the memory block chain accordingly.
// It is used mainly to dynamically load previous blocks from the database as
// they are needed to avoid needing to put the entire block chain in memory.
//
// This function MUST be called with the chain state lock held (for writes).
// The database transaction may be read-only.
func (b *BlockChain) loadBlockNode(dbTx database.Tx, hash *chainhash.Hash) (*blockNode, error) {
// Load the block header and height from the db.
blockHeader, err := dbFetchHeaderByHash(dbTx, hash)
if err != nil {
return nil, err
}
blockHeight, err := dbFetchHeightByHash(dbTx, hash)
if err != nil {
return nil, err
}
// Create the new block node for the block and set the work.
node := newBlockNode(blockHeader, hash, blockHeight)
node.inMainChain = true
// Add the node to the chain.
// There are a few possibilities here:
// 1) This node is a child of an existing block node
// 2) This node is the parent of one or more nodes
// 3) Neither 1 or 2 is true which implies it's an orphan block and
// therefore is an error to insert into the chain
prevHash := &blockHeader.PrevBlock
if parentNode, ok := b.index[*prevHash]; ok {
// Case 1 -- This node is a child of an existing block node.
// Update the node's work sum with the sum of the parent node's
// work sum and this node's work, append the node as a child of
// the parent node and set this node's parent to the parent
// node.
node.workSum = node.workSum.Add(parentNode.workSum, node.workSum)
parentNode.children = append(parentNode.children, node)
node.parent = parentNode
} else if childNodes, ok := b.depNodes[*hash]; ok {
// Case 2 -- This node is the parent of one or more nodes.
// Update the node's work sum by subtracting this node's work
// from the sum of its first child, and connect the node to all
// of its children.
node.workSum.Sub(childNodes[0].workSum, node.workSum)
for _, childNode := range childNodes {
childNode.parent = node
node.children = append(node.children, childNode)
}
} else {
// Case 3 -- The node doesn't have a parent and is not the
// parent of another node. This means an arbitrary orphan block
// is trying to be loaded which is not allowed.
str := "loadBlockNode: attempt to insert orphan block %v"
return nil, AssertError(fmt.Sprintf(str, hash))
}
// Add the new node to the indices for faster lookups.
b.index[*hash] = node
b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node)
return node, nil
}
// getPrevNodeFromBlock returns a block node for the block previous to the
// passed block (the passed block's parent). When it is already in the memory
// block chain, it simply returns it. Otherwise, it loads the previous block
// header from the block database, creates a new block node from it, and returns
// it. The returned node will be nil if the genesis block is passed.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) getPrevNodeFromBlock(block *btcutil.Block) (*blockNode, error) {
// Genesis block.
prevHash := &block.MsgBlock().Header.PrevBlock
if prevHash.IsEqual(zeroHash) {
return nil, nil
}
// Return the existing previous block node if it's already there.
if bn, ok := b.index[*prevHash]; ok {
return bn, nil
}
// Dynamically load the previous block from the block database, create
// a new block node for it, and update the memory chain accordingly.
var prevBlockNode *blockNode
err := b.db.View(func(dbTx database.Tx) error {
var err error
prevBlockNode, err = b.loadBlockNode(dbTx, prevHash)
return err
})
return prevBlockNode, err
}
// getPrevNodeFromNode returns a block node for the block previous to the
// passed block node (the passed block node's parent). When the node is already
// connected to a parent, it simply returns it. Otherwise, it loads the
// associated block from the database to obtain the previous hash and uses that
// to dynamically create a new block node and return it. The memory block
// chain is updated accordingly. The returned node will be nil if the genesis
// block is passed.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) getPrevNodeFromNode(node *blockNode) (*blockNode, error) {
// Return the existing previous block node if it's already there.
if node.parent != nil {
return node.parent, nil
}
// Genesis block.
if node.hash.IsEqual(b.chainParams.GenesisHash) {
return nil, nil
}
// Dynamically load the previous block from the block database, create
// a new block node for it, and update the memory chain accordingly.
var prevBlockNode *blockNode
err := b.db.View(func(dbTx database.Tx) error {
var err error
prevBlockNode, err = b.loadBlockNode(dbTx, node.parentHash)
return err
})
return prevBlockNode, err
}
// relativeNode returns the ancestor block a relative 'distance' blocks before
// the passed anchor block. While iterating backwards through the chain, any
// block nodes which aren't in the memory chain are loaded in dynamically.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) relativeNode(anchor *blockNode, distance uint32) (*blockNode, error) {
var err error
iterNode := anchor
err = b.db.View(func(dbTx database.Tx) error {
// Walk backwards in the chian until we've gone 'distance'
// steps back.
for i := distance; i > 0; i-- {
switch {
// If the parent of this node has already been loaded
// into memory, then we can follow the link without
// hitting the database.
case iterNode.parent != nil:
iterNode = iterNode.parent
// If this node is the genesis block, then we can't go
// back any further, so we exit immediately.
case iterNode.hash.IsEqual(b.chainParams.GenesisHash):
return nil
// Otherwise, load the block node from the database,
// pulling it into the memory cache in the processes.
default:
iterNode, err = b.loadBlockNode(dbTx,
iterNode.parentHash)
if err != nil {
return err
}
}
}
return nil
})
if err != nil {
return nil, err
}
return iterNode, nil
}
// ancestorNode returns the ancestor block node at the provided height by
// following the chain backwards from the given node while dynamically loading
// any pruned nodes from the database and updating the memory block chain as
// needed. The returned block will be nil when a height is requested that is
// after the height of the passed node or is less than zero.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) ancestorNode(node *blockNode, height int32) (*blockNode, error) {
// Nothing to do if the requested height is outside of the valid range.
if height > node.height || height < 0 {
return nil, nil
}
// Iterate backwards until the requested height is reached.
iterNode := node
for iterNode != nil && iterNode.height > height {
// Get the previous block node. This function is used over
// simply accessing iterNode.parent directly as it will
// dynamically create previous block nodes as needed. This
// helps allow only the pieces of the chain that are needed
// to remain in memory.
var err error
iterNode, err = b.getPrevNodeFromNode(iterNode)
if err != nil {
log.Errorf("getPrevNodeFromNode: %v", err)
return nil, err
}
}
return iterNode, nil
}
// removeBlockNode removes the passed block node from the memory chain by
// unlinking all of its children and removing it from the the node and
// dependency indices.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) removeBlockNode(node *blockNode) error {
if node.parent != nil {
return AssertError(fmt.Sprintf("removeBlockNode must be "+
"called with a node at the front of the chain - node %v",
node.hash))
}
// Remove the node from the node index.
delete(b.index, *node.hash)
// Unlink all of the node's children.
for _, child := range node.children {
child.parent = nil
}
node.children = nil
// Remove the reference from the dependency index.
prevHash := node.parentHash
if children, ok := b.depNodes[*prevHash]; ok {
// Find the node amongst the children of the
// dependencies for the parent hash and remove it.
b.depNodes[*prevHash] = removeChildNode(children, node)
// Remove the map entry altogether if there are no
// longer any nodes which depend on the parent hash.
if len(b.depNodes[*prevHash]) == 0 {
delete(b.depNodes, *prevHash)
}
}
return nil
}
// calcPastMedianTime calculates the median time of the previous few blocks
// prior to, and including, the passed block node. It is primarily used to
// validate new blocks have sane timestamps.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcPastMedianTime(startNode *blockNode) (time.Time, error) {
// Genesis block.
if startNode == nil {
return b.chainParams.GenesisBlock.Header.Timestamp, nil
}
// Create a slice of the previous few block timestamps used to calculate
// the median per the number defined by the constant medianTimeBlocks.
timestamps := make([]time.Time, medianTimeBlocks)
numNodes := 0
iterNode := startNode
for i := 0; i < medianTimeBlocks && iterNode != nil; i++ {
timestamps[i] = iterNode.timestamp
numNodes++
// Get the previous block node. This function is used over
// simply accessing iterNode.parent directly as it will
// dynamically create previous block nodes as needed. This
// helps allow only the pieces of the chain that are needed
// to remain in memory.
var err error
iterNode, err = b.getPrevNodeFromNode(iterNode)
if err != nil {
log.Errorf("getPrevNodeFromNode: %v", err)
return time.Time{}, err
}
}
// Prune the slice to the actual number of available timestamps which
// will be fewer than desired near the beginning of the block chain
// and sort them.
timestamps = timestamps[:numNodes]
sort.Sort(timeSorter(timestamps))
// NOTE: bitcoind incorrectly calculates the median for even numbers of
// blocks. A true median averages the middle two elements for a set
// with an even number of elements in it. Since the constant for the
// previous number of blocks to be used is odd, this is only an issue
// for a few blocks near the beginning of the chain. I suspect this is
// an optimization even though the result is slightly wrong for a few
// of the first blocks since after the first few blocks, there will
// always be an odd number of blocks in the set per the constant.
//
// This code follows suit to ensure the same rules are used as bitcoind
// however, be aware that should the medianTimeBlocks constant ever be
// changed to an even number, this code will be wrong.
medianTimestamp := timestamps[numNodes/2]
return medianTimestamp, nil
}
// CalcPastMedianTime calculates the median time of the previous few blocks
// prior to, and including, the end of the current best chain. It is primarily
// used to ensure new blocks have sane timestamps.
//
// This function is safe for concurrent access.
func (b *BlockChain) CalcPastMedianTime() (time.Time, error) {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.calcPastMedianTime(b.bestNode)
}
// SequenceLock represents the converted relative lock-time in seconds, and
// absolute block-height for a transaction input's relative lock-times.
// According to SequenceLock, after the referenced input has been confirmed
// within a block, a transaction spending that input can be included into a
// block either after 'seconds' (according to past median time), or once the
// 'BlockHeight' has been reached.
type SequenceLock struct {
Seconds int64
BlockHeight int32
}
// CalcSequenceLock computes a relative lock-time SequenceLock for the passed
// transaction using the passed UtxoViewpoint to obtain the past median time
// for blocks in which the referenced inputs of the transactions were included
// within. The generated SequenceLock lock can be used in conjunction with a
// block height, and adjusted median block time to determine if all the inputs
// referenced within a transaction have reached sufficient maturity allowing
// the candidate transaction to be included in a block.
//
// This function is safe for concurrent access.
func (b *BlockChain) CalcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint,
mempool bool) (*SequenceLock, error) {
b.chainLock.Lock()
defer b.chainLock.Unlock()
return b.calcSequenceLock(tx, utxoView, mempool)
}
// calcSequenceLock computes the relative lock-times for the passed
// transaction. See the exported version, CalcSequenceLock for further details.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) calcSequenceLock(tx *btcutil.Tx, utxoView *UtxoViewpoint,
mempool bool) (*SequenceLock, error) {
mTx := tx.MsgTx()
// A value of -1 for each relative lock type represents a relative time
// lock value that will allow a transaction to be included in a block
// at any given height or time. This value is returned as the relative
// lock time in the case that BIP 68 is disabled, or has not yet been
// activated.
sequenceLock := &SequenceLock{Seconds: -1, BlockHeight: -1}
// If the transaction's version is less than 2, and BIP 68 has not yet
// been activated then sequence locks are disabled. Additionally,
// sequence locks don't apply to coinbase transactions Therefore, we
// return sequence lock values of -1 indicating that this transaction
// can be included within a block at any given height or time.
// TODO(roasbeef): check version bits state or pass as param
// * true should be replaced with a version bits state check
sequenceLockActive := mTx.Version >= 2 && (mempool || true)
if !sequenceLockActive || IsCoinBase(tx) {
return sequenceLock, nil
}
// Grab the next height to use for inputs present in the mempool.
nextHeight := b.BestSnapshot().Height + 1
for txInIndex, txIn := range mTx.TxIn {
utxo := utxoView.LookupEntry(&txIn.PreviousOutPoint.Hash)
if utxo == nil {
str := fmt.Sprintf("unable to find unspent output "+
"%v referenced from transaction %s:%d",
txIn.PreviousOutPoint, tx.Hash(), txInIndex)
return sequenceLock, ruleError(ErrMissingTx, str)
}
// If the input height is set to the mempool height, then we
// assume the transaction makes it into the next block when
// evaluating its sequence blocks.
inputHeight := utxo.BlockHeight()
if inputHeight == 0x7fffffff {
inputHeight = nextHeight
}
// Given a sequence number, we apply the relative time lock
// mask in order to obtain the time lock delta required before
// this input can be spent.
sequenceNum := txIn.Sequence
relativeLock := int64(sequenceNum & wire.SequenceLockTimeMask)
switch {
// Relative time locks are disabled for this input, so we can
// skip any further calculation.
case sequenceNum&wire.SequenceLockTimeDisabled == wire.SequenceLockTimeDisabled:
continue
case sequenceNum&wire.SequenceLockTimeIsSeconds == wire.SequenceLockTimeIsSeconds:
// This input requires a relative time lock expressed
// in seconds before it can be spent. Therefore, we
// need to query for the block prior to the one in
// which this input was included within so we can
// compute the past median time for the block prior to
// the one which included this referenced output.
// TODO: caching should be added to keep this speedy
inputDepth := uint32(b.bestNode.height-inputHeight) + 1
blockNode, err := b.relativeNode(b.bestNode, inputDepth)
if err != nil {
return sequenceLock, err
}
// With all the necessary block headers loaded into
// memory, we can now finally calculate the MTP of the
// block prior to the one which included the output
// being spent.
medianTime, err := b.calcPastMedianTime(blockNode)
if err != nil {
return sequenceLock, err
}
// Time based relative time-locks as defined by BIP 68
// have a time granularity of RelativeLockSeconds, so
// we shift left by this amount to convert to the
// proper relative time-lock. We also subtract one from
// the relative lock to maintain the original lockTime
// semantics.
timeLockSeconds := (relativeLock << wire.SequenceLockTimeGranularity) - 1
timeLock := medianTime.Unix() + timeLockSeconds
if timeLock > sequenceLock.Seconds {
sequenceLock.Seconds = timeLock
}
default:
// The relative lock-time for this input is expressed
// in blocks so we calculate the relative offset from
// the input's height as its converted absolute
// lock-time. We subtract one from the relative lock in
// order to maintain the original lockTime semantics.
blockHeight := inputHeight + int32(relativeLock-1)
if blockHeight > sequenceLock.BlockHeight {
sequenceLock.BlockHeight = blockHeight
}
}
}
return sequenceLock, nil
}
// LockTimeToSequence converts the passed relative locktime to a sequence
// number in accordance to BIP-68.
// See: https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
// * (Compatibility)
func LockTimeToSequence(isSeconds bool, locktime uint32) uint32 {
// If we're expressing the relative lock time in blocks, then the
// corresponding sequence number is simply the desired input age.
if !isSeconds {
return locktime
}
// Set the 22nd bit which indicates the lock time is in seconds, then
// shift the locktime over by 9 since the time granularity is in
// 512-second intervals (2^9). This results in a max lock-time of
// 33,553,920 seconds, or 1.1 years.
return wire.SequenceLockTimeIsSeconds |
locktime>>wire.SequenceLockTimeGranularity
}
// getReorganizeNodes finds the fork point between the main chain and the passed
// node and returns a list of block nodes that would need to be detached from
// the main chain and a list of block nodes that would need to be attached to
// the fork point (which will be the end of the main chain after detaching the
// returned list of block nodes) in order to reorganize the chain such that the
// passed node is the new end of the main chain. The lists will be empty if the
// passed node is not on a side chain.
//
// This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) {
// Nothing to detach or attach if there is no node.
attachNodes := list.New()
detachNodes := list.New()
if node == nil {
return detachNodes, attachNodes
}
// Find the fork point (if any) adding each block to the list of nodes
// to attach to the main tree. Push them onto the list in reverse order
// so they are attached in the appropriate order when iterating the list
// later.
ancestor := node
for ; ancestor.parent != nil; ancestor = ancestor.parent {
if ancestor.inMainChain {
break
}
attachNodes.PushFront(ancestor)
}
// TODO(davec): Use prevNodeFromNode function in case the requested
// node is further back than the what is in memory. This shouldn't
// happen in the normal course of operation, but the ability to fetch
// input transactions of arbitrary blocks will likely to be exposed at
// some point and that could lead to an issue here.
// Start from the end of the main chain and work backwards until the
// common ancestor adding each block to the list of nodes to detach from
// the main chain.
for n := b.bestNode; n != nil && n.parent != nil; n = n.parent {
if n.hash.IsEqual(ancestor.hash) {
break
}
detachNodes.PushBack(n)
}
return detachNodes, attachNodes
}
// dbMaybeStoreBlock stores the provided block in the database if it's not
// already there.
func dbMaybeStoreBlock(dbTx database.Tx, block *btcutil.Block) error {
hasBlock, err := dbTx.HasBlock(block.Hash())
if err != nil {
return err
}
if hasBlock {
return nil
}
return dbTx.StoreBlock(block)
}
// connectBlock handles connecting the passed node/block to the end of the main
// (best) chain.
//
// This passed utxo view must have all referenced txos the block spends marked
// as spent and all of the new txos the block creates added to it. In addition,
// the passed stxos slice must be populated with all of the information for the
// spent txos. This approach is used because the connection validation that
// must happen prior to calling this function requires the same details, so
// it would be inefficient to repeat it.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos []spentTxOut) error {
// Make sure it's extending the end of the best chain.
prevHash := &block.MsgBlock().Header.PrevBlock
if !prevHash.IsEqual(b.bestNode.hash) {
return AssertError("connectBlock must be called with a block " +
"that extends the main chain")
}
// Sanity check the correct number of stxos are provided.
if len(stxos) != countSpentOutputs(block) {
return AssertError("connectBlock called with inconsistent " +
"spent transaction out information")
}
// No warnings about unknown rules or versions until the chain is
// current.
if b.isCurrent() {
// Warn if any unknown new rules are either about to activate or
// have already been activated.
if err := b.warnUnknownRuleActivations(node); err != nil {
return err
}
// Warn if a high enough percentage of the last blocks have
// unexpected versions.
if err := b.warnUnknownVersions(node); err != nil {
return err
}
}
// 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,
medianTime)
// Atomically insert info into the database.
err = b.db.Update(func(dbTx database.Tx) error {
// Update best block state.
err := dbPutBestState(dbTx, state, node.workSum)
if err != nil {
return err
}
// Add the block hash and height to the block index which tracks
// the main chain.
err = dbPutBlockIndex(dbTx, block.Hash(), node.height)
if err != nil {
return err
}
// Update the utxo set using the state of the utxo view. This
// entails removing all of the utxos spent and adding the new
// ones created by the block.
err = dbPutUtxoView(dbTx, view)
if err != nil {
return err
}
// Update the transaction spend journal by adding a record for
// the block that contains all txos spent by it.
err = dbPutSpendJournalEntry(dbTx, block.Hash(), stxos)
if err != nil {
return err
}
// Allow the index manager to call each of the currently active
// optional indexes with the block being connected so they can
// update themselves accordingly.
if b.indexManager != nil {
err := b.indexManager.ConnectBlock(dbTx, block, view)
if err != nil {
return err
}
}
// Update the cached threshold states in the database as needed.
return b.putThresholdCaches(dbTx)
})
if err != nil {
return err
}
// Mark all modified entries in the threshold caches as flushed now that
// they have been committed to the database.
b.markThresholdCachesFlushed()
// Prune fully spent entries and mark all entries in the view unmodified
// now that the modifications have been committed to the database.
view.commit()
// Add the new node to the memory main chain indices for faster
// lookups.
node.inMainChain = true
b.index[*node.hash] = node
b.depNodes[*prevHash] = append(b.depNodes[*prevHash], node)
// This node is now the end of the best chain.
b.bestNode = node
// Update the state for the best block. Notice how this replaces the
// entire struct instead of updating the existing one. This effectively
// allows the old version to act as a snapshot which callers can use
// freely without needing to hold a lock for the duration. See the
// comments on the state variable for more details.
b.stateLock.Lock()
b.stateSnapshot = state
b.stateLock.Unlock()
// Notify the caller that the block was connected to the main chain.
// The caller would typically want to react with actions such as
// updating wallets.
b.chainLock.Unlock()
b.sendNotification(NTBlockConnected, block)
b.chainLock.Lock()
return nil
}
// disconnectBlock handles disconnecting the passed node/block from the end of
// the main (best) chain.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) disconnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint) error {
// Make sure the node being disconnected is the end of the best chain.
if !node.hash.IsEqual(b.bestNode.hash) {
return AssertError("disconnectBlock must be called with the " +
"block at the end of the main chain")
}
// Get the previous block node. This function is used over simply
// accessing node.parent directly as it will dynamically create previous
// block nodes as needed. This helps allow only the pieces of the chain
// that are needed to remain in memory.
prevNode, err := b.getPrevNodeFromNode(node)
if err != nil {
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 {
var err error
prevBlock, err = dbFetchBlockByHash(dbTx, prevNode.hash)
return err
})
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(prevBlock.MsgBlock().Transactions))
blockSize := uint64(prevBlock.MsgBlock().SerializeSize())
newTotalTxns := curTotalTxns - uint64(len(block.MsgBlock().Transactions))
state := newBestState(prevNode, blockSize, numTxns, newTotalTxns,
medianTime)
err = b.db.Update(func(dbTx database.Tx) error {
// Update best block state.
err := dbPutBestState(dbTx, state, node.workSum)
if err != nil {
return err
}
// Remove the block hash and height from the block index which
// tracks the main chain.
err = dbRemoveBlockIndex(dbTx, block.Hash(), node.height)
if err != nil {
return err
}
// Update the utxo set using the state of the utxo view. This
// entails restoring all of the utxos spent and removing the new
// ones created by the block.
err = dbPutUtxoView(dbTx, view)
if err != nil {
return err
}
// Update the transaction spend journal by removing the record
// that contains all txos spent by the block .
err = dbRemoveSpendJournalEntry(dbTx, block.Hash())
if err != nil {
return err
}
// Allow the index manager to call each of the currently active
// optional indexes with the block being disconnected so they
// can update themselves accordingly.
if b.indexManager != nil {
err := b.indexManager.DisconnectBlock(dbTx, block, view)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}
// Prune fully spent entries and mark all entries in the view unmodified
// now that the modifications have been committed to the database.
view.commit()
// Mark block as being in a side chain.
node.inMainChain = false
// This node's parent is now the end of the best chain.
b.bestNode = node.parent
// Update the state for the best block. Notice how this replaces the
// entire struct instead of updating the existing one. This effectively
// allows the old version to act as a snapshot which callers can use
// freely without needing to hold a lock for the duration. See the
// comments on the state variable for more details.
b.stateLock.Lock()
b.stateSnapshot = state
b.stateLock.Unlock()
// Notify the caller that the block was disconnected from the main
// chain. The caller would typically want to react with actions such as
// updating wallets.
b.chainLock.Unlock()
b.sendNotification(NTBlockDisconnected, block)
b.chainLock.Lock()
return nil
}
// countSpentOutputs returns the number of utxos the passed block spends.
func countSpentOutputs(block *btcutil.Block) int {
// Exclude the coinbase transaction since it can't spend anything.
var numSpent int
for _, tx := range block.Transactions()[1:] {
numSpent += len(tx.MsgTx().TxIn)
}
return numSpent
}
// reorganizeChain reorganizes the block chain by disconnecting the nodes in the
// detachNodes list and connecting the nodes in the attach list. It expects
// that the lists are already in the correct order and are in sync with the
// end of the current best chain. Specifically, nodes that are being
// disconnected must be in reverse order (think of popping them off the end of
// the chain) and nodes the are being attached must be in forwards order
// (think pushing them onto the end of the chain).
//
// The flags modify the behavior of this function as follows:
// - BFDryRun: Only the checks which ensure the reorganize can be completed
// successfully are performed. The chain is not reorganized.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List, flags BehaviorFlags) error {
// All of the blocks to detach and related spend journal entries needed
// to unspend transaction outputs in the blocks being disconnected must
// be loaded from the database during the reorg check phase below and
// then they are needed again when doing the actual database updates.
// Rather than doing two loads, cache the loaded data into these slices.
detachBlocks := make([]*btcutil.Block, 0, detachNodes.Len())
detachSpentTxOuts := make([][]spentTxOut, 0, detachNodes.Len())
attachBlocks := make([]*btcutil.Block, 0, attachNodes.Len())
// Disconnect all of the blocks back to the point of the fork. This
// entails loading the blocks and their associated spent txos from the
// database and using that information to unspend all of the spent txos
// and remove the utxos created by the blocks.
view := NewUtxoViewpoint()
view.SetBestHash(b.bestNode.hash)
for e := detachNodes.Front(); e != nil; e = e.Next() {
n := e.Value.(*blockNode)
var block *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
var err error
block, err = dbFetchBlockByHash(dbTx, n.hash)
return err
})
if err != nil {
return err
}
// Load all of the utxos referenced by the block that aren't
// already in the view.
err = view.fetchInputUtxos(b.db, block)
if err != nil {
return err
}
// Load all of the spent txos for the block from the spend
// journal.
var stxos []spentTxOut
err = b.db.View(func(dbTx database.Tx) error {
stxos, err = dbFetchSpendJournalEntry(dbTx, block, view)
return err
})
if err != nil {
return err
}
// Store the loaded block and spend journal entry for later.
detachBlocks = append(detachBlocks, block)
detachSpentTxOuts = append(detachSpentTxOuts, stxos)
err = view.disconnectTransactions(block, stxos)
if err != nil {
return err
}
}
// Perform several checks to verify each block that needs to be attached
// to the main chain can be connected without violating any rules and
// without actually connecting the block.
//
// NOTE: These checks could be done directly when connecting a block,
// however the downside to that approach is that if any of these checks
// fail after disconnecting some blocks or attaching others, all of the
// operations have to be rolled back to get the chain back into the
// state it was before the rule violation (or other failure). There are
// at least a couple of ways accomplish that rollback, but both involve
// tweaking the chain and/or database. This approach catches these
// issues before ever modifying the chain.
for e := attachNodes.Front(); e != nil; e = e.Next() {
n := e.Value.(*blockNode)
var block *btcutil.Block
err := b.db.View(func(dbTx database.Tx) error {
// NOTE: This block is not in the main chain, so the
// block has to be loaded directly from the database
// instead of using the dbFetchBlockByHash function.
blockBytes, err := dbTx.FetchBlock(n.hash)
if err != nil {
return err
}
block, err = btcutil.NewBlockFromBytes(blockBytes)
if err != nil {
return err
}
block.SetHeight(n.height)
return nil
})
if err != nil {
return err
}
// Store the loaded block for later.
attachBlocks = append(attachBlocks, block)
// Notice the spent txout details are not requested here and
// thus will not be generated. This is done because the state
// is not being immediately written to the database, so it is
// not needed.
err = b.checkConnectBlock(n, block, view, nil)
if err != nil {
return err
}
}
// Skip disconnecting and connecting the blocks when running with the
// dry run flag set.
if flags&BFDryRun == BFDryRun {
return nil
}
// Reset the view for the actual connection code below. This is
// required because the view was previously modified when checking if
// the reorg would be successful and the connection code requires the
// view to be valid from the viewpoint of each block being connected or
// disconnected.
view = NewUtxoViewpoint()
view.SetBestHash(b.bestNode.hash)
// Disconnect blocks from the main chain.
for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() {
n := e.Value.(*blockNode)
block := detachBlocks[i]
// Load all of the utxos referenced by the block that aren't
// already in the view.
err := view.fetchInputUtxos(b.db, block)
if err != nil {
return err
}
// Update the view to unspend all of the spent txos and remove
// the utxos created by the block.
err = view.disconnectTransactions(block, detachSpentTxOuts[i])
if err != nil {
return err
}
// Update the database and chain state.
err = b.disconnectBlock(n, block, view)
if err != nil {
return err
}
}
// Connect the new best chain blocks.
for i, e := 0, attachNodes.Front(); e != nil; i, e = i+1, e.Next() {
n := e.Value.(*blockNode)
block := attachBlocks[i]
// Load all of the utxos referenced by the block that aren't
// already in the view.
err := view.fetchInputUtxos(b.db, block)
if err != nil {
return err
}
// Update the view to mark all utxos referenced by the block
// as spent and add all transactions being created by this block
// to it. Also, provide an stxo slice so the spent txout
// details are generated.
stxos := make([]spentTxOut, 0, countSpentOutputs(block))
err = view.connectTransactions(block, &stxos)
if err != nil {
return err
}
// Update the database and chain state.
err = b.connectBlock(n, block, view, stxos)
if err != nil {
return err
}
}
// Log the point where the chain forked.
firstAttachNode := attachNodes.Front().Value.(*blockNode)
forkNode, err := b.getPrevNodeFromNode(firstAttachNode)
if err == nil {
log.Infof("REORGANIZE: Chain forks at %v", forkNode.hash)
}
// Log the old and new best chain heads.
firstDetachNode := detachNodes.Front().Value.(*blockNode)
lastAttachNode := attachNodes.Back().Value.(*blockNode)
log.Infof("REORGANIZE: Old best chain head was %v", firstDetachNode.hash)
log.Infof("REORGANIZE: New best chain head is %v", lastAttachNode.hash)
return nil
}
// connectBestChain handles connecting the passed block to the chain while
// respecting proper chain selection according to the chain with the most
// proof of work. In the typical case, the new block simply extends the main
// chain. However, it may also be extending (or creating) a side chain (fork)
// which may or may not end up becoming the main chain depending on which fork
// cumulatively has the most proof of work. It returns whether or not the block
// ended up on the main chain (either due to extending the main chain or causing
// a reorganization to become the main chain).
//
// The flags modify the behavior of this function as follows:
// - BFFastAdd: Avoids several expensive transaction validation operations.
// This is useful when using checkpoints.
// - BFDryRun: Prevents the block from being connected and avoids modifying the
// state of the memory chain index. Also, any log messages related to
// modifying the state are avoided.
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, flags BehaviorFlags) (bool, error) {
fastAdd := flags&BFFastAdd == BFFastAdd
dryRun := flags&BFDryRun == BFDryRun
// We are extending the main (best) chain with a new block. This is the
// most common case.
if node.parentHash.IsEqual(b.bestNode.hash) {
// Perform several checks to verify the block can be connected
// to the main chain without violating any rules and without
// actually connecting the block.
view := NewUtxoViewpoint()
view.SetBestHash(node.parentHash)
stxos := make([]spentTxOut, 0, countSpentOutputs(block))
if !fastAdd {
err := b.checkConnectBlock(node, block, view, &stxos)
if err != nil {
return false, err
}
}
// Don't connect the block if performing a dry run.
if dryRun {
return true, nil
}
// In the fast add case the code to check the block connection
// was skipped, so the utxo view needs to load the referenced
// utxos, spend them, and add the new utxos being created by
// this block.
if fastAdd {
err := view.fetchInputUtxos(b.db, block)
if err != nil {
return false, err
}
err = view.connectTransactions(block, &stxos)
if err != nil {
return false, err
}
}
// Connect the block to the main chain.
err := b.connectBlock(node, block, view, stxos)
if err != nil {
return false, err
}
// Connect the parent node to this node.
if node.parent != nil {
node.parent.children = append(node.parent.children, node)
}
return true, nil
}
if fastAdd {
log.Warnf("fastAdd set in the side chain case? %v\n",
block.Hash())
}
// We're extending (or creating) a side chain which may or may not
// become the main chain, but in either case the entry is needed in the
// index for future processing.
b.index[*node.hash] = node
// Connect the parent node to this node.
node.inMainChain = false
node.parent.children = append(node.parent.children, node)
// Disconnect it from the parent node when the function returns when
// running in dry run mode.
if dryRun {
defer func() {
children := node.parent.children
children = removeChildNode(children, node)
node.parent.children = children
delete(b.index, *node.hash)
}()
}
// We're extending (or creating) a side chain, but the cumulative
// work for this new side chain is not enough to make it the new chain.
if node.workSum.Cmp(b.bestNode.workSum) <= 0 {
// Skip Logging info when the dry run flag is set.
if dryRun {
return false, nil
}
// Find the fork point.
fork := node
for ; fork.parent != nil; fork = fork.parent {
if fork.inMainChain {
break
}
}
// Log information about how the block is forking the chain.
if fork.hash.IsEqual(node.parent.hash) {
log.Infof("FORK: Block %v forks the chain at height %d"+
"/block %v, but does not cause a reorganize",
node.hash, fork.height, fork.hash)
} else {
log.Infof("EXTEND FORK: Block %v extends a side chain "+
"which forks the chain at height %d/block %v",
node.hash, fork.height, fork.hash)
}
return false, nil
}
// We're extending (or creating) a side chain and the cumulative work
// for this new side chain is more than the old best chain, so this side
// chain needs to become the main chain. In order to accomplish that,
// find the common ancestor of both sides of the fork, disconnect the
// blocks that form the (now) old fork from the main chain, and attach
// the blocks that form the new chain to the main chain starting at the
// common ancenstor (the point where the chain forked).
detachNodes, attachNodes := b.getReorganizeNodes(node)
// Reorganize the chain.
if !dryRun {
log.Infof("REORGANIZE: Block %v is causing a reorganize.",
node.hash)
}
err := b.reorganizeChain(detachNodes, attachNodes, flags)
if err != nil {
return false, err
}
return true, nil
}
// isCurrent returns whether or not the chain believes it is current. Several
// factors are used to guess, but the key factors that allow the chain to
// believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago
//
// This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) isCurrent() bool {
// Not current if the latest main (best) chain height is before the
// latest known good checkpoint (when checkpoints are enabled).
checkpoint := b.LatestCheckpoint()
if checkpoint != nil && b.bestNode.height < checkpoint.Height {
return false
}
// Not current if the latest best block has a timestamp before 24 hours
// ago.
//
// The chain appears to be current if none of the checks reported
// otherwise.
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour)
return !b.bestNode.timestamp.Before(minus24Hours)
}
// IsCurrent returns whether or not the chain believes it is current. Several
// factors are used to guess, but the key factors that allow the chain to
// believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago
//
// This function is safe for concurrent access.
func (b *BlockChain) IsCurrent() bool {
b.chainLock.RLock()
defer b.chainLock.RUnlock()
return b.isCurrent()
}
// BestSnapshot returns information about the current best chain block and
// related state as of the current point in time. The returned instance must be
// treated as immutable since it is shared by all callers.
//
// This function is safe for concurrent access.
func (b *BlockChain) BestSnapshot() *BestState {
b.stateLock.RLock()
snapshot := b.stateSnapshot
b.stateLock.RUnlock()
return snapshot
}
// IndexManager provides a generic interface that the is called when blocks are
// connected and disconnected to and from the tip of the main chain for the
// purpose of supporting optional indexes.
type IndexManager interface {
// Init is invoked during chain initialize in order to allow the index
// manager to initialize itself and any indexes it is managing.
Init(*BlockChain) error
// ConnectBlock is invoked when a new block has been connected to the
// main chain.
ConnectBlock(database.Tx, *btcutil.Block, *UtxoViewpoint) error
// DisconnectBlock is invoked when a block has been disconnected from
// the main chain.
DisconnectBlock(database.Tx, *btcutil.Block, *UtxoViewpoint) error
}
// Config is a descriptor which specifies the blockchain instance configuration.
type Config struct {
// DB defines the database which houses the blocks and will be used to
// store all metadata created by this package such as the utxo set.
//
// This field is required.
DB database.DB
// ChainParams identifies which chain parameters the chain is associated
// with.
//
// This field is required.
ChainParams *chaincfg.Params
// Checkpoints hold caller-defined checkpoints that should be added to
// the default checkpoints in ChainParams. Checkpoints must be sorted
// by height.
//
// This field can be nil if the caller does not wish to specify any
// checkpoints.
Checkpoints []chaincfg.Checkpoint
// TimeSource defines the median time source to use for things such as
// block processing and determining whether or not the chain is current.
//
// The caller is expected to keep a reference to the time source as well
// and add time samples from other peers on the network so the local
// time is adjusted to be in agreement with other peers.
TimeSource MedianTimeSource
// Notifications defines a callback to which notifications will be sent
// when various events take place. See the documentation for
// Notification and NotificationType for details on the types and
// contents of notifications.
//
// This field can be nil if the caller is not interested in receiving
// notifications.
Notifications NotificationCallback
// SigCache defines a signature cache to use when when validating
// signatures. This is typically most useful when individual
// transactions are already being validated prior to their inclusion in
// a block such as what is usually done via a transaction memory pool.
//
// This field can be nil if the caller is not interested in using a
// signature cache.
SigCache *txscript.SigCache
// IndexManager defines an index manager to use when initializing the
// chain and connecting and disconnecting blocks.
//
// This field can be nil if the caller does not wish to make use of an
// index manager.
IndexManager IndexManager
}
// New returns a BlockChain instance using the provided configuration details.
func New(config *Config) (*BlockChain, error) {
// Enforce required config fields.
if config.DB == nil {
return nil, AssertError("blockchain.New database is nil")
}
if config.ChainParams == nil {
return nil, AssertError("blockchain.New chain parameters nil")
}
if config.TimeSource == nil {
return nil, AssertError("blockchain.New timesource is nil")
}
// Generate a checkpoint by height map from the provided checkpoints
// and assert the provided checkpoints are sorted by height as required.
var checkpointsByHeight map[int32]*chaincfg.Checkpoint
var prevCheckpointHeight int32
if len(config.Checkpoints) > 0 {
checkpointsByHeight = make(map[int32]*chaincfg.Checkpoint)
for i := range config.Checkpoints {
checkpoint := &config.Checkpoints[i]
if checkpoint.Height <= prevCheckpointHeight {
return nil, AssertError("blockchain.New " +
"checkpoints are not sorted by height")
}
checkpointsByHeight[checkpoint.Height] = checkpoint
prevCheckpointHeight = checkpoint.Height
}
}
params := config.ChainParams
targetTimespan := int64(params.TargetTimespan)
targetTimePerBlock := int64(params.TargetTimePerBlock)
adjustmentFactor := params.RetargetAdjustmentFactor
b := BlockChain{
checkpoints: config.Checkpoints,
checkpointsByHeight: checkpointsByHeight,
db: config.DB,
chainParams: params,
timeSource: config.TimeSource,
notifications: config.Notifications,
sigCache: config.SigCache,
indexManager: config.IndexManager,
minRetargetTimespan: targetTimespan / adjustmentFactor,
maxRetargetTimespan: targetTimespan * adjustmentFactor,
blocksPerRetarget: int32(targetTimespan / targetTimePerBlock),
minMemoryNodes: int32(targetTimespan / targetTimePerBlock),
bestNode: nil,
index: make(map[chainhash.Hash]*blockNode),
depNodes: make(map[chainhash.Hash][]*blockNode),
orphans: make(map[chainhash.Hash]*orphanBlock),
prevOrphans: make(map[chainhash.Hash][]*orphanBlock),
warningCaches: newThresholdCaches(vbNumBits),
deploymentCaches: newThresholdCaches(chaincfg.DefinedDeployments),
}
// 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(); err != nil {
return nil, err
}
// Initialize and catch up all of the currently active optional indexes
// as needed.
if config.IndexManager != nil {
if err := config.IndexManager.Init(&b); err != nil {
return nil, err
}
}
// Initialize rule change threshold state caches from the passed
// database. When the db does not yet contains any cached information
// for a given threshold cache, the threshold states will be calculated
// using the chain state.
if err := b.initThresholdCaches(); err != nil {
return nil, err
}
log.Infof("Chain state (height %d, hash %v, totaltx %d, work %v)",
b.bestNode.height, b.bestNode.hash, b.stateSnapshot.TotalTxns,
b.bestNode.workSum)
return &b, nil
}