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