// indexBlock extract all of the standard addresses from all of the transactions // in the passed block and maps each of them to the assocaited transaction using // the passed map. func (idx *AddrIndex) indexBlock(data writeIndexData, block *btcutil.Block, view *blockchain.UtxoViewpoint) { for txIdx, tx := range block.Transactions() { // Coinbases do not reference any inputs. Since the block is // required to have already gone through full validation, it has // already been proven on the first transaction in the block is // a coinbase. if txIdx != 0 { for _, txIn := range tx.MsgTx().TxIn { // The view should always have the input since // the index contract requires it, however, be // safe and simply ignore any missing entries. origin := &txIn.PreviousOutPoint entry := view.LookupEntry(&origin.Hash) if entry == nil { continue } pkScript := entry.PkScriptByIndex(origin.Index) idx.indexPkScript(data, pkScript, txIdx) } } for _, txOut := range tx.MsgTx().TxOut { idx.indexPkScript(data, txOut.PkScript, txIdx) } } }
// ConnectBlock is invoked by the index manager when a new block has been // connected to the main chain. This indexer adds a mapping for each address // the transactions in the block involve. // // This is part of the Indexer interface. func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { // The offset and length of the transactions within the serialized // block. txLocs, err := block.TxLoc() if err != nil { return err } // Get the internal block ID associated with the block. blockID, err := dbFetchBlockIDByHash(dbTx, block.Hash()) if err != nil { return err } // Build all of the address to transaction mappings in a local map. addrsToTxns := make(writeIndexData) idx.indexBlock(addrsToTxns, block, view) // Add all of the index entries for each address. addrIdxBucket := dbTx.Metadata().Bucket(addrIndexKey) for addrKey, txIdxs := range addrsToTxns { for _, txIdx := range txIdxs { err := dbPutAddrIndexEntry(addrIdxBucket, addrKey, blockID, txLocs[txIdx]) if err != nil { return err } } } return nil }
// checkBIP0030 ensures blocks do not contain duplicate transactions which // 'overwrite' older transactions that are not fully spent. This prevents an // attack where a coinbase and all of its dependent transactions could be // duplicated to effectively revert the overwritten transactions to a single // confirmation thereby making them vulnerable to a double spend. // // For more details, see https://en.bitcoin.it/wiki/BIP_0030 and // http://r6.ca/blog/20120206T005236Z.html. // // This function MUST be called with the chain state lock held (for reads). func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block, view *UtxoViewpoint) error { // Fetch utxo details for all of the transactions in this block. // Typically, there will not be any utxos for any of the transactions. fetchSet := make(map[chainhash.Hash]struct{}) for _, tx := range block.Transactions() { fetchSet[*tx.Hash()] = struct{}{} } err := view.fetchUtxos(b.db, fetchSet) if err != nil { return err } // Duplicate transactions are only allowed if the previous transaction // is fully spent. for _, tx := range block.Transactions() { txEntry := view.LookupEntry(tx.Hash()) if txEntry != nil && !txEntry.IsFullySpent() { str := fmt.Sprintf("tried to overwrite transaction %v "+ "at block height %d that is not fully spent", tx.Hash(), txEntry.blockHeight) return ruleError(ErrOverwriteTx, str) } } return nil }
// makeUtxoView creates a mock unspent transaction output view by using the // transaction index in order to look up all inputs referenced by the // transactions in the block. This is sometimes needed when catching indexes up // because many of the txouts could actually already be spent however the // associated scripts are still required to index them. func makeUtxoView(dbTx database.Tx, block *btcutil.Block) (*blockchain.UtxoViewpoint, error) { view := blockchain.NewUtxoViewpoint() for txIdx, tx := range block.Transactions() { // Coinbases do not reference any inputs. Since the block is // required to have already gone through full validation, it has // already been proven on the first transaction in the block is // a coinbase. if txIdx == 0 { continue } // Use the transaction index to load all of the referenced // inputs and add their outputs to the view. for _, txIn := range tx.MsgTx().TxIn { originOut := &txIn.PreviousOutPoint originTx, err := dbFetchTx(dbTx, &originOut.Hash) if err != nil { return nil, err } view.AddTxOuts(btcutil.NewTx(originTx), 0) } } return view, nil }
// GetBlockWeight computes the value of the weight metric for a given block. // Currently the weight metric is simply the sum of the block's serialized size // without any witness data scaled proportionally by the WitnessScaleFactor, // and the block's serialized size including any witness data. func GetBlockWeight(blk *btcutil.Block) int64 { msgBlock := blk.MsgBlock() baseSize := msgBlock.SerializeSizeStripped() totalSize := msgBlock.SerializeSize() // (baseSize * 3) + totalSize return int64((baseSize * (WitnessScaleFactor - 1)) + totalSize) }
func assertTxInBlock(t *harnessTest, block *btcutil.Block, txid *wire.ShaHash) { for _, tx := range block.Transactions() { if bytes.Equal(txid[:], tx.Sha()[:]) { return } } t.Fatalf("funding tx was not included in block") }
// dbRemoveTxIndexEntries uses an existing database transaction to remove the // latest transaction entry for every transaction in the passed block. func dbRemoveTxIndexEntries(dbTx database.Tx, block *btcutil.Block) error { for _, tx := range block.Transactions() { err := dbRemoveTxIndexEntry(dbTx, tx.Hash()) if err != nil { return err } } return nil }
// DisconnectBlock is invoked by the index manager when a block has been // disconnected from the main chain. This indexer removes the // hash-to-transaction mapping for every transaction in the block. // // This is part of the Indexer interface. func (idx *TxIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { // Remove all of the transactions in the block from the index. if err := dbRemoveTxIndexEntries(dbTx, block); err != nil { return err } // Remove the block ID index entry for the block being disconnected and // decrement the current internal block ID to account for it. if err := dbRemoveBlockIDIndexEntry(dbTx, block.Hash()); err != nil { return err } idx.curBlockID-- return nil }
// dbIndexDisconnectBlock removes all of the index entries associated with the // given block using the provided indexer and updates the tip of the indexer // accordingly. An error will be returned if the current tip for the indexer is // not the passed block. func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { // Assert that the block being disconnected is the current tip of the // index. idxKey := indexer.Key() curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey) if err != nil { return err } if !curTipHash.IsEqual(block.Hash()) { return AssertError(fmt.Sprintf("dbIndexDisconnectBlock must "+ "be called with the block at the current index tip "+ "(%s, tip %s, block %s)", indexer.Name(), curTipHash, block.Hash())) } // Notify the indexer with the disconnected block so it can remove all // of the appropriate entries. if err := indexer.DisconnectBlock(dbTx, block, view); err != nil { return err } // Update the current index tip. prevHash := &block.MsgBlock().Header.PrevBlock return dbPutIndexerTip(dbTx, idxKey, prevHash, block.Height()-1) }
// fetchInputUtxos loads utxo details about the input transactions referenced // by the transactions in the given block into the view from the database as // needed. In particular, referenced entries that are earlier in the block are // added to the view and entries that are already in the view are not modified. func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *btcutil.Block) error { // Build a map of in-flight transactions because some of the inputs in // this block could be referencing other transactions earlier in this // block which are not yet in the chain. txInFlight := map[chainhash.Hash]int{} transactions := block.Transactions() for i, tx := range transactions { txInFlight[*tx.Hash()] = i } // Loop through all of the transaction inputs (except for the coinbase // which has no inputs) collecting them into sets of what is needed and // what is already known (in-flight). txNeededSet := make(map[chainhash.Hash]struct{}) for i, tx := range transactions[1:] { for _, txIn := range tx.MsgTx().TxIn { // It is acceptable for a transaction input to reference // the output of another transaction in this block only // if the referenced transaction comes before the // current one in this block. Add the outputs of the // referenced transaction as available utxos when this // is the case. Otherwise, the utxo details are still // needed. // // NOTE: The >= is correct here because i is one less // than the actual position of the transaction within // the block due to skipping the coinbase. originHash := &txIn.PreviousOutPoint.Hash if inFlightIndex, ok := txInFlight[*originHash]; ok && i >= inFlightIndex { originTx := transactions[inFlightIndex] view.AddTxOuts(originTx, block.Height()) continue } // Don't request entries that are already in the view // from the database. if _, ok := view.entries[*originHash]; ok { continue } txNeededSet[*originHash] = struct{}{} } } // Request the input utxos from the database. return view.fetchUtxosMain(db, txNeededSet) }
// CheckConnectBlock performs several checks to confirm connecting the passed // block to the main chain does not violate any rules. An example of some of // the checks performed are ensuring connecting the block would not cause any // duplicate transaction hashes for old transactions that aren't already fully // spent, double spends, exceeding the maximum allowed signature operations // per block, invalid values in relation to the expected block subsidy, or fail // transaction script validation. // // This function is safe for concurrent access. func (b *BlockChain) CheckConnectBlock(block *btcutil.Block) error { b.chainLock.Lock() defer b.chainLock.Unlock() prevNode := b.bestNode newNode := newBlockNode(&block.MsgBlock().Header, block.Hash(), prevNode.height+1) newNode.parent = prevNode newNode.workSum.Add(prevNode.workSum, newNode.workSum) // Leave the spent txouts entry nil in the state since the information // is not needed and thus extra work can be avoided. view := NewUtxoViewpoint() view.SetBestHash(prevNode.hash) return b.checkConnectBlock(newNode, block, view, nil) }
// ConnectBlock is invoked by the index manager when a new block has been // connected to the main chain. This indexer adds a hash-to-transaction mapping // for every transaction in the passed block. // // This is part of the Indexer interface. func (idx *TxIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { // Increment the internal block ID to use for the block being connected // and add all of the transactions in the block to the index. newBlockID := idx.curBlockID + 1 if err := dbAddTxIndexEntries(dbTx, block, newBlockID); err != nil { return err } // Add the new block ID index entry for the block being connected and // update the current internal block ID accordingly. err := dbPutBlockIDIndexEntry(dbTx, block.Hash(), newBlockID) if err != nil { return err } idx.curBlockID = newBlockID return nil }
// LogBlockHeight logs a new block height as an information message to show // progress to the user. In order to prevent spam, it limits logging to one // message every 10 seconds with duration and totals included. func (b *blockProgressLogger) LogBlockHeight(block *btcutil.Block) { b.Lock() defer b.Unlock() b.receivedLogBlocks++ b.receivedLogTx += int64(len(block.MsgBlock().Transactions)) now := time.Now() duration := now.Sub(b.lastBlockLogTime) if duration < time.Second*10 { return } // Truncate the duration to 10s of milliseconds. durationMillis := int64(duration / time.Millisecond) tDuration := 10 * time.Millisecond * time.Duration(durationMillis/10) // Log information about new block height. blockStr := "blocks" if b.receivedLogBlocks == 1 { blockStr = "block" } txStr := "transactions" if b.receivedLogTx == 1 { txStr = "transaction" } b.subsystemLogger.Infof("%s %d %s in the last %s (%d %s, height %d, %s)", b.progressAction, b.receivedLogBlocks, blockStr, tDuration, b.receivedLogTx, txStr, block.Height(), block.MsgBlock().Header.Timestamp) b.receivedLogBlocks = 0 b.receivedLogTx = 0 b.lastBlockLogTime = now }
// dbAddTxIndexEntries uses an existing database transaction to add a // transaction index entry for every transaction in the passed block. func dbAddTxIndexEntries(dbTx database.Tx, block *btcutil.Block, blockID uint32) error { // The offset and length of the transactions within the serialized // block. txLocs, err := block.TxLoc() if err != nil { return err } // As an optimization, allocate a single slice big enough to hold all // of the serialized transaction index entries for the block and // serialize them directly into the slice. Then, pass the appropriate // subslice to the database to be written. This approach significantly // cuts down on the number of required allocations. offset := 0 serializedValues := make([]byte, len(block.Transactions())*txEntrySize) for i, tx := range block.Transactions() { putTxIndexEntry(serializedValues[offset:], blockID, txLocs[i]) endOffset := offset + txEntrySize err := dbPutTxIndexEntry(dbTx, tx.Hash(), serializedValues[offset:endOffset:endOffset]) if err != nil { return err } offset += txEntrySize } return nil }
// ValidateWitnessCommitment validates the witness commitment (if any) found // within the coinbase transaction of the passed block. func ValidateWitnessCommitment(blk *btcutil.Block) error { coinbaseTx := blk.Transactions()[0] witnessCommitment, witnessFound := ExtractWitnessCommitment(coinbaseTx) // If we can't find a witness commitment in any of the coinbase's // outputs, then the block MUST NOT contain any transactions with // witness data. if !witnessFound { for _, tx := range blk.Transactions() { msgTx := tx.MsgTx() if msgTx.HasWitness() { str := fmt.Sprintf("block contains transaction with witness" + " data, yet no witness commitment present") return ruleError(ErrUnexpectedWitness, str) } } return nil } // At this point the block contains a witness commitment, so the // coinbase transaction MUST have exactly one witness element within // its witness data and that element must be exactly // CoinbaseWitnessDataLen bytes. coinbaseWitness := coinbaseTx.MsgTx().TxIn[0].Witness if len(coinbaseWitness) != 1 { str := fmt.Sprintf("the coinbase transaction has %d items in "+ "its witness stack when only one is allowed", len(coinbaseWitness)) return ruleError(ErrInvalidWitnessCommitment, str) } witnessNonce := coinbaseWitness[0] if len(witnessNonce) != CoinbaseWitnessDataLen { str := fmt.Sprintf("the coinbase transaction witness nonce "+ "has %d bytes when it must be %d bytes", len(witnessNonce), CoinbaseWitnessDataLen) return ruleError(ErrInvalidWitnessCommitment, str) } // Finally, with the preliminary checks out of the way, we can check if // the extracted witnessCommitment is equal to: // SHA256(witnessMerkleRoot || witnessNonce). Where witnessNonce is the // coinbase transaction's only witness item. witnessMerkleTree := BuildMerkleTreeStore(blk.Transactions(), true) witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1] witnessPreimage := make([]byte, 64) copy(witnessPreimage[:], witnessMerkleRoot[:]) copy(witnessPreimage[32:], witnessNonce) if !bytes.Equal(chainhash.DoubleHashB(witnessPreimage), witnessCommitment) { str := "witness commitment does not match" return ruleError(ErrWitnessCommitmentMismatch, str) } return nil }
// maybeAcceptBlock potentially accepts a block into the block chain and, if // accepted, returns whether or not it is on the main chain. It performs // several validation checks which depend on its position within the block chain // before adding it. The block is expected to have already gone through // ProcessBlock before calling this function with it. // // The flags modify the behavior of this function as follows: // - BFDryRun: The memory chain index will not be pruned and no accept // notification will be sent since the block is not being accepted. // // The flags are also passed to checkBlockContext and connectBestChain. See // their documentation for how the flags modify their behavior. // // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error) { dryRun := flags&BFDryRun == BFDryRun // Get a block node for the block previous to this one. Will be nil // if this is the genesis block. prevNode, err := b.getPrevNodeFromBlock(block) if err != nil { log.Errorf("getPrevNodeFromBlock: %v", err) return false, err } // The height of this block is one more than the referenced previous // block. blockHeight := int32(0) if prevNode != nil { blockHeight = prevNode.height + 1 } block.SetHeight(blockHeight) // The block must pass all of the validation rules which depend on the // position of the block within the block chain. err = b.checkBlockContext(block, prevNode, flags) if err != nil { return false, err } // Create a new block node for the block and add it to the in-memory // block chain (could be either a side chain or the main chain). blockHeader := &block.MsgBlock().Header newNode := newBlockNode(blockHeader, block.Hash(), blockHeight) if prevNode != nil { newNode.parent = prevNode newNode.height = blockHeight newNode.workSum.Add(prevNode.workSum, newNode.workSum) } // Connect the passed block to the chain while respecting proper chain // selection according to the chain with the most proof of work. This // also handles validation of the transaction scripts. isMainChain, err := b.connectBestChain(newNode, block, flags) if err != nil { return false, err } // Notify the caller that the new block was accepted into the block // chain. The caller would typically want to react by relaying the // inventory to other peers. if !dryRun { b.chainLock.Unlock() b.sendNotification(NTBlockAccepted, block) b.chainLock.Lock() } return isMainChain, nil }
// connectTransactions updates the view by adding all new utxos created by all // of the transactions in the passed block, marking all utxos the transactions // spend as spent, and setting the best hash for the view to the passed block. // In addition, when the 'stxos' argument is not nil, it will be updated to // append an entry for each spent txout. func (view *UtxoViewpoint) connectTransactions(block *btcutil.Block, stxos *[]spentTxOut) error { for _, tx := range block.Transactions() { err := view.connectTransaction(tx, block.Height(), stxos) if err != nil { return err } } // Update the best hash for view to include this block since all of its // transactions have been connected. view.SetBestHash(block.Hash()) return nil }
// dbIndexConnectBlock adds all of the index entries associated with the // given block using the provided indexer and updates the tip of the indexer // accordingly. An error will be returned if the current tip for the indexer is // not the previous block for the passed block. func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { // Assert that the block being connected properly connects to the // current tip of the index. idxKey := indexer.Key() curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey) if err != nil { return err } if !curTipHash.IsEqual(&block.MsgBlock().Header.PrevBlock) { return AssertError(fmt.Sprintf("dbIndexConnectBlock must be "+ "called with a block that extends the current index "+ "tip (%s, tip %s, block %s)", indexer.Name(), curTipHash, block.Hash())) } // Notify the indexer with the connected block so it can index it. if err := indexer.ConnectBlock(dbTx, block, view); err != nil { return err } // Update the current index tip. return dbPutIndexerTip(dbTx, idxKey, block.Hash(), block.Height()) }
// submitBlock submits the passed block to network after ensuring it passes all // of the consensus validation rules. func (m *CPUMiner) submitBlock(block *btcutil.Block) bool { m.submitBlockLock.Lock() defer m.submitBlockLock.Unlock() // Ensure the block is not stale since a new block could have shown up // while the solution was being found. Typically that condition is // detected and all work on the stale block is halted to start work on // a new block, but the check only happens periodically, so it is // possible a block was found and submitted in between. msgBlock := block.MsgBlock() if !msgBlock.Header.PrevBlock.IsEqual(m.g.BestSnapshot().Hash) { log.Debugf("Block submitted via CPU miner with previous "+ "block %s is stale", msgBlock.Header.PrevBlock) return false } // Process this block using the same rules as blocks coming from other // nodes. This will in turn relay it to the network like normal. isOrphan, err := m.cfg.ProcessBlock(block, blockchain.BFNone) if err != nil { // Anything other than a rule violation is an unexpected error, // so log that error as an internal error. if _, ok := err.(blockchain.RuleError); !ok { log.Errorf("Unexpected error while processing "+ "block submitted via CPU miner: %v", err) return false } log.Debugf("Block submitted via CPU miner rejected: %v", err) return false } if isOrphan { log.Debugf("Block submitted via CPU miner is an orphan") return false } // The block was accepted. coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0] log.Infof("Block submitted via CPU miner accepted (hash %s, "+ "amount %v)", block.Hash(), btcutil.Amount(coinbaseTx.Value)) return true }
// CreateBlock creates a new block building from the previous block with a // specified blockversion and timestamp. If the timestamp passed is zero (not // initialized), then the timestamp of the previous block will be used plus 1 // second is used. Passing nil for the previous block results in a block that // builds off of the genesis block for the specified chain. func CreateBlock(prevBlock *btcutil.Block, inclusionTxs []*btcutil.Tx, blockVersion int32, blockTime time.Time, miningAddr btcutil.Address, net *chaincfg.Params) (*btcutil.Block, error) { var ( prevHash *chainhash.Hash blockHeight int32 prevBlockTime time.Time ) // If the previous block isn't specified, then we'll construct a block // that builds off of the genesis block for the chain. if prevBlock == nil { prevHash = net.GenesisHash blockHeight = 1 prevBlockTime = net.GenesisBlock.Header.Timestamp.Add(time.Minute) } else { prevHash = prevBlock.Hash() blockHeight = prevBlock.Height() + 1 prevBlockTime = prevBlock.MsgBlock().Header.Timestamp } // If a target block time was specified, then use that as the header's // timestamp. Otherwise, add one second to the previous block unless // it's the genesis block in which case use the current time. var ts time.Time switch { case !blockTime.IsZero(): ts = blockTime default: ts = prevBlockTime.Add(time.Second) } extraNonce := uint64(0) coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce) if err != nil { return nil, err } coinbaseTx, err := createCoinbaseTx(coinbaseScript, blockHeight, miningAddr, net) if err != nil { return nil, err } // Create a new block ready to be solved. blockTxns := []*btcutil.Tx{coinbaseTx} if inclusionTxs != nil { blockTxns = append(blockTxns, inclusionTxs...) } merkles := blockchain.BuildMerkleTreeStore(blockTxns, false) var block wire.MsgBlock block.Header = wire.BlockHeader{ Version: blockVersion, PrevBlock: *prevHash, MerkleRoot: *merkles[len(merkles)-1], Timestamp: ts, Bits: net.PowLimitBits, } for _, tx := range blockTxns { if err := block.AddTransaction(tx.MsgTx()); err != nil { return nil, err } } found := solveBlock(&block.Header, net.PowLimit) if !found { return nil, errors.New("Unable to solve block") } utilBlock := btcutil.NewBlock(&block) utilBlock.SetHeight(blockHeight) return utilBlock, nil }
// ProcessBlock is the main workhorse for handling insertion of new blocks into // the block chain. It includes functionality such as rejecting duplicate // blocks, ensuring blocks follow all rules, orphan handling, and insertion into // the block chain along with best chain selection and reorganization. // // When no errors occurred during processing, the first return value indicates // whether or not the block is on the main chain and the second indicates // whether or not the block is an orphan. // // This function is safe for concurrent access. func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bool, bool, error) { b.chainLock.Lock() defer b.chainLock.Unlock() fastAdd := flags&BFFastAdd == BFFastAdd dryRun := flags&BFDryRun == BFDryRun blockHash := block.Hash() log.Tracef("Processing block %v", blockHash) // The block must not already exist in the main chain or side chains. exists, err := b.blockExists(blockHash) if err != nil { return false, false, err } if exists { str := fmt.Sprintf("already have block %v", blockHash) return false, false, ruleError(ErrDuplicateBlock, str) } // The block must not already exist as an orphan. if _, exists := b.orphans[*blockHash]; exists { str := fmt.Sprintf("already have block (orphan) %v", blockHash) return false, false, ruleError(ErrDuplicateBlock, str) } // Perform preliminary sanity checks on the block and its transactions. err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags) if err != nil { return false, false, err } // Find the previous checkpoint and perform some additional checks based // on the checkpoint. This provides a few nice properties such as // preventing old side chain blocks before the last checkpoint, // rejecting easy to mine, but otherwise bogus, blocks that could be // used to eat memory, and ensuring expected (versus claimed) proof of // work requirements since the previous checkpoint are met. blockHeader := &block.MsgBlock().Header checkpointBlock, err := b.findPreviousCheckpoint() if err != nil { return false, false, err } if checkpointBlock != nil { // Ensure the block timestamp is after the checkpoint timestamp. checkpointHeader := &checkpointBlock.MsgBlock().Header checkpointTime := checkpointHeader.Timestamp if blockHeader.Timestamp.Before(checkpointTime) { str := fmt.Sprintf("block %v has timestamp %v before "+ "last checkpoint timestamp %v", blockHash, blockHeader.Timestamp, checkpointTime) return false, false, ruleError(ErrCheckpointTimeTooOld, str) } if !fastAdd { // Even though the checks prior to now have already ensured the // proof of work exceeds the claimed amount, the claimed amount // is a field in the block header which could be forged. This // check ensures the proof of work is at least the minimum // expected based on elapsed time since the last checkpoint and // maximum adjustment allowed by the retarget rules. duration := blockHeader.Timestamp.Sub(checkpointTime) requiredTarget := CompactToBig(b.calcEasiestDifficulty( checkpointHeader.Bits, duration)) currentTarget := CompactToBig(blockHeader.Bits) if currentTarget.Cmp(requiredTarget) > 0 { str := fmt.Sprintf("block target difficulty of %064x "+ "is too low when compared to the previous "+ "checkpoint", currentTarget) return false, false, ruleError(ErrDifficultyTooLow, str) } } } // Handle orphan blocks. prevHash := &blockHeader.PrevBlock prevHashExists, err := b.blockExists(prevHash) if err != nil { return false, false, err } if !prevHashExists { if !dryRun { log.Infof("Adding orphan block %v with parent %v", blockHash, prevHash) b.addOrphanBlock(block) } return false, true, nil } // The block has passed all context independent checks and appears sane // enough to potentially accept it into the block chain. isMainChain, err := b.maybeAcceptBlock(block, flags) if err != nil { return false, false, err } // Don't process any orphans or log when the dry run flag is set. if !dryRun { // Accept any orphan blocks that depend on this block (they are // no longer orphans) and repeat for those accepted blocks until // there are no more. err := b.processOrphans(blockHash, flags) if err != nil { return false, false, err } log.Debugf("Accepted block %v", blockHash) } return isMainChain, false, nil }
// checkConnectBlock performs several checks to confirm connecting the passed // block to the chain represented by the passed view does not violate any rules. // In addition, the passed view is updated to spend all of the referenced // outputs and add all of the new utxos created by block. Thus, the view will // represent the state of the chain as if the block were actually connected and // consequently the best hash for the view is also updated to passed block. // // The CheckConnectBlock function makes use of this function to perform the // bulk of its work. The only difference is this function accepts a node which // may or may not require reorganization to connect it to the main chain whereas // CheckConnectBlock creates a new node which specifically connects to the end // of the current main chain and then calls this function with that node. // // See the comments for CheckConnectBlock for some examples of the type of // checks performed by this function. // // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos *[]spentTxOut) error { // If the side chain blocks end up in the database, a call to // CheckBlockSanity should be done here in case a previous version // allowed a block that is no longer valid. However, since the // implementation only currently uses memory for the side chain blocks, // it isn't currently necessary. // The coinbase for the Genesis block is not spendable, so just return // an error now. if node.hash.IsEqual(b.chainParams.GenesisHash) { str := "the coinbase for the genesis block is not spendable" return ruleError(ErrMissingTx, str) } // Ensure the view is for the node being checked. if !view.BestHash().IsEqual(node.parentHash) { return AssertError(fmt.Sprintf("inconsistent view when "+ "checking block connection: best hash is %v instead "+ "of expected %v", view.BestHash(), node.hash)) } // BIP0030 added a rule to prevent blocks which contain duplicate // transactions that 'overwrite' older transactions which are not fully // spent. See the documentation for checkBIP0030 for more details. // // There are two blocks in the chain which violate this rule, so the // check must be skipped for those blocks. The isBIP0030Node function // is used to determine if this block is one of the two blocks that must // be skipped. // // In addition, as of BIP0034, duplicate coinbases are no longer // possible due to its requirement for including the block height in the // coinbase and thus it is no longer possible to create transactions // that 'overwrite' older ones. Therefore, only enforce the rule if // BIP0034 is not yet active. This is a useful optimization because the // BIP0030 check is expensive since it involves a ton of cache misses in // the utxoset. if !isBIP0030Node(node) && (node.height < b.chainParams.BIP0034Height) { err := b.checkBIP0030(node, block, view) if err != nil { return err } } // Load all of the utxos referenced by the inputs for all transactions // in the block don't already exist in the utxo view from the database. // // These utxo entries are needed for verification of things such as // transaction inputs, counting pay-to-script-hashes, and scripts. err := view.fetchInputUtxos(b.db, block) if err != nil { return err } // BIP0016 describes a pay-to-script-hash type that is considered a // "standard" type. The rules for this BIP only apply to transactions // after the timestamp defined by txscript.Bip16Activation. See // https://en.bitcoin.it/wiki/BIP_0016 for more details. enforceBIP0016 := node.timestamp.After(txscript.Bip16Activation) // Query for the Version Bits state for the segwit soft-fork // deployment. If segwit is active, we'll switch over to enforcing all // the new rules. segwitState, err := b.deploymentState(node.parent, chaincfg.DeploymentSegwit) if err != nil { return err } enforceSegWit := segwitState == ThresholdActive // The number of signature operations must be less than the maximum // allowed per block. Note that the preliminary sanity checks on a // block also include a check similar to this one, but this check // expands the count to include a precise count of pay-to-script-hash // signature operations in each of the input transaction public key // scripts. transactions := block.Transactions() totalSigOpCost := 0 for i, tx := range transactions { // Since the first (and only the first) transaction has // already been verified to be a coinbase transaction, // use i == 0 as an optimization for the flag to // countP2SHSigOps for whether or not the transaction is // a coinbase transaction rather than having to do a // full coinbase check again. sigOpCost, err := GetSigOpCost(tx, i == 0, view, enforceBIP0016, enforceSegWit) if err != nil { return err } // Check for overflow or going over the limits. We have to do // this on every loop iteration to avoid overflow. lastSigOpCost := totalSigOpCost totalSigOpCost += sigOpCost if totalSigOpCost < lastSigOpCost || totalSigOpCost > MaxBlockSigOpsCost { str := fmt.Sprintf("block contains too many "+ "signature operations - got %v, max %v", totalSigOpCost, MaxBlockSigOpsCost) return ruleError(ErrTooManySigOps, str) } } // Perform several checks on the inputs for each transaction. Also // accumulate the total fees. This could technically be combined with // the loop above instead of running another loop over the transactions, // but by separating it we can avoid running the more expensive (though // still relatively cheap as compared to running the scripts) checks // against all the inputs when the signature operations are out of // bounds. var totalFees int64 for _, tx := range transactions { txFee, err := CheckTransactionInputs(tx, node.height, view, b.chainParams) if err != nil { return err } // Sum the total fees and ensure we don't overflow the // accumulator. lastTotalFees := totalFees totalFees += txFee if totalFees < lastTotalFees { return ruleError(ErrBadFees, "total fees for block "+ "overflows accumulator") } // Add all of the outputs for this transaction which are not // provably unspendable as available utxos. Also, the passed // spent txos slice is updated to contain an entry for each // spent txout in the order each transaction spends them. err = view.connectTransaction(tx, node.height, stxos) if err != nil { return err } } // The total output values of the coinbase transaction must not exceed // the expected subsidy value plus total transaction fees gained from // mining the block. It is safe to ignore overflow and out of range // errors here because those error conditions would have already been // caught by checkTransactionSanity. var totalSatoshiOut int64 for _, txOut := range transactions[0].MsgTx().TxOut { totalSatoshiOut += txOut.Value } expectedSatoshiOut := CalcBlockSubsidy(node.height, b.chainParams) + totalFees if totalSatoshiOut > expectedSatoshiOut { str := fmt.Sprintf("coinbase transaction for block pays %v "+ "which is more than expected value of %v", totalSatoshiOut, expectedSatoshiOut) return ruleError(ErrBadCoinbaseValue, str) } // Don't run scripts if this node is before the latest known good // checkpoint since the validity is verified via the checkpoints (all // transactions are included in the merkle root hash and any changes // will therefore be detected by the next checkpoint). This is a huge // optimization because running the scripts is the most time consuming // portion of block handling. checkpoint := b.latestCheckpoint() runScripts := !b.noVerify if checkpoint != nil && node.height <= checkpoint.Height { runScripts = false } // Blocks created after the BIP0016 activation time need to have the // pay-to-script-hash checks enabled. var scriptFlags txscript.ScriptFlags if enforceBIP0016 { scriptFlags |= txscript.ScriptBip16 } // Enforce DER signatures for block versions 3+ once the historical // activation threshold has been reached. This is part of BIP0066. blockHeader := &block.MsgBlock().Header if blockHeader.Version >= 3 && node.height >= b.chainParams.BIP0066Height { scriptFlags |= txscript.ScriptVerifyDERSignatures } // Enforce CHECKLOCKTIMEVERIFY for block versions 4+ once the historical // activation threshold has been reached. This is part of BIP0065. if blockHeader.Version >= 4 && node.height >= b.chainParams.BIP0065Height { scriptFlags |= txscript.ScriptVerifyCheckLockTimeVerify } // Enforce the segwit soft-fork package once the soft-fork has shifted // into the "active" version bits state. if enforceSegWit { scriptFlags |= txscript.ScriptVerifyWitness scriptFlags |= txscript.ScriptStrictMultiSig } // Enforce CHECKSEQUENCEVERIFY during all block validation checks once // the soft-fork deployment is fully active. csvState, err := b.deploymentState(node.parent, chaincfg.DeploymentCSV) if err != nil { return err } if csvState == ThresholdActive { // If the CSV soft-fork is now active, then modify the // scriptFlags to ensure that the CSV op code is properly // validated during the script checks bleow. scriptFlags |= txscript.ScriptVerifyCheckSequenceVerify // We obtain the MTP of the *previous* block in order to // determine if transactions in the current block are final. medianTime, err := b.calcPastMedianTime(node.parent) if err != nil { return err } // Additionally, if the CSV soft-fork package is now active, // then we also enforce the relative sequence number based // lock-times within the inputs of all transactions in this // candidate block. for _, tx := range block.Transactions() { // A transaction can only be included within a block // once the sequence locks of *all* its inputs are // active. sequenceLock, err := b.calcSequenceLock(node, tx, view, false) if err != nil { return err } if !SequenceLockActive(sequenceLock, node.height, medianTime) { str := fmt.Sprintf("block contains " + "transaction whose input sequence " + "locks are not met") return ruleError(ErrUnfinalizedTx, str) } } } // Now that the inexpensive checks are done and have passed, verify the // transactions are actually allowed to spend the coins by running the // expensive ECDSA signature check scripts. Doing this last helps // prevent CPU exhaustion attacks. if runScripts { err := checkBlockScripts(block, view, scriptFlags, b.sigCache, b.hashCache) if err != nil { return err } } // Update the best hash for view to include this block since all of its // transactions have been connected. view.SetBestHash(node.hash) return nil }
// CheckProofOfWork ensures the block header bits which indicate the target // difficulty is in min/max range and that the block hash is less than the // target difficulty as claimed. func CheckProofOfWork(block *btcutil.Block, powLimit *big.Int) error { return checkProofOfWork(&block.MsgBlock().Header, powLimit, BFNone) }
// checkBlockSanity performs some preliminary checks on a block to ensure it is // sane before continuing with block processing. These checks are context free. // // The flags do not modify the behavior of this function directly, however they // are needed to pass along to checkBlockHeaderSanity. func checkBlockSanity(block *btcutil.Block, powLimit *big.Int, timeSource MedianTimeSource, flags BehaviorFlags) error { msgBlock := block.MsgBlock() header := &msgBlock.Header err := checkBlockHeaderSanity(header, powLimit, timeSource, flags) if err != nil { return err } // A block must have at least one transaction. numTx := len(msgBlock.Transactions) if numTx == 0 { return ruleError(ErrNoTransactions, "block does not contain "+ "any transactions") } // A block must not have more transactions than the max block payload. if numTx > wire.MaxBlockPayload { str := fmt.Sprintf("block contains too many transactions - "+ "got %d, max %d", numTx, wire.MaxBlockPayload) return ruleError(ErrTooManyTransactions, str) } // A block must not exceed the maximum allowed block payload when // serialized. serializedSize := msgBlock.SerializeSizeStripped() if serializedSize > MaxBlockBaseSize { str := fmt.Sprintf("serialized block is too big - got %d, "+ "max %d", serializedSize, MaxBlockBaseSize) return ruleError(ErrBlockTooBig, str) } // The first transaction in a block must be a coinbase. transactions := block.Transactions() if !IsCoinBase(transactions[0]) { return ruleError(ErrFirstTxNotCoinbase, "first transaction in "+ "block is not a coinbase") } // A block must not have more than one coinbase. for i, tx := range transactions[1:] { if IsCoinBase(tx) { str := fmt.Sprintf("block contains second coinbase at "+ "index %d", i+1) return ruleError(ErrMultipleCoinbases, str) } } // Do some preliminary checks on each transaction to ensure they are // sane before continuing. for _, tx := range transactions { err := CheckTransactionSanity(tx) if err != nil { return err } } // Build merkle tree and ensure the calculated merkle root matches the // entry in the block header. This also has the effect of caching all // of the transaction hashes in the block to speed up future hash // checks. Bitcoind builds the tree here and checks the merkle root // after the following checks, but there is no reason not to check the // merkle root matches here. merkles := BuildMerkleTreeStore(block.Transactions(), false) calculatedMerkleRoot := merkles[len(merkles)-1] if !header.MerkleRoot.IsEqual(calculatedMerkleRoot) { str := fmt.Sprintf("block merkle root is invalid - block "+ "header indicates %v, but calculated value is %v", header.MerkleRoot, calculatedMerkleRoot) return ruleError(ErrBadMerkleRoot, str) } // Check for duplicate transactions. This check will be fairly quick // since the transaction hashes are already cached due to building the // merkle tree above. existingTxHashes := make(map[chainhash.Hash]struct{}) for _, tx := range transactions { hash := tx.Hash() if _, exists := existingTxHashes[*hash]; exists { str := fmt.Sprintf("block contains duplicate "+ "transaction %v", hash) return ruleError(ErrDuplicateTx, str) } existingTxHashes[*hash] = struct{}{} } // The number of signature operations must be less than the maximum // allowed per block. totalSigOps := 0 for _, tx := range transactions { // We could potentially overflow the accumulator so check for // overflow. lastSigOps := totalSigOps totalSigOps += (CountSigOps(tx) * WitnessScaleFactor) if totalSigOps < lastSigOps || totalSigOps > MaxBlockSigOpsCost { str := fmt.Sprintf("block contains too many signature "+ "operations - got %v, max %v", totalSigOps, MaxBlockSigOpsCost) return ruleError(ErrTooManySigOps, str) } } // Once the witness commitment, witness nonce, and sig op cost have // been validated, we can finally assert that the block's weight // doesn't exceed the current consensus paramter. blockWeight := GetBlockWeight(block) if blockWeight > MaxBlockWeight { str := fmt.Sprintf("block's weight metric is too high - got %v, max %v", blockWeight, MaxBlockWeight) return ruleError(ErrBlockVersionTooOld, str) } return nil }
// disconnectTransactions updates the view by removing all of the transactions // created by the passed block, restoring all utxos the transactions spent by // using the provided spent txo information, and setting the best hash for the // view to the block before the passed block. func (view *UtxoViewpoint) disconnectTransactions(block *btcutil.Block, stxos []spentTxOut) error { // Sanity check the correct number of stxos are provided. if len(stxos) != countSpentOutputs(block) { return AssertError("disconnectTransactions called with bad " + "spent transaction out information") } // Loop backwards through all transactions so everything is unspent in // reverse order. This is necessary since transactions later in a block // can spend from previous ones. stxoIdx := len(stxos) - 1 transactions := block.Transactions() for txIdx := len(transactions) - 1; txIdx > -1; txIdx-- { tx := transactions[txIdx] // Clear this transaction from the view if it already exists or // create a new empty entry for when it does not. This is done // because the code relies on its existence in the view in order // to signal modifications have happened. isCoinbase := txIdx == 0 entry := view.entries[*tx.Hash()] if entry == nil { entry = newUtxoEntry(tx.MsgTx().Version, isCoinbase, block.Height()) view.entries[*tx.Hash()] = entry } entry.modified = true entry.sparseOutputs = make(map[uint32]*utxoOutput) // Loop backwards through all of the transaction inputs (except // for the coinbase which has no inputs) and unspend the // referenced txos. This is necessary to match the order of the // spent txout entries. if isCoinbase { continue } for txInIdx := len(tx.MsgTx().TxIn) - 1; txInIdx > -1; txInIdx-- { // Ensure the spent txout index is decremented to stay // in sync with the transaction input. stxo := &stxos[stxoIdx] stxoIdx-- // When there is not already an entry for the referenced // transaction in the view, it means it was fully spent, // so create a new utxo entry in order to resurrect it. txIn := tx.MsgTx().TxIn[txInIdx] originHash := &txIn.PreviousOutPoint.Hash originIndex := txIn.PreviousOutPoint.Index entry := view.entries[*originHash] if entry == nil { entry = newUtxoEntry(stxo.version, stxo.isCoinBase, stxo.height) view.entries[*originHash] = entry } // Mark the entry as modified since it is either new // or will be changed below. entry.modified = true // Restore the specific utxo using the stxo data from // the spend journal if it doesn't already exist in the // view. output, ok := entry.sparseOutputs[originIndex] if !ok { // Add the unspent transaction output. entry.sparseOutputs[originIndex] = &utxoOutput{ spent: false, compressed: stxo.compressed, amount: stxo.amount, pkScript: stxo.pkScript, } continue } // Mark the existing referenced transaction output as // unspent. output.spent = false } } // Update the best hash for view to the previous block since all of the // transactions for the current block have been disconnected. view.SetBestHash(&block.MsgBlock().Header.PrevBlock) return nil }
// checkBlockContext peforms several validation checks on the block which depend // on its position within the block chain. // // The flags modify the behavior of this function as follows: // - BFFastAdd: The transaction are not checked to see if they are finalized // and the somewhat expensive BIP0034 validation is not performed. // // The flags are also passed to checkBlockHeaderContext. See its documentation // for how the flags modify its behavior. // // This function MUST be called with the chain state lock held (for writes). func (b *BlockChain) checkBlockContext(block *btcutil.Block, prevNode *blockNode, flags BehaviorFlags) error { // The genesis block is valid by definition. if prevNode == nil { return nil } // Perform all block header related validation checks. header := &block.MsgBlock().Header err := b.checkBlockHeaderContext(header, prevNode, flags) if err != nil { return err } // Query for the Version Bits state for the segwit soft-fork // deployment. If segwit is active, we'll switch over to enforcing all // the new rules. segwitState, err := b.deploymentState(prevNode, chaincfg.DeploymentSegwit) if err != nil { return err } // If segwit is active, then we'll need to fully validate the new // witness commitment for adherance to the rules. if segwitState == ThresholdActive { // Validate the witness commitment (if any) within the block. // This involves asserting that if the coinbase contains the // special commitment output, then this merkle root matches a // computed merkle root of all the wtxid's of the transactions // within the block. In addition, various other checks against // the coinbase's witness stack. if err := ValidateWitnessCommitment(block); err != nil { return err } } fastAdd := flags&BFFastAdd == BFFastAdd if !fastAdd { // Obtain the latest state of the deployed CSV soft-fork in // order to properly guard the new validation behavior based on // the current BIP 9 version bits state. csvState, err := b.deploymentState(prevNode, chaincfg.DeploymentCSV) if err != nil { return err } // Once the CSV soft-fork is fully active, we'll switch to // using the current median time past of the past block's // timestamps for all lock-time based checks. blockTime := header.Timestamp if csvState == ThresholdActive { medianTime, err := b.calcPastMedianTime(prevNode) if err != nil { return err } blockTime = medianTime } // The height of this block is one more than the referenced // previous block. blockHeight := prevNode.height + 1 // Ensure all transactions in the block are finalized. for _, tx := range block.Transactions() { if !IsFinalizedTransaction(tx, blockHeight, blockTime) { str := fmt.Sprintf("block contains unfinalized "+ "transaction %v", tx.Hash()) return ruleError(ErrUnfinalizedTx, str) } } // Ensure coinbase starts with serialized block heights for // blocks whose version is the serializedHeightVersion or newer // once a majority of the network has upgraded. This is part of // BIP0034. if ShouldHaveSerializedBlockHeight(header) && blockHeight >= b.chainParams.BIP0034Height { coinbaseTx := block.Transactions()[0] err := checkSerializedHeight(coinbaseTx, blockHeight) if err != nil { return err } } } return nil }
// IsCheckpointCandidate returns whether or not the passed block is a good // checkpoint candidate. // // The factors used to determine a good checkpoint are: // - The block must be in the main chain // - The block must be at least 'CheckpointConfirmations' blocks prior to the // current end of the main chain // - The timestamps for the blocks before and after the checkpoint must have // timestamps which are also before and after the checkpoint, respectively // (due to the median time allowance this is not always the case) // - The block must not contain any strange transaction such as those with // nonstandard scripts // // The intent is that candidates are reviewed by a developer to make the final // decision and then manually added to the list of checkpoints for a network. // // This function is safe for concurrent access. func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) { b.chainLock.RLock() defer b.chainLock.RUnlock() // Checkpoints must be enabled. if b.noCheckpoints { return false, fmt.Errorf("checkpoints are disabled") } var isCandidate bool err := b.db.View(func(dbTx database.Tx) error { // A checkpoint must be in the main chain. blockHeight, err := dbFetchHeightByHash(dbTx, block.Hash()) if err != nil { // Only return an error if it's not due to the block not // being in the main chain. if !isNotInMainChainErr(err) { return err } return nil } // Ensure the height of the passed block and the entry for the // block in the main chain match. This should always be the // case unless the caller provided an invalid block. if blockHeight != block.Height() { return fmt.Errorf("passed block height of %d does not "+ "match the main chain height of %d", block.Height(), blockHeight) } // A checkpoint must be at least CheckpointConfirmations blocks // before the end of the main chain. mainChainHeight := b.bestNode.height if blockHeight > (mainChainHeight - CheckpointConfirmations) { return nil } // Get the previous block header. prevHash := &block.MsgBlock().Header.PrevBlock prevHeader, err := dbFetchHeaderByHash(dbTx, prevHash) if err != nil { return err } // Get the next block header. nextHeader, err := dbFetchHeaderByHeight(dbTx, blockHeight+1) if err != nil { return err } // A checkpoint must have timestamps for the block and the // blocks on either side of it in order (due to the median time // allowance this is not always the case). prevTime := prevHeader.Timestamp curTime := block.MsgBlock().Header.Timestamp nextTime := nextHeader.Timestamp if prevTime.After(curTime) || nextTime.Before(curTime) { return nil } // A checkpoint must have transactions that only contain // standard scripts. for _, tx := range block.Transactions() { if isNonstandardTransaction(tx) { return nil } } // All of the checks passed, so the block is a candidate. isCandidate = true return nil }) return isCandidate, err }
// checkBlockScripts executes and validates the scripts for all transactions in // the passed block using multiple goroutines. func checkBlockScripts(block *btcutil.Block, utxoView *UtxoViewpoint, scriptFlags txscript.ScriptFlags, sigCache *txscript.SigCache, hashCache *txscript.HashCache) error { // First determine if segwit is active according to the scriptFlags. If // it isn't then we don't need to interact with the HashCache. segwitActive := scriptFlags&txscript.ScriptVerifyWitness == txscript.ScriptVerifyWitness // Collect all of the transaction inputs and required information for // validation for all transactions in the block into a single slice. numInputs := 0 for _, tx := range block.Transactions() { numInputs += len(tx.MsgTx().TxIn) } txValItems := make([]*txValidateItem, 0, numInputs) for _, tx := range block.Transactions() { sha := tx.Hash() // If the HashCache is present, and it doesn't yet contain the // partial sighashes for this transaction, then we add the // sighashes for the transaction. This allows us to take // advantage of the potential speed savings due to the new // digest algorithm (BIP0143). if segwitActive && hashCache != nil && !hashCache.ContainsHashes(sha) { hashCache.AddSigHashes(tx.MsgTx()) } var cachedHashes *txscript.TxSigHashes if segwitActive { if hashCache != nil { cachedHashes, _ = hashCache.GetSigHashes(sha) } else { cachedHashes = txscript.NewTxSigHashes(tx.MsgTx()) } } for txInIdx, txIn := range tx.MsgTx().TxIn { // Skip coinbases. if txIn.PreviousOutPoint.Index == math.MaxUint32 { continue } txVI := &txValidateItem{ txInIndex: txInIdx, txIn: txIn, tx: tx, sigHashes: cachedHashes, } txValItems = append(txValItems, txVI) } } // Validate all of the inputs. validator := newTxValidator(utxoView, scriptFlags, sigCache, hashCache) start := time.Now() if err := validator.Validate(txValItems); err != nil { return err } elapsed := time.Since(start) log.Tracef("block %v took %v to verify", block.Hash(), elapsed) // If the HashCache is present, once we have validated the block, we no // longer need the cached hashes for these transactions, so we purge // them from the cache. if segwitActive && hashCache != nil { for _, tx := range block.Transactions() { hashCache.PurgeSigHashes(tx.Hash()) } } return nil }