diff --git a/blockchain/claimtrie.go b/blockchain/claimtrie.go index 9605b398..b0ce8443 100644 --- a/blockchain/claimtrie.go +++ b/blockchain/claimtrie.go @@ -65,11 +65,13 @@ func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error { if e == nil { return errors.Errorf("missing input in view for %s", op.String()) } - cs, err := txscript.DecodeClaimScript(e.pkScript) + cs, closer, err := txscript.DecodeClaimScript(e.pkScript) if err == txscript.ErrNotClaimScript { + closer() continue } if err != nil { + closer() return err } @@ -89,6 +91,7 @@ func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error { copy(id[:], cs.ClaimID()) err = ct.SpendSupport(name, op, id) } + closer() if err != nil { return errors.Wrapf(err, "handleTxIns") } @@ -99,11 +102,13 @@ func (h *handler) handleTxIns(ct *claimtrie.ClaimTrie) error { func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error { for i, txOut := range h.tx.MsgTx().TxOut { op := *wire.NewOutPoint(h.tx.Hash(), uint32(i)) - cs, err := txscript.DecodeClaimScript(txOut.PkScript) + cs, closer, err := txscript.DecodeClaimScript(txOut.PkScript) if err == txscript.ErrNotClaimScript { + closer() continue } if err != nil { + closer() return err } @@ -127,12 +132,14 @@ func (h *handler) handleTxOuts(ct *claimtrie.ClaimTrie) error { if !bytes.Equal(h.spent[id.Key()], normName) { node.LogOnce(fmt.Sprintf("Invalid update operation: name or ID mismatch at %d for: %s, %s", ct.Height(), normName, id.String())) + closer() continue } delete(h.spent, id.Key()) err = ct.UpdateClaim(name, op, amt, id) } + closer() if err != nil { return errors.Wrapf(err, "handleTxOuts") } diff --git a/blockchain/scriptval.go b/blockchain/scriptval.go index 8ba59a42..ac81c126 100644 --- a/blockchain/scriptval.go +++ b/blockchain/scriptval.go @@ -86,6 +86,7 @@ out: txIn.PreviousOutPoint, err, witness, sigScript, pkScript) err := ruleError(ErrScriptMalformed, str) + vm.Close() v.sendResult(err) break out } @@ -100,11 +101,13 @@ out: txIn.PreviousOutPoint, err, witness, sigScript, pkScript) err := ruleError(ErrScriptValidation, str) + vm.Close() v.sendResult(err) break out } // Validation succeeded. + vm.Close() v.sendResult(nil) case <-v.quitChan: diff --git a/claimtrie/cmd/cmd/chain.go b/claimtrie/cmd/cmd/chain.go index f792e5f9..d82b3fa5 100644 --- a/claimtrie/cmd/cmd/chain.go +++ b/claimtrie/cmd/cmd/chain.go @@ -343,8 +343,9 @@ func (cb *chainConverter) processBlock() { for _, txIn := range tx.MsgTx().TxIn { prevOutpoint := txIn.PreviousOutPoint pkScript := utxoPubScripts[prevOutpoint] - cs, err := txscript.DecodeClaimScript(pkScript) + cs, closer, err := txscript.DecodeClaimScript(pkScript) if err == txscript.ErrNotClaimScript { + closer() continue } if err != nil { @@ -371,12 +372,14 @@ func (cb *chainConverter) processBlock() { } changes = append(changes, chg) + closer() } op := *wire.NewOutPoint(tx.Hash(), 0) for i, txOut := range tx.MsgTx().TxOut { - cs, err := txscript.DecodeClaimScript(txOut.PkScript) + cs, closer, err := txscript.DecodeClaimScript(txOut.PkScript) if err == txscript.ErrNotClaimScript { + closer() continue } @@ -401,6 +404,7 @@ func (cb *chainConverter) processBlock() { copy(chg.ClaimID[:], cs.ClaimID()) } changes = append(changes, chg) + closer() } } cb.stat.blocksProcessed++ diff --git a/rpcclaimtrie.go b/rpcclaimtrie.go index 0677637b..6a90152e 100644 --- a/rpcclaimtrie.go +++ b/rpcclaimtrie.go @@ -323,7 +323,8 @@ func lookupValue(s *rpcServer, outpoint wire.OutPoint, includeValues *bool) (str } txo := msgTx.TxOut[outpoint.Index] - cs, err := txscript.DecodeClaimScript(txo.PkScript) + cs, closer, err := txscript.DecodeClaimScript(txo.PkScript) + defer closer() if err != nil { context := "Failed to decode the claim script" return "", "", internalRPCError(err.Error(), context) diff --git a/txscript/engine.go b/txscript/engine.go index b6981c8c..d7bd1003 100644 --- a/txscript/engine.go +++ b/txscript/engine.go @@ -136,6 +136,20 @@ type Engine struct { witnessVersion int witnessProgram []byte inputAmount int64 + cleanups []func() +} + +func (vm *Engine) Close() { + for i := range vm.cleanups { + vm.cleanups[i]() + } + vm.cleanups = nil + vm.scripts = nil + vm.savedFirstStack = nil + vm.witnessProgram = nil + vm.condStack = nil + vm.sigCache = nil + vm.hashCache = nil } // hasFlag returns whether the script engine instance has the passed flag set. @@ -269,8 +283,9 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { if err != nil { return err } - pops, err := parseScript(pkScript) + pops, closer, err := parseScript(pkScript) if err != nil { + closer() return err } @@ -278,6 +293,7 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { // append the pkScript generated above as the next // script to execute. vm.scripts = append(vm.scripts, pops) + vm.cleanups = append(vm.cleanups, closer) vm.SetStack(witness) case payToWitnessScriptHashDataSize: // P2WSH @@ -310,8 +326,9 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { // With all the validity checks passed, parse the // script into individual op-codes so w can execute it // as the next script. - pops, err := parseScript(witnessScript) + pops, closer, err := parseScript(witnessScript) if err != nil { + closer() return err } @@ -319,6 +336,7 @@ func (vm *Engine) verifyWitnessProgram(witness [][]byte) error { // the stack, and set the witnessScript to be the next // script executed. vm.scripts = append(vm.scripts, pops) + vm.cleanups = append(vm.cleanups, closer) vm.SetStack(witness[:len(witness)-1]) default: @@ -492,11 +510,13 @@ func (vm *Engine) Step() (done bool, err error) { } script := vm.savedFirstStack[len(vm.savedFirstStack)-1] - pops, err := parseScript(script) + pops, closer, err := parseScript(script) if err != nil { + closer() return false, err } vm.scripts = append(vm.scripts, pops) + vm.cleanups = append(vm.cleanups, closer) // Set stack to be the stack from first script minus the // script itself @@ -910,10 +930,13 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags return nil, scriptError(ErrScriptTooBig, str) } var err error - vm.scripts[i], err = parseScript(scr) + var closer func() + vm.scripts[i], closer, err = parseScript(scr) if err != nil { + closer() return nil, err } + vm.cleanups = append(vm.cleanups, closer) } // Advance the program counter to the public key script if the signature diff --git a/txscript/nameclaim.go b/txscript/nameclaim.go index bcdf01eb..9501c060 100644 --- a/txscript/nameclaim.go +++ b/txscript/nameclaim.go @@ -55,27 +55,27 @@ func UpdateClaimScript(name string, claimID []byte, value string) ([]byte, error } // DecodeClaimScript ... -func DecodeClaimScript(script []byte) (*ClaimScript, error) { +func DecodeClaimScript(script []byte) (*ClaimScript, func(), error) { if len(script) == 0 { - return nil, ErrNotClaimScript + return nil, func() {}, ErrNotClaimScript } op := script[0] if op != OP_CLAIMNAME && op != OP_SUPPORTCLAIM && op != OP_UPDATECLAIM { - return nil, ErrNotClaimScript + return nil, func() {}, ErrNotClaimScript } - pops, err := parseScript(script) + pops, closer, err := parseScript(script) if err != nil { - return nil, err + return nil, closer, err } if isClaimName(pops) || isSupportClaim(pops) || isUpdateClaim(pops) { cs := &ClaimScript{op: op, pops: pops} if cs.Size() > MaxClaimScriptSize { log.Infof("claim script of %d bytes is larger than %d", cs.Size(), MaxClaimScriptSize) - return nil, ErrInvalidClaimScript + return nil, closer, ErrInvalidClaimScript } - return cs, nil + return cs, closer, nil } - return nil, ErrInvalidClaimScript + return nil, closer, ErrInvalidClaimScript } // ClaimScript ... @@ -132,7 +132,8 @@ func (cs *ClaimScript) Size() int { // StripClaimScriptPrefix ... func StripClaimScriptPrefix(script []byte) []byte { - cs, err := DecodeClaimScript(script) + cs, closer, err := DecodeClaimScript(script) + defer closer() if err != nil { return script } @@ -141,7 +142,8 @@ func StripClaimScriptPrefix(script []byte) []byte { // claimNameSize returns size of the name in a claim script or 0 if script is not a claimtrie transaction. func claimNameSize(script []byte) int { - cs, err := DecodeClaimScript(script) + cs, closer, err := DecodeClaimScript(script) + defer closer() if err != nil { return 0 } @@ -200,7 +202,8 @@ func isUpdateClaim(pops []parsedOpcode) bool { const illegalChars = "=&#:*$@%?/;\\\b\n\t\r\x00" func AllClaimsAreSane(script []byte, enforceSoftFork bool) error { - cs, err := DecodeClaimScript(script) + cs, closer, err := DecodeClaimScript(script) + defer closer() if err != ErrNotClaimScript { if err != nil { return fmt.Errorf("invalid claim script: %s", err.Error()) diff --git a/txscript/nameclaim_test.go b/txscript/nameclaim_test.go index ed1a07ce..c793c9b3 100644 --- a/txscript/nameclaim_test.go +++ b/txscript/nameclaim_test.go @@ -12,12 +12,14 @@ func TestCreationParseLoopClaim(t *testing.T) { claim, err := ClaimNameScript("tester", "value") r.NoError(err) - parsed, err := parseScript(claim) + parsed, closer, err := parseScript(claim) + defer closer() r.NoError(err) r.True(isClaimName(parsed)) r.False(isSupportClaim(parsed)) r.False(isUpdateClaim(parsed)) - script, err := DecodeClaimScript(claim) + script, closer2, err := DecodeClaimScript(claim) + defer closer2() r.NoError(err) r.Equal([]byte("tester"), script.Name()) r.Equal([]byte("value"), script.Value()) @@ -30,12 +32,14 @@ func TestCreationParseLoopUpdate(t *testing.T) { claimID := []byte("12345123451234512345") claim, err := UpdateClaimScript("tester", claimID, "value") r.NoError(err) - parsed, err := parseScript(claim) + parsed, closer, err := parseScript(claim) + defer closer() r.NoError(err) r.False(isSupportClaim(parsed)) r.False(isClaimName(parsed)) r.True(isUpdateClaim(parsed)) - script, err := DecodeClaimScript(claim) + script, closer2, err := DecodeClaimScript(claim) + defer closer2() r.NoError(err) r.Equal([]byte("tester"), script.Name()) @@ -50,12 +54,15 @@ func TestCreationParseLoopSupport(t *testing.T) { claimID := []byte("12345123451234512345") claim, err := SupportClaimScript("tester", claimID, []byte("value")) r.NoError(err) - parsed, err := parseScript(claim) + parsed, closer, err := parseScript(claim) + defer closer() + r.NoError(err) r.True(isSupportClaim(parsed)) r.False(isClaimName(parsed)) r.False(isUpdateClaim(parsed)) - script, err := DecodeClaimScript(claim) + script, closer2, err := DecodeClaimScript(claim) + defer closer2() r.NoError(err) r.Equal([]byte("tester"), script.Name()) @@ -64,7 +71,8 @@ func TestCreationParseLoopSupport(t *testing.T) { claim, err = SupportClaimScript("tester", claimID, nil) r.NoError(err) - script, err = DecodeClaimScript(claim) + script, closer, err = DecodeClaimScript(claim) + defer closer() r.NoError(err) r.Equal([]byte("tester"), script.Name()) diff --git a/txscript/pkscript.go b/txscript/pkscript.go index 0703ef5d..e8f379ee 100644 --- a/txscript/pkscript.go +++ b/txscript/pkscript.go @@ -211,7 +211,8 @@ func computeNonWitnessPkScript(sigScript []byte) (PkScript, error) { // The redeem script will always be the last data push of the // signature script, so we'll parse the script into opcodes to // obtain it. - parsedOpcodes, err := parseScript(sigScript) + parsedOpcodes, closer, err := parseScript(sigScript) + defer closer() if err != nil { return PkScript{}, err } diff --git a/txscript/script.go b/txscript/script.go index ae6f509e..64089e83 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/binary" "fmt" + "sync" "time" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -63,7 +64,8 @@ func isScriptHash(pops []parsedOpcode) bool { // IsPayToScriptHash returns true if the script is in the standard // pay-to-script-hash (P2SH) format, false otherwise. func IsPayToScriptHash(script []byte) bool { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return false } @@ -81,7 +83,8 @@ func isWitnessScriptHash(pops []parsedOpcode) bool { // IsPayToWitnessScriptHash returns true if the is in the standard // pay-to-witness-script-hash (P2WSH) format, false otherwise. func IsPayToWitnessScriptHash(script []byte) bool { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return false } @@ -91,7 +94,8 @@ func IsPayToWitnessScriptHash(script []byte) bool { // IsPayToWitnessPubKeyHash returns true if the is in the standard // pay-to-witness-pubkey-hash (P2WKH) format, false otherwise. func IsPayToWitnessPubKeyHash(script []byte) bool { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return false } @@ -119,7 +123,8 @@ func IsWitnessProgram(script []byte) bool { return false } - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return false } @@ -143,7 +148,8 @@ func isWitnessProgram(pops []parsedOpcode) bool { // ExtractWitnessProgramInfo attempts to extract the witness program version, // as well as the witness program itself from the passed script. func ExtractWitnessProgramInfo(script []byte) (int, []byte, error) { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return 0, nil, err } @@ -184,18 +190,25 @@ func isPushOnly(pops []parsedOpcode) bool { // // False will be returned when the script does not parse. func IsPushOnlyScript(script []byte) bool { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return false } return isPushOnly(pops) } +var parsedPool = sync.Pool{ + New: func() interface{} { + return make([]parsedOpcode, 0, 8) + }, +} + // parseScriptTemplate is the same as parseScript but allows the passing of the // template list for testing purposes. When there are parse errors, it returns // the list of parsed opcodes up to the point of failure along with the error. -func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, error) { - retScript := make([]parsedOpcode, 0, len(script)) +func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, func(), error) { + retScript := parsedPool.Get().([]parsedOpcode) var err error for i := 0; i < len(script); { instr := script[i] @@ -203,13 +216,19 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, e pop := parsedOpcode{opcode: op} i, err = pop.checkParseableInScript(script, i) if err != nil { - return retScript, err + break } retScript = append(retScript, pop) } - return retScript, nil + return retScript, func() { + for i := range retScript { + retScript[i].data = nil + retScript[i].opcode = nil + } + parsedPool.Put(retScript[:0]) + }, err } // checkScriptTemplateParseable is the same as parseScriptTemplate but does not @@ -252,7 +271,7 @@ func checkScriptTemplateParseable(script []byte, opcodes *[256]opcode) (*byte, e // parseScript preparses the script in bytes into a list of parsedOpcodes while // applying a number of sanity checks. -func parseScript(script []byte) ([]parsedOpcode, error) { +func parseScript(script []byte) ([]parsedOpcode, func(), error) { return parseScriptTemplate(script, &opcodeArray) } @@ -277,7 +296,8 @@ func unparseScript(pops []parsedOpcode) ([]byte, error) { // if the caller wants more information about the failure. func DisasmString(buf []byte) (string, error) { var disbuf bytes.Buffer - opcodes, err := parseScript(buf) + opcodes, closer, err := parseScript(buf) + defer closer() for _, pop := range opcodes { disbuf.WriteString(pop.print(true)) disbuf.WriteByte(' ') @@ -517,7 +537,8 @@ func calcWitnessSignatureHash(subScript []parsedOpcode, sigHashes *TxSigHashes, func CalcWitnessSigHash(script []byte, sigHashes *TxSigHashes, hType SigHashType, tx *wire.MsgTx, idx int, amt int64) ([]byte, error) { - parsedScript, err := parseScript(script) + parsedScript, closer, err := parseScript(script) + defer closer() if err != nil { return nil, fmt.Errorf("cannot parse output script: %v", err) } @@ -558,7 +579,8 @@ func shallowCopyTx(tx *wire.MsgTx) wire.MsgTx { // engine instance, calculate the signature hash to be used for signing and // verification. func CalcSignatureHash(script []byte, hashType SigHashType, tx *wire.MsgTx, idx int) ([]byte, error) { - parsedScript, err := parseScript(script) + parsedScript, closer, err := parseScript(script) + defer closer() if err != nil { return nil, fmt.Errorf("cannot parse output script: %v", err) } @@ -711,7 +733,8 @@ func getSigOpCount(pops []parsedOpcode, precise bool) int { func GetSigOpCount(script []byte) int { // Don't check error since parseScript returns the parsed-up-to-error // list of pops. - pops, _ := parseScript(script) + pops, closer, _ := parseScript(script) + defer closer() return getSigOpCount(pops, false) } @@ -723,7 +746,8 @@ func GetSigOpCount(script []byte) int { func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int { // Don't check error since parseScript returns the parsed-up-to-error // list of pops. - pops, _ := parseScript(scriptPubKey) + pops, closer1, _ := parseScript(scriptPubKey) + defer closer1() // Treat non P2SH transactions as normal. if !(bip16 && isScriptHash(pops)) { @@ -733,7 +757,9 @@ func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int { // The public key script is a pay-to-script-hash, so parse the signature // script to get the final item. Scripts that fail to fully parse count // as 0 signature operations. - sigPops, err := parseScript(scriptSig) + sigPops, closer2, err := parseScript(scriptSig) + defer closer2() + if err != nil { return 0 } @@ -756,7 +782,9 @@ func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int { // returns the parsed-up-to-error list of pops and the consensus rules // dictate signature operations are counted up to the first parse // failure. - shPops, _ := parseScript(shScript) + shPops, closer3, _ := parseScript(shScript) + defer closer3() + return getSigOpCount(shPops, true) } @@ -776,7 +804,8 @@ func GetWitnessSigOpCount(sigScript, pkScript []byte, witness wire.TxWitness) in // Next, we'll check the sigScript to see if this is a nested p2sh // witness program. This is a case wherein the sigScript is actually a // datapush of a p2wsh witness program. - sigPops, err := parseScript(sigScript) + sigPops, closer, err := parseScript(sigScript) + defer closer() if err != nil { return 0 } @@ -811,7 +840,8 @@ func getWitnessSigOps(pkScript []byte, witness wire.TxWitness) int { len(witness) > 0: witnessScript := witness[len(witness)-1] - pops, _ := parseScript(witnessScript) + pops, closer, _ := parseScript(witnessScript) + defer closer() return getSigOpCount(pops, true) } } diff --git a/txscript/sign.go b/txscript/sign.go index 348a109b..2b0876f2 100644 --- a/txscript/sign.go +++ b/txscript/sign.go @@ -22,7 +22,8 @@ func RawTxInWitnessSignature(tx *wire.MsgTx, sigHashes *TxSigHashes, idx int, amt int64, subScript []byte, hashType SigHashType, key *btcec.PrivateKey) ([]byte, error) { - parsedScript, err := parseScript(subScript) + parsedScript, closer, err := parseScript(subScript) + defer closer() if err != nil { return nil, fmt.Errorf("cannot parse output script: %v", err) } @@ -232,11 +233,13 @@ func mergeScripts(chainParams *chaincfg.Params, tx *wire.MsgTx, idx int, case ScriptHashTy: // Remove the last push in the script and then recurse. // this could be a lot less inefficient. - sigPops, err := parseScript(sigScript) + sigPops, closer1, err := parseScript(sigScript) + defer closer1() if err != nil || len(sigPops) == 0 { return prevScript } - prevPops, err := parseScript(prevScript) + prevPops, closer2, err := parseScript(prevScript) + defer closer2() if err != nil || len(prevPops) == 0 { return sigScript } @@ -293,14 +296,17 @@ func mergeMultiSig(tx *wire.MsgTx, idx int, addresses []btcutil.Address, // This is an internal only function and we already parsed this script // as ok for multisig (this is how we got here), so if this fails then // all assumptions are broken and who knows which way is up? - pkPops, _ := parseScript(pkScript) + pkPops, closer1, _ := parseScript(pkScript) + defer closer1() - sigPops, err := parseScript(sigScript) + sigPops, closer2, err := parseScript(sigScript) + defer closer2() if err != nil || len(sigPops) == 0 { return prevScript } - prevPops, err := parseScript(prevScript) + prevPops, closer3, err := parseScript(prevScript) + defer closer3() if err != nil || len(prevPops) == 0 { return sigScript } diff --git a/txscript/standard.go b/txscript/standard.go index 0acce5bc..8a0ec81b 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -183,7 +183,8 @@ func typeOfScript(pops []parsedOpcode) ScriptClass { // // NonStandardTy will be returned when the script does not parse. func GetScriptClass(script []byte) ScriptClass { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return NonStandardTy } @@ -273,12 +274,14 @@ type ScriptInfo struct { func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness, bip16, segwit bool) (*ScriptInfo, error) { - sigPops, err := parseScript(sigScript) + sigPops, closer1, err := parseScript(sigScript) + defer closer1() if err != nil { return nil, err } - pkPops, err := parseScript(pkScript) + pkPops, closer2, err := parseScript(pkScript) + defer closer2() if err != nil { return nil, err } @@ -301,7 +304,8 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness, // The pay-to-hash-script is the final data push of the // signature script. script := sigPops[len(sigPops)-1].data - shPops, err := parseScript(script) + shPops, closer3, err := parseScript(script) + defer closer3() if err != nil { return nil, err } @@ -332,7 +336,8 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness, // Extract the pushed witness program from the sigScript so we // can determine the number of expected inputs. - pkPops, _ := parseScript(sigScript[1:]) + pkPops, closer4, _ := parseScript(sigScript[1:]) + defer closer4() shInputs := expectedInputs(pkPops, typeOfScript(pkPops)) if shInputs == -1 { si.ExpectedInputs = -1 @@ -351,7 +356,8 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness, // The witness script is the final element of the witness // stack. witnessScript := witness[len(witness)-1] - pops, _ := parseScript(witnessScript) + pops, closer5, _ := parseScript(witnessScript) + defer closer5() shInputs := expectedInputs(pops, typeOfScript(pops)) if shInputs == -1 { @@ -378,7 +384,8 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness, // a multi-signature transaction script. The passed script MUST already be // known to be a multi-signature script. func CalcMultiSigStats(script []byte) (int, int, error) { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return 0, 0, err } @@ -519,7 +526,8 @@ func MultiSigScript(pubkeys []*btcutil.AddressPubKey, nrequired int) ([]byte, er // PushedData returns an array of byte slices containing any pushed data found // in the passed script. This includes OP_0, but not OP_1 - OP_16. func PushedData(script []byte) ([][]byte, error) { - pops, err := parseScript(script) + pops, closer, err := parseScript(script) + defer closer() if err != nil { return nil, err } @@ -547,7 +555,8 @@ func ExtractPkScriptAddrs(pkScript []byte, chainParams *chaincfg.Params) (Script // No valid addresses or required signatures if the script doesn't // parse. - pops, err := parseScript(stripped) + pops, closer, err := parseScript(stripped) + defer closer() if err != nil { return NonStandardTy, nil, 0, err } @@ -669,7 +678,8 @@ type AtomicSwapDataPushes struct { // This function is only defined in the txscript package due to API limitations // which prevent callers using txscript to parse nonstandard scripts. func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDataPushes, error) { - pops, err := parseScript(pkScript) + pops, closer, err := parseScript(pkScript) + defer closer() if err != nil { return nil, err }