github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/blockchain/process.go (about)

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