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  }