github.com/palcoin-project/palcd@v1.0.0/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/palcoin-project/palcd/chaincfg"
    14  	"github.com/palcoin-project/palcd/chaincfg/chainhash"
    15  	"github.com/palcoin-project/palcd/database"
    16  	"github.com/palcoin-project/palcd/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  
    97  	// status is a bitfield representing the validation state of the block. The
    98  	// status field, unlike the other fields, may be written to and so should
    99  	// only be accessed using the concurrent-safe NodeStatus method on
   100  	// blockIndex once the node has been added to the global index.
   101  	status blockStatus
   102  }
   103  
   104  // initBlockNode initializes a block node from the given header and parent node,
   105  // calculating the height and workSum from the respective fields on the parent.
   106  // This function is NOT safe for concurrent access.  It must only be called when
   107  // initially creating a node.
   108  func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) {
   109  	*node = blockNode{
   110  		hash:       blockHeader.BlockHash(),
   111  		workSum:    CalcWork(blockHeader.Bits),
   112  		version:    blockHeader.Version,
   113  		bits:       blockHeader.Bits,
   114  		nonce:      blockHeader.Nonce,
   115  		timestamp:  blockHeader.Timestamp.Unix(),
   116  		merkleRoot: blockHeader.MerkleRoot,
   117  	}
   118  	if parent != nil {
   119  		node.parent = parent
   120  		node.height = parent.height + 1
   121  		node.workSum = node.workSum.Add(parent.workSum, node.workSum)
   122  	}
   123  }
   124  
   125  // newBlockNode returns a new block node for the given block header and parent
   126  // node, calculating the height and workSum from the respective fields on the
   127  // parent. This function is NOT safe for concurrent access.
   128  func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode {
   129  	var node blockNode
   130  	initBlockNode(&node, blockHeader, parent)
   131  	return &node
   132  }
   133  
   134  // Header constructs a block header from the node and returns it.
   135  //
   136  // This function is safe for concurrent access.
   137  func (node *blockNode) Header() wire.BlockHeader {
   138  	// No lock is needed because all accessed fields are immutable.
   139  	prevHash := &zeroHash
   140  	if node.parent != nil {
   141  		prevHash = &node.parent.hash
   142  	}
   143  	return wire.BlockHeader{
   144  		Version:    node.version,
   145  		PrevBlock:  *prevHash,
   146  		MerkleRoot: node.merkleRoot,
   147  		Timestamp:  time.Unix(node.timestamp, 0),
   148  		Bits:       node.bits,
   149  		Nonce:      node.nonce,
   150  	}
   151  }
   152  
   153  // Ancestor returns the ancestor block node at the provided height by following
   154  // the chain backwards from this node.  The returned block will be nil when a
   155  // height is requested that is after the height of the passed node or is less
   156  // than zero.
   157  //
   158  // This function is safe for concurrent access.
   159  func (node *blockNode) Ancestor(height int32) *blockNode {
   160  	if height < 0 || height > node.height {
   161  		return nil
   162  	}
   163  
   164  	n := node
   165  	for ; n != nil && n.height != height; n = n.parent {
   166  		// Intentionally left blank
   167  	}
   168  
   169  	return n
   170  }
   171  
   172  // RelativeAncestor returns the ancestor block node a relative 'distance' blocks
   173  // before this node.  This is equivalent to calling Ancestor with the node's
   174  // height minus provided distance.
   175  //
   176  // This function is safe for concurrent access.
   177  func (node *blockNode) RelativeAncestor(distance int32) *blockNode {
   178  	return node.Ancestor(node.height - distance)
   179  }
   180  
   181  // CalcPastMedianTime calculates the median time of the previous few blocks
   182  // prior to, and including, the block node.
   183  //
   184  // This function is safe for concurrent access.
   185  func (node *blockNode) CalcPastMedianTime() time.Time {
   186  	// Create a slice of the previous few block timestamps used to calculate
   187  	// the median per the number defined by the constant medianTimeBlocks.
   188  	timestamps := make([]int64, medianTimeBlocks)
   189  	numNodes := 0
   190  	iterNode := node
   191  	for i := 0; i < medianTimeBlocks && iterNode != nil; i++ {
   192  		timestamps[i] = iterNode.timestamp
   193  		numNodes++
   194  
   195  		iterNode = iterNode.parent
   196  	}
   197  
   198  	// Prune the slice to the actual number of available timestamps which
   199  	// will be fewer than desired near the beginning of the block chain
   200  	// and sort them.
   201  	timestamps = timestamps[:numNodes]
   202  	sort.Sort(timeSorter(timestamps))
   203  
   204  	// NOTE: The consensus rules incorrectly calculate the median for even
   205  	// numbers of blocks.  A true median averages the middle two elements
   206  	// for a set with an even number of elements in it.   Since the constant
   207  	// for the previous number of blocks to be used is odd, this is only an
   208  	// issue for a few blocks near the beginning of the chain.  I suspect
   209  	// this is an optimization even though the result is slightly wrong for
   210  	// a few of the first blocks since after the first few blocks, there
   211  	// will always be an odd number of blocks in the set per the constant.
   212  	//
   213  	// This code follows suit to ensure the same rules are used, however, be
   214  	// aware that should the medianTimeBlocks constant ever be changed to an
   215  	// even number, this code will be wrong.
   216  	medianTimestamp := timestamps[numNodes/2]
   217  	return time.Unix(medianTimestamp, 0)
   218  }
   219  
   220  // blockIndex provides facilities for keeping track of an in-memory index of the
   221  // block chain.  Although the name block chain suggests a single chain of
   222  // blocks, it is actually a tree-shaped structure where any node can have
   223  // multiple children.  However, there can only be one active branch which does
   224  // indeed form a chain from the tip all the way back to the genesis block.
   225  type blockIndex struct {
   226  	// The following fields are set when the instance is created and can't
   227  	// be changed afterwards, so there is no need to protect them with a
   228  	// separate mutex.
   229  	db          database.DB
   230  	chainParams *chaincfg.Params
   231  
   232  	sync.RWMutex
   233  	index map[chainhash.Hash]*blockNode
   234  	dirty map[*blockNode]struct{}
   235  }
   236  
   237  // newBlockIndex returns a new empty instance of a block index.  The index will
   238  // be dynamically populated as block nodes are loaded from the database and
   239  // manually added.
   240  func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex {
   241  	return &blockIndex{
   242  		db:          db,
   243  		chainParams: chainParams,
   244  		index:       make(map[chainhash.Hash]*blockNode),
   245  		dirty:       make(map[*blockNode]struct{}),
   246  	}
   247  }
   248  
   249  // HaveBlock returns whether or not the block index contains the provided hash.
   250  //
   251  // This function is safe for concurrent access.
   252  func (bi *blockIndex) HaveBlock(hash *chainhash.Hash) bool {
   253  	bi.RLock()
   254  	_, hasBlock := bi.index[*hash]
   255  	bi.RUnlock()
   256  	return hasBlock
   257  }
   258  
   259  // LookupNode returns the block node identified by the provided hash.  It will
   260  // return nil if there is no entry for the hash.
   261  //
   262  // This function is safe for concurrent access.
   263  func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode {
   264  	bi.RLock()
   265  	node := bi.index[*hash]
   266  	bi.RUnlock()
   267  	return node
   268  }
   269  
   270  // AddNode adds the provided node to the block index and marks it as dirty.
   271  // Duplicate entries are not checked so it is up to caller to avoid adding them.
   272  //
   273  // This function is safe for concurrent access.
   274  func (bi *blockIndex) AddNode(node *blockNode) {
   275  	bi.Lock()
   276  	bi.addNode(node)
   277  	bi.dirty[node] = struct{}{}
   278  	bi.Unlock()
   279  }
   280  
   281  // addNode adds the provided node to the block index, but does not mark it as
   282  // dirty. This can be used while initializing the block index.
   283  //
   284  // This function is NOT safe for concurrent access.
   285  func (bi *blockIndex) addNode(node *blockNode) {
   286  	bi.index[node.hash] = node
   287  }
   288  
   289  // NodeStatus provides concurrent-safe access to the status field of a node.
   290  //
   291  // This function is safe for concurrent access.
   292  func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus {
   293  	bi.RLock()
   294  	status := node.status
   295  	bi.RUnlock()
   296  	return status
   297  }
   298  
   299  // SetStatusFlags flips the provided status flags on the block node to on,
   300  // regardless of whether they were on or off previously. This does not unset any
   301  // flags currently on.
   302  //
   303  // This function is safe for concurrent access.
   304  func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) {
   305  	bi.Lock()
   306  	node.status |= flags
   307  	bi.dirty[node] = struct{}{}
   308  	bi.Unlock()
   309  }
   310  
   311  // UnsetStatusFlags flips the provided status flags on the block node to off,
   312  // regardless of whether they were on or off previously.
   313  //
   314  // This function is safe for concurrent access.
   315  func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) {
   316  	bi.Lock()
   317  	node.status &^= flags
   318  	bi.dirty[node] = struct{}{}
   319  	bi.Unlock()
   320  }
   321  
   322  // flushToDB writes all dirty block nodes to the database. If all writes
   323  // succeed, this clears the dirty set.
   324  func (bi *blockIndex) flushToDB() error {
   325  	bi.Lock()
   326  	if len(bi.dirty) == 0 {
   327  		bi.Unlock()
   328  		return nil
   329  	}
   330  
   331  	err := bi.db.Update(func(dbTx database.Tx) error {
   332  		for node := range bi.dirty {
   333  			err := dbStoreBlockNode(dbTx, node)
   334  			if err != nil {
   335  				return err
   336  			}
   337  		}
   338  		return nil
   339  	})
   340  
   341  	// If write was successful, clear the dirty set.
   342  	if err == nil {
   343  		bi.dirty = make(map[*blockNode]struct{})
   344  	}
   345  
   346  	bi.Unlock()
   347  	return err
   348  }