process.go raw

   1  package blockchain
   2  
   3  import (
   4  	"errors"
   5  	"fmt"
   6  	"github.com/p9c/p9/pkg/bits"
   7  	"github.com/p9c/p9/pkg/block"
   8  	"github.com/p9c/p9/pkg/fork"
   9  	"github.com/p9c/p9/pkg/log"
  10  
  11  	"time"
  12  	
  13  	"github.com/p9c/p9/pkg/chainhash"
  14  	"github.com/p9c/p9/pkg/database"
  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 for the
  23  	// block since it is already known to fit into the chain due to already proving
  24  	// it correct links into the chain up to a known checkpoint. This is primarily
  25  	// used for headers-first mode.
  26  	BFFastAdd BehaviorFlags = 1 << iota
  27  	// BFNoPoWCheck may be set to indicate the proof of work check which ensures a
  28  	// block hashes to a value less than the required target will not be performed.
  29  	BFNoPoWCheck
  30  	// BFNone is a convenience value to specifically indicate no flags.
  31  	BFNone BehaviorFlags = 0
  32  )
  33  
  34  // ProcessBlock is the main workhorse for handling insertion of new blocks into
  35  // the block chain. It includes functionality such as rejecting duplicate
  36  // blocks, ensuring blocks follow all rules, orphan handling, and insertion into
  37  // the block chain along with best chain selection and reorganization.
  38  //
  39  // When no errors occurred during processing, the first return value indicates
  40  // whether or not the block is on the main chain and the second indicates
  41  // whether or not the block is an orphan.
  42  //
  43  // This function is safe for concurrent access.
  44  func (b *BlockChain) ProcessBlock(
  45  	workerNumber uint32, candidateBlock *block.Block,
  46  	flags BehaviorFlags, blockHeight int32,
  47  ) (bool, bool, error,) {
  48  	T.Ln("blockchain.ProcessBlock", blockHeight, log.Caller("\nfrom", 1))
  49  	var prevBlock *block.Block
  50  	var e error
  51  	prevBlock, e = b.BlockByHash(&candidateBlock.WireBlock().Header.PrevBlock)
  52  	if prevBlock != nil {
  53  		blockHeight = prevBlock.Height() + 1
  54  	} else {
  55  		return false, false, e
  56  	}
  57  	// trc.S(prevBlock)
  58  	b.ChainLock.Lock()
  59  	defer b.ChainLock.Unlock()
  60  	fastAdd := flags&BFFastAdd == BFFastAdd
  61  	blockHash := candidateBlock.Hash()
  62  	hf := fork.GetCurrent(blockHeight)
  63  	bhwa := candidateBlock.WireBlock().BlockHashWithAlgos
  64  	var algo int32
  65  	switch hf {
  66  	case 0:
  67  		if candidateBlock.WireBlock().Header.Version != 514 {
  68  			algo = 2
  69  		} else {
  70  			algo = 514
  71  		}
  72  	case 1:
  73  		algo = candidateBlock.WireBlock().Header.Version
  74  	}
  75  	// The candidateBlock must not already exist in the main chain or side chains.
  76  	var exists bool
  77  	if exists, e = b.blockExists(blockHash); E.Chk(e) {
  78  		return false, false, e
  79  	}
  80  	if exists {
  81  		str := ruleError(ErrDuplicateBlock, fmt.Sprintf("already have candidateBlock %v", bhwa(blockHeight).String()))
  82  		E.Ln(str)
  83  		return false, false, str
  84  	}
  85  	// The candidateBlock must not already exist as an orphan.
  86  	if _, exists := b.orphans[*blockHash]; exists {
  87  		str := ruleError(ErrDuplicateBlock, fmt.Sprintf("already have candidateBlock (orphan)"))
  88  		E.Ln(str)
  89  		return false, false, str
  90  	}
  91  	// Perform preliminary sanity checks on the candidateBlock and its transactions.
  92  	var DoNotCheckPow bool
  93  	pl := fork.GetMinDiff(fork.GetAlgoName(algo, blockHeight), blockHeight)
  94  	T.F("powLimit %d %s %d %064x", algo, fork.GetAlgoName(algo, blockHeight), blockHeight, pl)
  95  	ph := &candidateBlock.WireBlock().Header.PrevBlock
  96  	pn := b.Index.LookupNode(ph)
  97  	if pn == nil {
  98  		return false, false, errors.New("could not find parent block of candidate block")
  99  	}
 100  	var pb *BlockNode
 101  	pb = pn.GetLastWithAlgo(algo)
 102  	if pb == nil {
 103  		DoNotCheckPow = true
 104  	}
 105  	T.F("checkBlockSanity powLimit %d %s %d %064x ts %v", algo, fork.GetAlgoName(algo, blockHeight), blockHeight, pl,
 106  		pn.Header().Timestamp,
 107  	)
 108  	if e = checkBlockSanity(
 109  		candidateBlock,
 110  		pl,
 111  		b.timeSource,
 112  		flags,
 113  		DoNotCheckPow,
 114  		blockHeight,
 115  		pn.Header().Timestamp,
 116  	); E.Chk(e) {
 117  		return false, false, e
 118  	}
 119  	T.Ln("searching back to checkpoints")
 120  	// Find the previous checkpoint and perform some additional checks based on the
 121  	// checkpoint. This provides a few nice properties such as preventing old side
 122  	// chain blocks before the last checkpoint, rejecting easy to mine, but
 123  	// otherwise bogus, blocks that could be used to eat memory, and ensuring
 124  	// expected (versus claimed) proof of work requirements since the previous
 125  	// checkpoint are met.
 126  	blockHeader := &candidateBlock.WireBlock().Header
 127  	var checkpointNode *BlockNode
 128  	if checkpointNode, e = b.findPreviousCheckpoint(); E.Chk(e) {
 129  		return false, false, e
 130  	}
 131  	if checkpointNode != nil {
 132  		// Ensure the candidateBlock timestamp is after the checkpoint timestamp.
 133  		checkpointTime := time.Unix(checkpointNode.timestamp, 0)
 134  		if blockHeader.Timestamp.Before(checkpointTime) {
 135  			str := fmt.Sprintf(
 136  				"candidateBlock %v has timestamp %v before last checkpoint timestamp %v",
 137  				bhwa(blockHeight).String(), blockHeader.Timestamp, checkpointTime,
 138  			)
 139  			T.Ln(str)
 140  			return false, false, ruleError(ErrCheckpointTimeTooOld, str)
 141  		}
 142  		if !fastAdd {
 143  			// Even though the checks prior to now have already ensured the proof of work
 144  			// exceeds the claimed amount, the claimed amount is a field in the candidateBlock header
 145  			// which could be forged. This check ensures the proof of work is at least the
 146  			// minimum expected based on elapsed time since the last checkpoint and maximum
 147  			// adjustment allowed by the retarget rules.
 148  			duration := blockHeader.Timestamp.Sub(checkpointTime)
 149  			requiredTarget := bits.CompactToBig(
 150  				b.calcEasiestDifficulty(
 151  					checkpointNode.bits, duration,
 152  				),
 153  			)
 154  			currentTarget := bits.CompactToBig(blockHeader.Bits)
 155  			if currentTarget.Cmp(requiredTarget) > 0 {
 156  				str := fmt.Sprintf(
 157  					"processing: candidateBlock target difficulty of %064x is too low when compared to the"+
 158  						" previous checkpoint", currentTarget,
 159  				)
 160  				E.Ln(str)
 161  				return false, false, ruleError(ErrDifficultyTooLow, str)
 162  			}
 163  		}
 164  	}
 165  	T.Ln("handling orphans")
 166  	// Handle orphan blocks.
 167  	prevHash := &blockHeader.PrevBlock
 168  	var prevHashExists bool
 169  	if prevHashExists, e = b.blockExists(prevHash); E.Chk(e) {
 170  		return false, false, e
 171  	}
 172  	if !prevHashExists {
 173  		D.C(
 174  			func() string {
 175  				return fmt.Sprintf(
 176  					"adding orphan candidateBlock %v with parent %v",
 177  					bhwa(blockHeight).String(),
 178  					prevHash,
 179  				)
 180  			},
 181  		)
 182  		b.addOrphanBlock(candidateBlock)
 183  		return false, true, nil
 184  	}
 185  	// The candidateBlock has passed all context independent checks and appears sane enough
 186  	// to potentially accept it into the candidateBlock chain.
 187  	T.Ln("maybe accept candidateBlock")
 188  	var isMainChain bool
 189  	if isMainChain, e = b.maybeAcceptBlock(workerNumber, candidateBlock, flags); E.Chk(e) {
 190  		return false, false, e
 191  	}
 192  	// Accept any orphan blocks that depend on this candidateBlock (they are no longer
 193  	// orphans) and repeat for those accepted blocks until there are no more.
 194  	if isMainChain {
 195  		T.Ln("new candidateBlock on main chain")
 196  		// Traces(candidateBlock)
 197  	}
 198  	if e = b.processOrphans(workerNumber, blockHash, flags); E.Chk(e) {
 199  		return false, false, e
 200  	}
 201  	T.F(
 202  		"accepted candidateBlock %d %v %s",
 203  		blockHeight, bhwa(blockHeight).String(), fork.GetAlgoName(
 204  			candidateBlock.WireBlock().
 205  				Header.Version, blockHeight,
 206  		),
 207  	)
 208  	T.Ln("finished blockchain.ProcessBlock")
 209  	return isMainChain, false, nil
 210  }
 211  
 212  // blockExists determines whether a block with the given hash exists either in
 213  // the main chain or any side chains.
 214  //
 215  // This function is safe for concurrent access.
 216  func (b *BlockChain) blockExists(hash *chainhash.Hash) (exists bool, e error) {
 217  	// Chk block index first (could be main chain or side chain blocks).
 218  	if b.Index.HaveBlock(hash) {
 219  		return true, nil
 220  	}
 221  	// Check in the database.
 222  	e = b.db.View(
 223  		func(dbTx database.Tx) (e error) {
 224  			exists, e = dbTx.HasBlock(hash)
 225  			if e != nil || !exists {
 226  				return e
 227  			}
 228  			// Ignore side chain blocks in the database. This is necessary because there is
 229  			// not currently any record of the associated block index data such as its block
 230  			// height, so it's not yet possible to efficiently load the block and do
 231  			// anything useful with it. Ultimately the entire block index should be
 232  			// serialized instead of only the current main chain so it can be consulted
 233  			// directly.
 234  			if _, e = dbFetchHeightByHash(dbTx, hash); E.Chk(e) {
 235  			}
 236  			if isNotInMainChainErr(e) {
 237  				exists = false
 238  				return nil
 239  			}
 240  			return e
 241  		},
 242  	)
 243  	return exists, e
 244  }
 245  
 246  // processOrphans determines if there are any orphans which depend on the passed
 247  // block hash (they are no longer orphans if true) and potentially accepts them.
 248  // It repeats the process for the newly accepted blocks ( to detect further
 249  // orphans which may no longer be orphans) until there are no more. The flags do
 250  // not modify the behavior of this function directly, however they are needed to
 251  // pass along to maybeAcceptBlock.
 252  //
 253  // This function MUST be called with the chain state lock held (for writes).
 254  func (b *BlockChain) processOrphans(
 255  	workerNumber uint32, hash *chainhash.Hash,
 256  	flags BehaviorFlags,
 257  ) (e error) {
 258  	// Start with processing at least the passed hash. Leave a little room for
 259  	// additional orphan blocks that need to be processed without needing to grow
 260  	// the array in the common case.
 261  	processHashes := make([]*chainhash.Hash, 0, 10)
 262  	processHashes = append(processHashes, hash)
 263  	for len(processHashes) > 0 {
 264  		// Pop the first hash to process from the slice.
 265  		processHash := processHashes[0]
 266  		processHashes[0] = nil // Prevent GC leak.
 267  		processHashes = processHashes[1:]
 268  		// Look up all orphans that are parented by the block we just accepted. This
 269  		// will typically only be one, but it could be multiple if multiple blocks are
 270  		// mined and broadcast around the same time. The one with the most proof of work
 271  		// will eventually win out. An indexing for loop is intentionally used over a
 272  		// range here as range does not reevaluate the slice on each iteration nor does
 273  		// it adjust the index for the modified slice.
 274  		for i := 0; i < len(b.prevOrphans[*processHash]); i++ {
 275  			orphan := b.prevOrphans[*processHash][i]
 276  			if orphan == nil {
 277  				D.F(
 278  					"found a nil entry at index %d in the orphan dependency list for block %v",
 279  					i, processHash,
 280  				)
 281  				continue
 282  			}
 283  			// Remove the orphan from the orphan pool.
 284  			orphanHash := orphan.block.Hash()
 285  			b.removeOrphanBlock(orphan)
 286  			i--
 287  			// Potentially accept the block into the block chain.
 288  			var e error
 289  			if _, e = b.maybeAcceptBlock(workerNumber, orphan.block, flags); E.Chk(e) {
 290  				return e
 291  			}
 292  			// Add this block to the list of blocks to process so any orphan blocks that
 293  			// depend on this block are handled too.
 294  			processHashes = append(processHashes, orphanHash)
 295  		}
 296  	}
 297  	return nil
 298  }
 299