github.com/lbryio/lbcd@v0.22.119/blockchain/blockindex.go (about)

     1  // Copyright (c) 2015-2017 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package blockchain
     6  
     7  import (
     8  	"math/big"
     9  	"sort"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/lbryio/lbcd/chaincfg"
    14  	"github.com/lbryio/lbcd/chaincfg/chainhash"
    15  	"github.com/lbryio/lbcd/database"
    16  	"github.com/lbryio/lbcd/wire"
    17  )
    18  
    19  // blockStatus is a bit field representing the validation state of the block.
    20  type blockStatus byte
    21  
    22  const (
    23  	// statusDataStored indicates that the block's payload is stored on disk.
    24  	statusDataStored blockStatus = 1 << iota
    25  
    26  	// statusValid indicates that the block has been fully validated.
    27  	statusValid
    28  
    29  	// statusValidateFailed indicates that the block has failed validation.
    30  	statusValidateFailed
    31  
    32  	// statusInvalidAncestor indicates that one of the block's ancestors has
    33  	// has failed validation, thus the block is also invalid.
    34  	statusInvalidAncestor
    35  
    36  	// statusNone indicates that the block has no validation state flags set.
    37  	//
    38  	// NOTE: This must be defined last in order to avoid influencing iota.
    39  	statusNone blockStatus = 0
    40  )
    41  
    42  // HaveData returns whether the full block data is stored in the database. This
    43  // will return false for a block node where only the header is downloaded or
    44  // kept.
    45  func (status blockStatus) HaveData() bool {
    46  	return status&statusDataStored != 0
    47  }
    48  
    49  // KnownValid returns whether the block is known to be valid. This will return
    50  // false for a valid block that has not been fully validated yet.
    51  func (status blockStatus) KnownValid() bool {
    52  	return status&statusValid != 0
    53  }
    54  
    55  // KnownInvalid returns whether the block is known to be invalid. This may be
    56  // because the block itself failed validation or any of its ancestors is
    57  // invalid. This will return false for invalid blocks that have not been proven
    58  // invalid yet.
    59  func (status blockStatus) KnownInvalid() bool {
    60  	return status&(statusValidateFailed|statusInvalidAncestor) != 0
    61  }
    62  
    63  // blockNode represents a block within the block chain and is primarily used to
    64  // aid in selecting the best chain to be the main chain.  The main chain is
    65  // stored into the block database.
    66  type blockNode struct {
    67  	// NOTE: Additions, deletions, or modifications to the order of the
    68  	// definitions in this struct should not be changed without considering
    69  	// how it affects alignment on 64-bit platforms.  The current order is
    70  	// specifically crafted to result in minimal padding.  There will be
    71  	// hundreds of thousands of these in memory, so a few extra bytes of
    72  	// padding adds up.
    73  
    74  	// parent is the parent block for this node.
    75  	parent *blockNode
    76  
    77  	// hash is the double sha 256 of the block.
    78  	hash chainhash.Hash
    79  
    80  	// workSum is the total amount of work in the chain up to and including
    81  	// this node.
    82  	workSum *big.Int
    83  
    84  	// height is the position in the block chain.
    85  	height int32
    86  
    87  	// Some fields from block headers to aid in best chain selection and
    88  	// reconstructing headers from memory.  These must be treated as
    89  	// immutable and are intentionally ordered to avoid padding on 64-bit
    90  	// platforms.
    91  	version    int32
    92  	bits       uint32
    93  	nonce      uint32
    94  	timestamp  int64
    95  	merkleRoot chainhash.Hash
    96  	claimTrie  chainhash.Hash
    97  
    98  	// status is a bitfield representing the validation state of the block. The
    99  	// status field, unlike the other fields, may be written to and so should
   100  	// only be accessed using the concurrent-safe NodeStatus method on
   101  	// blockIndex once the node has been added to the global index.
   102  	status blockStatus
   103  }
   104  
   105  // initBlockNode initializes a block node from the given header and parent node,
   106  // calculating the height and workSum from the respective fields on the parent.
   107  // This function is NOT safe for concurrent access.  It must only be called when
   108  // initially creating a node.
   109  func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) {
   110  	*node = blockNode{
   111  		hash:       blockHeader.BlockHash(),
   112  		workSum:    CalcWork(blockHeader.Bits),
   113  		version:    blockHeader.Version,
   114  		bits:       blockHeader.Bits,
   115  		nonce:      blockHeader.Nonce,
   116  		timestamp:  blockHeader.Timestamp.Unix(),
   117  		merkleRoot: blockHeader.MerkleRoot,
   118  		claimTrie:  blockHeader.ClaimTrie,
   119  	}
   120  	if parent != nil {
   121  		node.parent = parent
   122  		node.height = parent.height + 1
   123  		node.workSum = node.workSum.Add(parent.workSum, node.workSum)
   124  	}
   125  }
   126  
   127  // newBlockNode returns a new block node for the given block header and parent
   128  // node, calculating the height and workSum from the respective fields on the
   129  // parent. This function is NOT safe for concurrent access.
   130  func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode {
   131  	var node blockNode
   132  	initBlockNode(&node, blockHeader, parent)
   133  	return &node
   134  }
   135  
   136  // Header constructs a block header from the node and returns it.
   137  //
   138  // This function is safe for concurrent access.
   139  func (node *blockNode) Header() wire.BlockHeader {
   140  	// No lock is needed because all accessed fields are immutable.
   141  	prevHash := &zeroHash
   142  	if node.parent != nil {
   143  		prevHash = &node.parent.hash
   144  	}
   145  	return wire.BlockHeader{
   146  		Version:    node.version,
   147  		PrevBlock:  *prevHash,
   148  		MerkleRoot: node.merkleRoot,
   149  		ClaimTrie:  node.claimTrie,
   150  		Timestamp:  time.Unix(node.timestamp, 0),
   151  		Bits:       node.bits,
   152  		Nonce:      node.nonce,
   153  	}
   154  }
   155  
   156  // Ancestor returns the ancestor block node at the provided height by following
   157  // the chain backwards from this node.  The returned block will be nil when a
   158  // height is requested that is after the height of the passed node or is less
   159  // than zero.
   160  //
   161  // This function is safe for concurrent access.
   162  func (node *blockNode) Ancestor(height int32) *blockNode {
   163  	if height < 0 || height > node.height {
   164  		return nil
   165  	}
   166  
   167  	n := node
   168  	for ; n != nil && n.height != height; n = n.parent {
   169  		// Intentionally left blank
   170  	}
   171  
   172  	return n
   173  }
   174  
   175  // RelativeAncestor returns the ancestor block node a relative 'distance' blocks
   176  // before this node.  This is equivalent to calling Ancestor with the node's
   177  // height minus provided distance.
   178  //
   179  // This function is safe for concurrent access.
   180  func (node *blockNode) RelativeAncestor(distance int32) *blockNode {
   181  	return node.Ancestor(node.height - distance)
   182  }
   183  
   184  // CalcPastMedianTime calculates the median time of the previous few blocks
   185  // prior to, and including, the block node.
   186  //
   187  // This function is safe for concurrent access.
   188  func (node *blockNode) CalcPastMedianTime() time.Time {
   189  	// Create a slice of the previous few block timestamps used to calculate
   190  	// the median per the number defined by the constant medianTimeBlocks.
   191  	timestamps := make([]int64, medianTimeBlocks)
   192  	numNodes := 0
   193  	iterNode := node
   194  	for i := 0; i < medianTimeBlocks && iterNode != nil; i++ {
   195  		timestamps[i] = iterNode.timestamp
   196  		numNodes++
   197  
   198  		iterNode = iterNode.parent
   199  	}
   200  
   201  	// Prune the slice to the actual number of available timestamps which
   202  	// will be fewer than desired near the beginning of the block chain
   203  	// and sort them.
   204  	timestamps = timestamps[:numNodes]
   205  	sort.Sort(timeSorter(timestamps))
   206  
   207  	// NOTE: The consensus rules incorrectly calculate the median for even
   208  	// numbers of blocks.  A true median averages the middle two elements
   209  	// for a set with an even number of elements in it.   Since the constant
   210  	// for the previous number of blocks to be used is odd, this is only an
   211  	// issue for a few blocks near the beginning of the chain.  I suspect
   212  	// this is an optimization even though the result is slightly wrong for
   213  	// a few of the first blocks since after the first few blocks, there
   214  	// will always be an odd number of blocks in the set per the constant.
   215  	//
   216  	// This code follows suit to ensure the same rules are used, however, be
   217  	// aware that should the medianTimeBlocks constant ever be changed to an
   218  	// even number, this code will be wrong.
   219  	medianTimestamp := timestamps[numNodes/2]
   220  	return time.Unix(medianTimestamp, 0)
   221  }
   222  
   223  // blockIndex provides facilities for keeping track of an in-memory index of the
   224  // block chain.  Although the name block chain suggests a single chain of
   225  // blocks, it is actually a tree-shaped structure where any node can have
   226  // multiple children.  However, there can only be one active branch which does
   227  // indeed form a chain from the tip all the way back to the genesis block.
   228  type blockIndex struct {
   229  	// The following fields are set when the instance is created and can't
   230  	// be changed afterwards, so there is no need to protect them with a
   231  	// separate mutex.
   232  	db          database.DB
   233  	chainParams *chaincfg.Params
   234  
   235  	sync.RWMutex
   236  	index map[chainhash.Hash]*blockNode
   237  	dirty map[*blockNode]struct{}
   238  }
   239  
   240  // newBlockIndex returns a new empty instance of a block index.  The index will
   241  // be dynamically populated as block nodes are loaded from the database and
   242  // manually added.
   243  func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex {
   244  	return &blockIndex{
   245  		db:          db,
   246  		chainParams: chainParams,
   247  		index:       make(map[chainhash.Hash]*blockNode),
   248  		dirty:       make(map[*blockNode]struct{}),
   249  	}
   250  }
   251  
   252  // HaveBlock returns whether or not the block index contains the provided hash.
   253  //
   254  // This function is safe for concurrent access.
   255  func (bi *blockIndex) HaveBlock(hash *chainhash.Hash) bool {
   256  	bi.RLock()
   257  	_, hasBlock := bi.index[*hash]
   258  	bi.RUnlock()
   259  	return hasBlock
   260  }
   261  
   262  // LookupNode returns the block node identified by the provided hash.  It will
   263  // return nil if there is no entry for the hash.
   264  //
   265  // This function is safe for concurrent access.
   266  func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode {
   267  	bi.RLock()
   268  	node := bi.index[*hash]
   269  	bi.RUnlock()
   270  	return node
   271  }
   272  
   273  // AddNode adds the provided node to the block index and marks it as dirty.
   274  // Duplicate entries are not checked so it is up to caller to avoid adding them.
   275  //
   276  // This function is safe for concurrent access.
   277  func (bi *blockIndex) AddNode(node *blockNode) {
   278  	bi.Lock()
   279  	bi.addNode(node)
   280  	bi.dirty[node] = struct{}{}
   281  	bi.Unlock()
   282  }
   283  
   284  // addNode adds the provided node to the block index, but does not mark it as
   285  // dirty. This can be used while initializing the block index.
   286  //
   287  // This function is NOT safe for concurrent access.
   288  func (bi *blockIndex) addNode(node *blockNode) {
   289  	bi.index[node.hash] = node
   290  }
   291  
   292  // NodeStatus provides concurrent-safe access to the status field of a node.
   293  //
   294  // This function is safe for concurrent access.
   295  func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus {
   296  	bi.RLock()
   297  	status := node.status
   298  	bi.RUnlock()
   299  	return status
   300  }
   301  
   302  // SetStatusFlags flips the provided status flags on the block node to on,
   303  // regardless of whether they were on or off previously. This does not unset any
   304  // flags currently on.
   305  //
   306  // This function is safe for concurrent access.
   307  func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) {
   308  	bi.Lock()
   309  	node.status |= flags
   310  	bi.dirty[node] = struct{}{}
   311  	bi.Unlock()
   312  }
   313  
   314  // UnsetStatusFlags flips the provided status flags on the block node to off,
   315  // regardless of whether they were on or off previously.
   316  //
   317  // This function is safe for concurrent access.
   318  func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) {
   319  	bi.Lock()
   320  	node.status &^= flags
   321  	bi.dirty[node] = struct{}{}
   322  	bi.Unlock()
   323  }
   324  
   325  // flushToDB writes all dirty block nodes to the database. If all writes
   326  // succeed, this clears the dirty set.
   327  func (bi *blockIndex) flushToDB() error {
   328  	bi.Lock()
   329  	if len(bi.dirty) == 0 {
   330  		bi.Unlock()
   331  		return nil
   332  	}
   333  
   334  	err := bi.db.Update(func(dbTx database.Tx) error {
   335  		for node := range bi.dirty {
   336  			err := dbStoreBlockNode(dbTx, node)
   337  			if err != nil {
   338  				return err
   339  			}
   340  		}
   341  		return nil
   342  	})
   343  
   344  	// If write was successful, clear the dirty set.
   345  	if err == nil {
   346  		bi.dirty = make(map[*blockNode]struct{})
   347  	}
   348  
   349  	bi.Unlock()
   350  	return err
   351  }