github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/btcutil/blockchain/accept.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 "github.com/mit-dci/lit/btcutil" 8 9 // maybeAcceptBlock potentially accepts a block into the block chain and, if 10 // accepted, returns whether or not it is on the main chain. It performs 11 // several validation checks which depend on its position within the block chain 12 // before adding it. The block is expected to have already gone through 13 // ProcessBlock before calling this function with it. 14 // 15 // The flags modify the behavior of this function as follows: 16 // - BFDryRun: The memory chain index will not be pruned and no accept 17 // notification will be sent since the block is not being accepted. 18 // 19 // The flags are also passed to checkBlockContext and connectBestChain. See 20 // their documentation for how the flags modify their behavior. 21 // 22 // This function MUST be called with the chain state lock held (for writes). 23 func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { 24 dryRun := flags&BFDryRun == BFDryRun 25 26 // Get a block node for the block previous to this one. Will be nil 27 // if this is the genesis block. 28 prevNode, err := b.getPrevNodeFromBlock(block) 29 if err != nil { 30 return false, err 31 } 32 33 // The height of this block is one more than the referenced previous 34 // block. 35 blockHeight := int32(0) 36 if prevNode != nil { 37 blockHeight = prevNode.height + 1 38 } 39 block.SetHeight(blockHeight) 40 41 // The block must pass all of the validation rules which depend on the 42 // position of the block within the block chain. 43 err = b.checkBlockContext(block, prevNode, flags) 44 if err != nil { 45 return false, err 46 } 47 48 // Prune block nodes which are no longer needed before creating 49 // a new node. 50 if !dryRun { 51 err = b.pruneBlockNodes() 52 if err != nil { 53 return false, err 54 } 55 } 56 57 // Create a new block node for the block and add it to the in-memory 58 // block chain (could be either a side chain or the main chain). 59 blockHeader := &block.MsgBlock().Header 60 newNode := newBlockNode(blockHeader, block.Hash(), blockHeight) 61 if prevNode != nil { 62 newNode.parent = prevNode 63 newNode.height = blockHeight 64 newNode.workSum.Add(prevNode.workSum, newNode.workSum) 65 } 66 67 // Connect the passed block to the chain while respecting proper chain 68 // selection according to the chain with the most proof of work. This 69 // also handles validation of the transaction scripts. 70 isMainChain, err := b.connectBestChain(newNode, block, flags) 71 if err != nil { 72 return false, err 73 } 74 75 // Notify the caller that the new block was accepted into the block 76 // chain. The caller would typically want to react by relaying the 77 // inventory to other peers. 78 if !dryRun { 79 b.chainLock.Unlock() 80 b.sendNotification(NTBlockAccepted, block) 81 b.chainLock.Lock() 82 } 83 84 return isMainChain, nil 85 }