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

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