From b77654f8d4dc593d15bcfe5cfc8783606745fb69 Mon Sep 17 00:00:00 2001 From: DanielKrawisz Date: Fri, 21 Oct 2016 09:37:48 -0500 Subject: [PATCH] txscript: Add null data script creator This adds a new function named NullDataScript to the txscript package that returns a provably-pruneable OP_RETURN script with the provided data. The function will return an error if the provided data is larger than the maximum allowed length for a nulldata script to be be considered standard. --- txscript/standard.go | 10 +++++ txscript/standard_test.go | 86 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/txscript/standard.go b/txscript/standard.go index f64ff099..69a869b0 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -351,6 +351,16 @@ func PayToAddrScript(addr btcutil.Address) ([]byte, error) { return nil, ErrUnsupportedAddress } +// NullDataScript creates a provably prunable script +// containing OP_RETURN followed by the passed data. +func NullDataScript(data []byte) ([]byte, error) { + if len(data) > MaxDataCarrierSize { + return nil, ErrStackLongScript + } + + return NewScriptBuilder().AddOp(OP_RETURN).AddData(data).Script() +} + // MultiSigScript returns a valid script for a multisignature redemption where // nrequired of the keys in pubkeys are required to have signed the transaction // for success. An ErrBadNumRequired will be returned if nrequired is larger diff --git a/txscript/standard_test.go b/txscript/standard_test.go index 3c199dd7..7a37c5df 100644 --- a/txscript/standard_test.go +++ b/txscript/standard_test.go @@ -1028,3 +1028,89 @@ func TestStringifyClass(t *testing.T) { } } } + +// TestNullDataScript tests whether NullDataScript returns a valid script. +func TestNullDataScript(t *testing.T) { + tiny := hexToBytes("01") + short := hexToBytes("0102030405060708090a0b0c0d0e0f1" + + "01112131415161718") + shortExp := hexToBytes("6a180102030405060708090a0b0c0d0e0f1" + + "01112131415161718") + justRight := hexToBytes("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f20212223242526272829" + + "2a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + + "4445464748494a4b4c4d4e4f") + tooLong := hexToBytes("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f20212223242526272829" + + "2a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243" + + "4445464748494a4b4c4d4e4f50") + + tests := []struct { + name string + data []byte + valid bool + expected []byte + }{ + { + name: "small data", + data: tiny, + valid: true, + expected: []byte{0x6a, 0x51}, + }, + { + name: "data of size before OP_PUSHDATA1 is needed", + data: short, + valid: true, + expected: shortExp, + }, + { + name: "just right", + data: justRight, + valid: true, + expected: append([]byte{ + OP_RETURN, OP_PUSHDATA1, 80}, + justRight...), + }, + { + name: "too big", + data: tooLong, + valid: false, + expected: nil, + }, + } + + for _, test := range tests { + script, err := NullDataScript(test.data) + + if !test.valid { + if err == nil { + t.Errorf("NullDataScript test %v: expected error but none was returned. ", + test.name) + } + + continue + } + + if err != nil { + t.Errorf("NullDataScript test %v: Unexpected error returned %v ", + test.name, err) + + continue + } + + // Check that the expected result was returned. + if !bytes.Equal(script, test.expected) { + t.Errorf("NullDataScript test %v: Expected %x, got %x", + test.name, test.expected, script) + + continue + } + + // Check that the script has the correct type. + scriptType := GetScriptClass(script) + if scriptType != NullDataTy { + t.Errorf("NullDataScript test %v: Expected NullDataTy, got %v", + test.name, scriptType) + } + } +}