// ValidateTransactionScripts validates the scripts for the passed transaction // using multiple goroutines. func ValidateTransactionScripts(tx *btcutil.Tx, utxoView *UtxoViewpoint, flags txscript.ScriptFlags, sigCache *txscript.SigCache, hashCache *txscript.HashCache) error { // If the hashcache doesn't yet has the sighash midstate for this // transaction, then we'll compute them now so we can re-use them // amongst all worker validation goroutines. if !hashCache.ContainsHashes(tx.Hash()) { hashCache.AddSigHashes(tx.MsgTx()) } // The same pointer to the transaction's sighash midstate will be // re-used amongst all validation goroutines. By pre-computing the // sighash here instead of during validation, we ensure the sighashes // are only computed once. cachedHashes, _ := hashCache.GetSigHashes(tx.Hash()) // Collect all of the transaction inputs and required information for // validation. txIns := tx.MsgTx().TxIn txValItems := make([]*txValidateItem, 0, len(txIns)) for txInIdx, txIn := range txIns { // 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, flags, sigCache, hashCache) return validator.Validate(txValItems) }
// 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 }