This commit is contained in:
Daniel Katzan 2025-03-12 10:52:21 +02:00 committed by GitHub
commit 4931cdf595
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 13 deletions

View file

@ -504,25 +504,51 @@ func isNullDataScript(scriptVersion uint16, 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 entire scriptPubKey, including OP_RETURN and the payload, must not
// exceed 83 bytes by default.
// 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.
const MaxScriptPubKeySize = 83
// Check if the script size exceeds the maximum allowed size.
if len(script) > MaxScriptPubKeySize {
return false
}
// The script must start with OP_RETURN.
if len(script) < 1 || script[0] != OP_RETURN {
return false
}
// Single OP_RETURN.
// Single OP_RETURN (no payload).
if len(script) == 1 {
return true
}
// OP_RETURN followed by data push up to MaxDataCarrierSize bytes.
// Tokenize and validate the script after OP_RETURN.
tokenizer := MakeScriptTokenizer(scriptVersion, script[1:])
return tokenizer.Next() && tokenizer.Done() &&
(IsSmallInt(tokenizer.Opcode()) || tokenizer.Opcode() <= OP_PUSHDATA4) &&
len(tokenizer.Data()) <= MaxDataCarrierSize
for tokenizer.Next() {
opcode := tokenizer.Opcode()
// Allow small integer opcodes (OP_1 to OP_16).
if IsSmallInt(opcode) {
continue
}
// Allow valid data pushes.
if opcode <= OP_PUSHDATA4 {
// Ensure each data push is valid and within limits.
if len(tokenizer.Data()) > MaxDataCarrierSize {
return false
}
continue
}
// Any other opcode is invalid for a null data script.
return false
}
// Ensure the tokenizer successfully parsed the entire script.
return tokenizer.Done()
}
// scriptType returns the type of the script being inspected from the known

View file

@ -1032,11 +1032,10 @@ var scriptClassTests = []struct {
class: NonStandardTy,
},
{
// Almost nulldata, but add an additional opcode after the data
// to make it nonstandard.
name: "almost nulldata",
// nulldata, with combinations of op_code and pushdata
name: "nulldata with multiple pushes",
script: "RETURN 4 TRUE",
class: NonStandardTy,
class: NullDataTy,
},
// The next few are almost multisig (it is the more complex script type)
@ -1277,6 +1276,28 @@ func TestNullDataScript(t *testing.T) {
}
}
func TestIsNullDataScript(t *testing.T) {
tests := []struct {
name string
data []byte
expectedIsNullData bool
}{{
name: "multiple pushes",
data: hexToBytes("6a5d0f160100e6a233fc078088a5a9a30700"),
expectedIsNullData: true,
},
}
for i, test := range tests {
isNullData := isNullDataScript(0, test.data)
if isNullData != test.expectedIsNullData {
t.Errorf("IsNullDataScript: #%d (%s) wrong result -- "+
"got: %v, want: %v", i, test.name, isNullData,
test.expectedIsNullData)
continue
}
}
}
// TestNewScriptClass tests whether NewScriptClass returns a valid ScriptClass.
func TestNewScriptClass(t *testing.T) {
tests := []struct {