github.com/decred/dcrd/blockchain@v1.2.1/process.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Copyright (c) 2015-2018 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package blockchain
     7  
     8  import (
     9  	"fmt"
    10  	"time"
    11  
    12  	"github.com/decred/dcrd/blockchain/standalone"
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrd/dcrutil"
    15  )
    16  
    17  // BehaviorFlags is a bitmask defining tweaks to the normal behavior when
    18  // performing chain processing and consensus rules checks.
    19  type BehaviorFlags uint32
    20  
    21  const (
    22  	// BFFastAdd may be set to indicate that several checks can be avoided
    23  	// for the block since it is already known to fit into the chain due to
    24  	// already proving it correct links into the chain up to a known
    25  	// checkpoint.  This is primarily used for headers-first mode.
    26  	BFFastAdd BehaviorFlags = 1 << iota
    27  
    28  	// BFNoPoWCheck may be set to indicate the proof of work check which
    29  	// ensures a block hashes to a value less than the required target will
    30  	// not be performed.
    31  	BFNoPoWCheck
    32  
    33  	// BFNone is a convenience value to specifically indicate no flags.
    34  	BFNone BehaviorFlags = 0
    35  )
    36  
    37  // processOrphans determines if there are any orphans which depend on the passed
    38  // block hash (they are no longer orphans if true) and potentially accepts them.
    39  // It repeats the process for the newly accepted blocks (to detect further
    40  // orphans which may no longer be orphans) until there are no more.
    41  //
    42  // The flags do not modify the behavior of this function directly, however they
    43  // are needed to pass along to maybeAcceptBlock.
    44  //
    45  // This function MUST be called with the chain state lock held (for writes).
    46  func (b *BlockChain) processOrphans(hash *chainhash.Hash, flags BehaviorFlags) error {
    47  	// Start with processing at least the passed hash.  Leave a little room
    48  	// for additional orphan blocks that need to be processed without
    49  	// needing to grow the array in the common case.
    50  	processHashes := make([]*chainhash.Hash, 0, 10)
    51  	processHashes = append(processHashes, hash)
    52  	for len(processHashes) > 0 {
    53  		// Pop the first hash to process from the slice.
    54  		processHash := processHashes[0]
    55  		processHashes[0] = nil // Prevent GC leak.
    56  		processHashes = processHashes[1:]
    57  
    58  		// Look up all orphans that are parented by the block we just
    59  		// accepted.  This will typically only be one, but it could
    60  		// be multiple if multiple blocks are mined and broadcast
    61  		// around the same time.  The one with the most proof of work
    62  		// will eventually win out.  An indexing for loop is
    63  		// intentionally used over a range here as range does not
    64  		// reevaluate the slice on each iteration nor does it adjust the
    65  		// index for the modified slice.
    66  		for i := 0; i < len(b.prevOrphans[*processHash]); i++ {
    67  			orphan := b.prevOrphans[*processHash][i]
    68  			if orphan == nil {
    69  				log.Warnf("Found a nil entry at index %d in the "+
    70  					"orphan dependency list for block %v", i,
    71  					processHash)
    72  				continue
    73  			}
    74  
    75  			// Remove the orphan from the orphan pool.
    76  			orphanHash := orphan.block.Hash()
    77  			b.removeOrphanBlock(orphan)
    78  			i--
    79  
    80  			// Potentially accept the block into the block chain.
    81  			_, err := b.maybeAcceptBlock(orphan.block, flags)
    82  			if err != nil {
    83  				return err
    84  			}
    85  
    86  			// Add this block to the list of blocks to process so
    87  			// any orphan blocks that depend on this block are
    88  			// handled too.
    89  			processHashes = append(processHashes, orphanHash)
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  // ProcessBlock is the main workhorse for handling insertion of new blocks into
    96  // the block chain.  It includes functionality such as rejecting duplicate
    97  // blocks, ensuring blocks follow all rules, orphan handling, and insertion into
    98  // the block chain along with best chain selection and reorganization.
    99  //
   100  // When no errors occurred during processing, the first return value indicates
   101  // the length of the fork the block extended.  In the case it either exteneded
   102  // the best chain or is now the tip of the best chain due to causing a
   103  // reorganize, the fork length will be 0.  The second return value indicates
   104  // whether or not the block is an orphan, in which case the fork length will
   105  // also be zero as expected, because it, by definition, does not connect ot the
   106  // best chain.
   107  //
   108  // This function is safe for concurrent access.
   109  func (b *BlockChain) ProcessBlock(block *dcrutil.Block, flags BehaviorFlags) (int64, bool, error) {
   110  	b.chainLock.Lock()
   111  	defer b.chainLock.Unlock()
   112  
   113  	fastAdd := flags&BFFastAdd == BFFastAdd
   114  
   115  	blockHash := block.Hash()
   116  	log.Tracef("Processing block %v", blockHash)
   117  	currentTime := time.Now()
   118  	defer func() {
   119  		elapsedTime := time.Since(currentTime)
   120  		log.Debugf("Block %v (height %v) finished processing in %s",
   121  			blockHash, block.Height(), elapsedTime)
   122  	}()
   123  
   124  	// The block must not already exist in the main chain or side chains.
   125  	if b.index.HaveBlock(blockHash) {
   126  		str := fmt.Sprintf("already have block %v", blockHash)
   127  		return 0, false, ruleError(ErrDuplicateBlock, str)
   128  	}
   129  
   130  	// The block must not already exist as an orphan.
   131  	if _, exists := b.orphans[*blockHash]; exists {
   132  		str := fmt.Sprintf("already have block (orphan) %v", blockHash)
   133  		return 0, false, ruleError(ErrDuplicateBlock, str)
   134  	}
   135  
   136  	// Perform preliminary sanity checks on the block and its transactions.
   137  	err := checkBlockSanity(block, b.timeSource, flags, b.chainParams)
   138  	if err != nil {
   139  		return 0, false, err
   140  	}
   141  
   142  	// Find the previous checkpoint and perform some additional checks based
   143  	// on the checkpoint.  This provides a few nice properties such as
   144  	// preventing old side chain blocks before the last checkpoint,
   145  	// rejecting easy to mine, but otherwise bogus, blocks that could be
   146  	// used to eat memory, and ensuring expected (versus claimed) proof of
   147  	// work requirements since the previous checkpoint are met.
   148  	blockHeader := &block.MsgBlock().Header
   149  	checkpointNode, err := b.findPreviousCheckpoint()
   150  	if err != nil {
   151  		return 0, false, err
   152  	}
   153  	if checkpointNode != nil {
   154  		// Ensure the block timestamp is after the checkpoint timestamp.
   155  		checkpointTime := time.Unix(checkpointNode.timestamp, 0)
   156  		if blockHeader.Timestamp.Before(checkpointTime) {
   157  			str := fmt.Sprintf("block %v has timestamp %v before "+
   158  				"last checkpoint timestamp %v", blockHash,
   159  				blockHeader.Timestamp, checkpointTime)
   160  			return 0, false, ruleError(ErrCheckpointTimeTooOld, str)
   161  		}
   162  
   163  		if !fastAdd {
   164  			// Even though the checks prior to now have already ensured the
   165  			// proof of work exceeds the claimed amount, the claimed amount
   166  			// is a field in the block header which could be forged.  This
   167  			// check ensures the proof of work is at least the minimum
   168  			// expected based on elapsed time since the last checkpoint and
   169  			// maximum adjustment allowed by the retarget rules.
   170  			duration := blockHeader.Timestamp.Sub(checkpointTime)
   171  			requiredTarget := standalone.CompactToBig(b.calcEasiestDifficulty(
   172  				checkpointNode.bits, duration))
   173  			currentTarget := standalone.CompactToBig(blockHeader.Bits)
   174  			if currentTarget.Cmp(requiredTarget) > 0 {
   175  				str := fmt.Sprintf("block target difficulty of %064x "+
   176  					"is too low when compared to the previous "+
   177  					"checkpoint", currentTarget)
   178  				return 0, false, ruleError(ErrDifficultyTooLow, str)
   179  			}
   180  		}
   181  	}
   182  
   183  	// Handle orphan blocks.
   184  	prevHash := &blockHeader.PrevBlock
   185  	if !b.index.HaveBlock(prevHash) {
   186  		log.Infof("Adding orphan block %v with parent %v", blockHash,
   187  			prevHash)
   188  		b.addOrphanBlock(block)
   189  
   190  		// The fork length of orphans is unknown since they, by definition, do
   191  		// not connect to the best chain.
   192  		return 0, true, nil
   193  	}
   194  
   195  	// The block has passed all context independent checks and appears sane
   196  	// enough to potentially accept it into the block chain.
   197  	forkLen, err := b.maybeAcceptBlock(block, flags)
   198  	if err != nil {
   199  		return 0, false, err
   200  	}
   201  
   202  	// Accept any orphan blocks that depend on this block (they are no
   203  	// longer orphans) and repeat for those accepted blocks until there are
   204  	// no more.
   205  	err = b.processOrphans(blockHash, flags)
   206  	if err != nil {
   207  		return 0, false, err
   208  	}
   209  
   210  	log.Debugf("Accepted block %v", blockHash)
   211  
   212  	return forkLen, false, nil
   213  }