remove memory pressure from parseScript
This commit is contained in:
parent
9aa4259382
commit
ccfa7af546
11 changed files with 160 additions and 64 deletions
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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++
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue