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 }