github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/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/BlockABC/godash/database" 12 "github.com/BlockABC/godash/wire" 13 "github.com/BlockABC/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 }