txscript: Convert CalcScriptInfo.
This converts CalcScriptInfo and dependent expectedInputs to make use of the new script tokenizer as well as several of the other recently added raw script analysis functions in order to remove the reliance on parsed opcodes as a step towards utlimately removing them altogether. It is worth noting that this has the side effect of significantly optimizing the function as well, however, since it is deprecated, no benchmarks are provided.
This commit is contained in:
parent
43846b1edf
commit
705d24cab4
1 changed files with 37 additions and 39 deletions
|
@ -481,7 +481,11 @@ func NewScriptClass(name string) (*ScriptClass, error) {
|
||||||
// then -1 is returned. We are an internal function and thus assume that class
|
// then -1 is returned. We are an internal function and thus assume that class
|
||||||
// is the real class of pops (and we can thus assume things that were determined
|
// is the real class of pops (and we can thus assume things that were determined
|
||||||
// while finding out the type).
|
// while finding out the type).
|
||||||
func expectedInputs(pops []parsedOpcode, class ScriptClass) int {
|
//
|
||||||
|
// NOTE: This function is only valid for version 0 scripts. Since the function
|
||||||
|
// does not accept a script version, the results are undefined for other script
|
||||||
|
// versions.
|
||||||
|
func expectedInputs(script []byte, class ScriptClass) int {
|
||||||
switch class {
|
switch class {
|
||||||
case PubKeyTy:
|
case PubKeyTy:
|
||||||
return 1
|
return 1
|
||||||
|
@ -508,7 +512,7 @@ func expectedInputs(pops []parsedOpcode, class ScriptClass) int {
|
||||||
// the original bitcoind bug where OP_CHECKMULTISIG pops an
|
// the original bitcoind bug where OP_CHECKMULTISIG pops an
|
||||||
// additional item from the stack, add an extra expected input
|
// additional item from the stack, add an extra expected input
|
||||||
// for the extra push that is required to compensate.
|
// for the extra push that is required to compensate.
|
||||||
return asSmallInt(pops[0].opcode.value) + 1
|
return asSmallInt(script[0]) + 1
|
||||||
|
|
||||||
case NullDataTy:
|
case NullDataTy:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -549,52 +553,52 @@ type ScriptInfo struct {
|
||||||
func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
||||||
bip16, segwit bool) (*ScriptInfo, error) {
|
bip16, segwit bool) (*ScriptInfo, error) {
|
||||||
|
|
||||||
|
// Count the number of opcodes in the signature script while also ensuring
|
||||||
|
// that successfully parses. Since there is a check below to ensure the
|
||||||
|
// script is push only, this equates to the number of inputs to the public
|
||||||
|
// key script.
|
||||||
const scriptVersion = 0
|
const scriptVersion = 0
|
||||||
|
var numInputs int
|
||||||
sigPops, err := parseScript(sigScript)
|
tokenizer := MakeScriptTokenizer(scriptVersion, sigScript)
|
||||||
if err != nil {
|
for tokenizer.Next() {
|
||||||
|
numInputs++
|
||||||
|
}
|
||||||
|
if err := tokenizer.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pkPops, err := parseScript(pkScript)
|
if err := checkScriptParses(scriptVersion, pkScript); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't have a signature script that doesn't just push data.
|
||||||
|
if !IsPushOnlyScript(sigScript) {
|
||||||
|
return nil, scriptError(ErrNotPushOnly,
|
||||||
|
"signature script is not push only")
|
||||||
|
}
|
||||||
|
|
||||||
si := new(ScriptInfo)
|
si := new(ScriptInfo)
|
||||||
si.PkScriptClass = typeOfScript(scriptVersion, pkScript)
|
si.PkScriptClass = typeOfScript(scriptVersion, pkScript)
|
||||||
|
|
||||||
// Can't have a signature script that doesn't just push data.
|
si.ExpectedInputs = expectedInputs(pkScript, si.PkScriptClass)
|
||||||
if !isPushOnly(sigPops) {
|
|
||||||
return nil, scriptError(ErrNotPushOnly,
|
|
||||||
"signature script is not push only")
|
|
||||||
}
|
|
||||||
|
|
||||||
si.ExpectedInputs = expectedInputs(pkPops, si.PkScriptClass)
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// Count sigops taking into account pay-to-script-hash.
|
// Count sigops taking into account pay-to-script-hash.
|
||||||
case si.PkScriptClass == ScriptHashTy && bip16 && !segwit:
|
case si.PkScriptClass == ScriptHashTy && bip16 && !segwit:
|
||||||
// The pay-to-hash-script is the final data push of the
|
// The redeem script is the final data push of the signature script.
|
||||||
// signature script.
|
redeemScript := finalOpcodeData(scriptVersion, sigScript)
|
||||||
script := sigPops[len(sigPops)-1].data
|
reedeemClass := typeOfScript(scriptVersion, redeemScript)
|
||||||
shPops, err := parseScript(script)
|
rsInputs := expectedInputs(redeemScript, reedeemClass)
|
||||||
if err != nil {
|
if rsInputs == -1 {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
redeemClass := typeOfScript(scriptVersion, script)
|
|
||||||
shInputs := expectedInputs(shPops, redeemClass)
|
|
||||||
if shInputs == -1 {
|
|
||||||
si.ExpectedInputs = -1
|
si.ExpectedInputs = -1
|
||||||
} else {
|
} else {
|
||||||
si.ExpectedInputs += shInputs
|
si.ExpectedInputs += rsInputs
|
||||||
}
|
}
|
||||||
si.SigOps = getSigOpCount(shPops, true)
|
si.SigOps = countSigOpsV0(redeemScript, true)
|
||||||
|
|
||||||
// All entries pushed to stack (or are OP_RESERVED and exec
|
// All entries pushed to stack (or are OP_RESERVED and exec
|
||||||
// will fail).
|
// will fail).
|
||||||
si.NumInputs = len(sigPops)
|
si.NumInputs = numInputs
|
||||||
|
|
||||||
// If segwit is active, and this is a regular p2wkh output, then we'll
|
// If segwit is active, and this is a regular p2wkh output, then we'll
|
||||||
// treat the script as a p2pkh output in essence.
|
// treat the script as a p2pkh output in essence.
|
||||||
|
@ -610,10 +614,8 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
||||||
|
|
||||||
// Extract the pushed witness program from the sigScript so we
|
// Extract the pushed witness program from the sigScript so we
|
||||||
// can determine the number of expected inputs.
|
// can determine the number of expected inputs.
|
||||||
pkPops, _ := parseScript(sigScript[1:])
|
|
||||||
|
|
||||||
redeemClass := typeOfScript(scriptVersion, sigScript[1:])
|
redeemClass := typeOfScript(scriptVersion, sigScript[1:])
|
||||||
shInputs := expectedInputs(pkPops, redeemClass)
|
shInputs := expectedInputs(sigScript[1:], redeemClass)
|
||||||
if shInputs == -1 {
|
if shInputs == -1 {
|
||||||
si.ExpectedInputs = -1
|
si.ExpectedInputs = -1
|
||||||
} else {
|
} else {
|
||||||
|
@ -623,18 +625,14 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
||||||
si.SigOps = GetWitnessSigOpCount(sigScript, pkScript, witness)
|
si.SigOps = GetWitnessSigOpCount(sigScript, pkScript, witness)
|
||||||
|
|
||||||
si.NumInputs = len(witness)
|
si.NumInputs = len(witness)
|
||||||
si.NumInputs += len(sigPops)
|
si.NumInputs += numInputs
|
||||||
|
|
||||||
// If segwit is active, and this is a p2wsh output, then we'll need to
|
// If segwit is active, and this is a p2wsh output, then we'll need to
|
||||||
// examine the witness script to generate accurate script info.
|
// examine the witness script to generate accurate script info.
|
||||||
case si.PkScriptClass == WitnessV0ScriptHashTy && segwit:
|
case si.PkScriptClass == WitnessV0ScriptHashTy && segwit:
|
||||||
// The witness script is the final element of the witness
|
|
||||||
// stack.
|
|
||||||
witnessScript := witness[len(witness)-1]
|
witnessScript := witness[len(witness)-1]
|
||||||
pops, _ := parseScript(witnessScript)
|
|
||||||
|
|
||||||
redeemClass := typeOfScript(scriptVersion, witnessScript)
|
redeemClass := typeOfScript(scriptVersion, witnessScript)
|
||||||
shInputs := expectedInputs(pops, redeemClass)
|
shInputs := expectedInputs(witnessScript, redeemClass)
|
||||||
if shInputs == -1 {
|
if shInputs == -1 {
|
||||||
si.ExpectedInputs = -1
|
si.ExpectedInputs = -1
|
||||||
} else {
|
} else {
|
||||||
|
@ -645,11 +643,11 @@ func CalcScriptInfo(sigScript, pkScript []byte, witness wire.TxWitness,
|
||||||
si.NumInputs = len(witness)
|
si.NumInputs = len(witness)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
si.SigOps = getSigOpCount(pkPops, true)
|
si.SigOps = countSigOpsV0(pkScript, true)
|
||||||
|
|
||||||
// All entries pushed to stack (or are OP_RESERVED and exec
|
// All entries pushed to stack (or are OP_RESERVED and exec
|
||||||
// will fail).
|
// will fail).
|
||||||
si.NumInputs = len(sigPops)
|
si.NumInputs = numInputs
|
||||||
}
|
}
|
||||||
|
|
||||||
return si, nil
|
return si, nil
|
||||||
|
|
Loading…
Reference in a new issue