input: add new ScriptIsOpReturn helper func

This commit is contained in:
Olaoluwa Osuntokun 2025-02-10 18:34:03 -08:00
parent 29afeb42fb
commit 127d3bed66
2 changed files with 84 additions and 0 deletions

View File

@ -0,0 +1,51 @@
package input
import (
"testing"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/txscript"
"github.com/stretchr/testify/require"
)
// FuzzScriptIsOpReturn fuzzes the ScriptIsOpReturn function.
func FuzzScriptIsOpReturn(f *testing.F) {
// Seed the corpus with some representative inputs.
f.Add([]byte{})
f.Add([]byte{txscript.OP_RETURN})
// Use our canonical ScriptBuilder to produce a valid OP_RETURN script.
builder := txscript.NewScriptBuilder()
builder.AddOp(txscript.OP_RETURN)
builder.AddData([]byte("valid data"))
script, err := builder.Script()
require.NoError(f, err)
f.Add(script)
// An example of a script that does not start with OP_RETURN.
f.Add([]byte{txscript.OP_DUP, txscript.OP_RETURN})
f.Fuzz(func(t *testing.T, pkScript []byte) {
result := ScriptIsOpReturn(pkScript)
var expected bool
if len(script) == 0 || script[0] != txscript.OP_RETURN {
expected = false
} else {
scriptClass, _, _, err := txscript.ExtractPkScriptAddrs(
pkScript, &chaincfg.MainNetParams,
)
if err != nil {
t.Fatalf("unable to extract pk script "+
"addresses: %v", err)
}
expected = scriptClass == txscript.NullDataTy
}
if result != expected {
t.Fatalf("for script %x, expected ScriptIsOpReturn=%v;"+
" got %v", script, expected, result)
}
})
}

View File

@ -3239,3 +3239,36 @@ func ComputeCommitmentPoint(commitSecret []byte) *btcec.PublicKey {
_, pubKey := btcec.PrivKeyFromBytes(commitSecret)
return pubKey
}
// ScriptIsOpReturn returns true if the passed script is an OP_RETURN script.
//
// Lifted from the txscript package:
// https://github.com/btcsuite/btcd/blob/cc26860b40265e1332cca8748c5dbaf3c81cc094/txscript/standard.go#L493-L526.
//
//nolint:ll
func ScriptIsOpReturn(script []byte) bool {
// A null script is of the form:
// OP_RETURN <optional data>
//
// Thus, it can either be a single OP_RETURN or an OP_RETURN followed by
// a data push up to MaxDataCarrierSize bytes.
// The script can't possibly be a null data script if it doesn't start
// with OP_RETURN. Fail fast to avoid more work below.
if len(script) < 1 || script[0] != txscript.OP_RETURN {
return false
}
// Single OP_RETURN.
if len(script) == 1 {
return true
}
// OP_RETURN followed by data push up to MaxDataCarrierSize bytes.
tokenizer := txscript.MakeScriptTokenizer(0, script[1:])
return tokenizer.Next() && tokenizer.Done() &&
(txscript.IsSmallInt(tokenizer.Opcode()) ||
tokenizer.Opcode() <= txscript.OP_PUSHDATA4) &&
len(tokenizer.Data()) <= txscript.MaxDataCarrierSize
}