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