decred.org/dcrdex@v1.0.5/dex/networks/dcr/script_test.go (about)

     1  package dcr
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"strings"
    10  	"testing"
    11  
    12  	"decred.org/dcrdex/dex"
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrd/chaincfg/v3"
    15  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    16  	"github.com/decred/dcrd/dcrutil/v4"
    17  	"github.com/decred/dcrd/txscript/v4"
    18  	"github.com/decred/dcrd/txscript/v4/stdaddr"
    19  	"github.com/decred/dcrd/wire"
    20  )
    21  
    22  var (
    23  	tStamp        = int64(1574264305)
    24  	tParams       = chaincfg.MainNetParams()
    25  	invalidScript = []byte{txscript.OP_DATA_75}
    26  )
    27  
    28  func randBytes(l int) []byte {
    29  	b := make([]byte, l)
    30  	_, _ = rand.Read(b)
    31  	return b
    32  }
    33  
    34  func newPubKey() []byte {
    35  	prk, err := secp256k1.GeneratePrivateKey()
    36  	if err != nil {
    37  		fmt.Printf("error creating pubkey: %v\n", err)
    38  	}
    39  	return prk.PubKey().SerializeCompressed()
    40  }
    41  
    42  type tAddrs struct {
    43  	pkh       *stdaddr.AddressPubKeyHashEcdsaSecp256k1V0
    44  	sh        *stdaddr.AddressScriptHashV0
    45  	pk1       *stdaddr.AddressPubKeyEcdsaSecp256k1V0
    46  	pk2       *stdaddr.AddressPubKeyEcdsaSecp256k1V0
    47  	edwards   *stdaddr.AddressPubKeyHashEd25519V0
    48  	schnorrPK *stdaddr.AddressPubKeySchnorrSecp256k1V0
    49  	multiSig  []byte
    50  }
    51  
    52  func multiSigScript(pubkeys []*stdaddr.AddressPubKeyEcdsaSecp256k1V0, numReq int64) ([]byte, error) {
    53  	builder := txscript.NewScriptBuilder().AddInt64(numReq)
    54  	for _, key := range pubkeys {
    55  		script, err := AddressScript(key)
    56  		if err != nil {
    57  			return nil, err
    58  		}
    59  		builder.AddData(script)
    60  	}
    61  	builder.AddInt64(int64(len(pubkeys))).AddOp(txscript.OP_CHECKMULTISIG)
    62  	return builder.Script()
    63  }
    64  
    65  func testAddresses() *tAddrs {
    66  	p2pkh, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
    67  	pk1, _ := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0Raw(newPubKey(), tParams)
    68  	pk2, _ := stdaddr.NewAddressPubKeyEcdsaSecp256k1V0Raw(newPubKey(), tParams)
    69  	edwards, _ := stdaddr.NewAddressPubKeyHashEd25519V0(randBytes(20), tParams)
    70  	schnorrPK, _ := stdaddr.NewAddressPubKeySchnorrSecp256k1V0Raw(newPubKey(), tParams)
    71  	multiSig, _ := multiSigScript([]*stdaddr.AddressPubKeyEcdsaSecp256k1V0{pk1, pk2}, 1)
    72  	p2sh, _ := stdaddr.NewAddressScriptHashV0(multiSig, tParams)
    73  	return &tAddrs{
    74  		pkh:       p2pkh,
    75  		sh:        p2sh,
    76  		pk1:       pk1,
    77  		pk2:       pk2,
    78  		edwards:   edwards,
    79  		schnorrPK: schnorrPK,
    80  		multiSig:  multiSig,
    81  	}
    82  }
    83  
    84  func TestExtractBondDetailsV0(t *testing.T) {
    85  	bondScript, _ := hex.DecodeString("041d013663b17576a91465b064a4c6bbb1b57362b5b390c00dbd33bdb2b888ac")
    86  	lockTime, pkh, err := ExtractBondDetailsV0(0, bondScript)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	wantLock := uint32(1664483613)
    91  	if lockTime != wantLock {
    92  		t.Errorf("wanted locktime %d, got %d", wantLock, lockTime)
    93  	}
    94  	wantPkh, _ := hex.DecodeString("65b064a4c6bbb1b57362b5b390c00dbd33bdb2b8")
    95  	if !bytes.Equal(pkh, wantPkh) {
    96  		t.Errorf("wanted pkh %x, got %x", wantPkh, pkh)
    97  	}
    98  }
    99  
   100  // Test ScriptType methods and pkScript identification via ParseScriptType.
   101  // TestInputInfo verifies combined P2SH pkScript + redeemscript identification.
   102  // This test also verifies ExtractScriptHashV0.
   103  func TestScriptType(t *testing.T) {
   104  	addrs := testAddresses()
   105  
   106  	var scriptType ScriptType
   107  	parse := func(addr stdaddr.Address, stakeOpcode byte) ([]byte, ScriptType) {
   108  		t.Helper()
   109  		_, pkScript := addr.PaymentScript()
   110  		if stakeOpcode != 0 {
   111  			pkScript = append([]byte{stakeOpcode}, pkScript...)
   112  		}
   113  		scriptType = ParseScriptType(0, pkScript)
   114  		return pkScript, scriptType
   115  	}
   116  
   117  	check := func(name string, res bool, exp bool) {
   118  		t.Helper()
   119  		if res != exp {
   120  			t.Fatalf("%s check failed. wanted %t, got %t", name, exp, res)
   121  		}
   122  	}
   123  
   124  	parse(addrs.pk1, 0)
   125  	check("p2pk-IsP2PK", scriptType.IsP2PK(), true)
   126  	check("p2pk-IsP2PKH", scriptType.IsP2PKH(), false)
   127  	check("p2pk-IsP2SH", scriptType.IsP2SH(), false)
   128  	check("p2pk-IsStake", scriptType.IsStake(), false)
   129  	check("p2pk-IsMultiSig", scriptType.IsMultiSig(), false)
   130  
   131  	parse(addrs.pkh, 0)
   132  	check("p2pkh-IsP2PK", scriptType.IsP2PK(), false)
   133  	check("p2pkh-IsP2PKH", scriptType.IsP2PKH(), true)
   134  	check("p2pkh-IsP2SH", scriptType.IsP2SH(), false)
   135  	check("p2pkh-IsStake", scriptType.IsStake(), false)
   136  	check("p2pkh-IsMultiSig", scriptType.IsMultiSig(), false)
   137  
   138  	parse(addrs.pkh, txscript.OP_SSGEN)
   139  	check("stakePKH-IsP2PK", scriptType.IsP2PK(), false)
   140  	check("stakePKH-IsP2PKH", scriptType.IsP2PKH(), true)
   141  	check("stakePKH-IsP2SH", scriptType.IsP2SH(), false)
   142  	check("stakePKH-IsStake", scriptType.IsStake(), true)
   143  	check("stakePKH-IsMultiSig", scriptType.IsMultiSig(), false)
   144  
   145  	parse(addrs.edwards, 0)
   146  	check("edwards-IsP2PK", scriptType.IsP2PK(), false)
   147  	check("edwards-IsP2PKH", scriptType.IsP2PKH(), true)
   148  	check("edwards-IsP2SH", scriptType.IsP2SH(), false)
   149  	check("edwards-IsStake", scriptType.IsStake(), false)
   150  	check("edwards-IsMultiSig", scriptType.IsMultiSig(), false)
   151  
   152  	parse(addrs.schnorrPK, 0)
   153  	check("schnorrPK-IsP2PK", scriptType.IsP2PK(), true)
   154  	check("schnorrPK-IsP2PKH", scriptType.IsP2PKH(), false)
   155  	check("schnorrPK-IsP2SH", scriptType.IsP2SH(), false)
   156  	check("schnorrPK-IsStake", scriptType.IsStake(), false)
   157  	check("schnorrPK-IsMultiSig", scriptType.IsMultiSig(), false)
   158  
   159  	pkScript, scriptType := parse(addrs.sh, 0)
   160  	check("p2sh-IsP2PK", scriptType.IsP2PK(), false)
   161  	check("p2sh-IsP2PKH", scriptType.IsP2PKH(), false)
   162  	check("p2sh-IsP2SH", scriptType.IsP2SH(), true)
   163  	check("p2pkh-IsStake", scriptType.IsStake(), false)
   164  
   165  	scriptHash := ExtractScriptHashV0(pkScript)
   166  	if scriptHash == nil {
   167  		t.Fatalf("error extracting non-stake script hash")
   168  	}
   169  
   170  	// Identification of a pkScript combined with a multisig redeemscript is
   171  	// verified in TestInputInfo; here we just test the IsMultiSig method.
   172  	scriptType |= ScriptMultiSig
   173  	check("p2sh-IsMultiSig", scriptType.IsMultiSig(), true)
   174  	// retest other Is methods now that we've set the multisig bit
   175  	check("p2sh-IsP2PKH", scriptType.IsP2PKH(), false)
   176  	check("p2sh-IsP2SH", scriptType.IsP2SH(), true)
   177  	check("p2pkh-IsStake", scriptType.IsStake(), false)
   178  
   179  	pkScript, scriptType = parse(addrs.sh, txscript.OP_SSGEN)
   180  	check("stake-p2sh-IsP2PK", scriptType.IsP2PK(), false)
   181  	check("stake-p2sh-IsP2PKH", scriptType.IsP2PKH(), false)
   182  	check("stake-p2sh-IsP2SH", scriptType.IsP2SH(), true)
   183  	check("stake-p2pkh-IsStake", scriptType.IsStake(), true)
   184  
   185  	scriptType |= ScriptMultiSig
   186  	check("stake-p2sh-IsMultiSig", scriptType.IsMultiSig(), true)
   187  	check("stake-p2sh-IsP2PKH", scriptType.IsP2PKH(), false)
   188  	check("stake-p2sh-IsP2SH", scriptType.IsP2SH(), true)
   189  	check("stake-p2pkh-IsStake", scriptType.IsStake(), true)
   190  
   191  	scriptHash = ExtractScriptHashV0(pkScript)
   192  	if scriptHash == nil {
   193  		t.Fatalf("error extracting stake script hash")
   194  	}
   195  }
   196  
   197  func TestMakeContract(t *testing.T) {
   198  	ra, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   199  	recipient := ra.String()
   200  	sa, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   201  	sender := sa.String()
   202  	badAddr := "notanaddress"
   203  
   204  	// Bad recipient
   205  	_, err := MakeContract(badAddr, sender, randBytes(32), tStamp, tParams)
   206  	if err == nil {
   207  		t.Fatalf("no error for bad recipient")
   208  	}
   209  	// Wrong recipient address type
   210  	p2sh, _ := stdaddr.NewAddressScriptHashV0(randBytes(50), tParams)
   211  	_, err = MakeContract(p2sh.String(), sender, randBytes(32), tStamp, tParams)
   212  	if err == nil {
   213  		t.Fatalf("no error for wrong recipient address type")
   214  	}
   215  
   216  	// Bad sender
   217  	_, err = MakeContract(recipient, badAddr, randBytes(32), tStamp, tParams)
   218  	if err == nil {
   219  		t.Fatalf("no error for bad sender")
   220  	}
   221  	// Wrong sender address type.
   222  	altAddr, _ := stdaddr.NewAddressPubKeyHashEd25519V0(randBytes(20), tParams)
   223  	_, err = MakeContract(recipient, altAddr.String(), randBytes(32), tStamp, tParams)
   224  	if err == nil {
   225  		t.Fatalf("no error for wrong sender address type")
   226  	}
   227  
   228  	// Bad secret hash
   229  	_, err = MakeContract(recipient, sender, randBytes(10), tStamp, tParams)
   230  	if err == nil {
   231  		t.Fatalf("no error for bad secret hash")
   232  	}
   233  
   234  	// Good to go
   235  	_, err = MakeContract(recipient, sender, randBytes(32), tStamp, tParams)
   236  	if err != nil {
   237  		t.Fatalf("error for valid contract parameters: %v", err)
   238  	}
   239  }
   240  
   241  func TestIsDust(t *testing.T) {
   242  	pkScript := []byte{0x76, 0xa9, 0x21, 0x03, 0x2f, 0x7e, 0x43,
   243  		0x0a, 0xa4, 0xc9, 0xd1, 0x59, 0x43, 0x7e, 0x84, 0xb9,
   244  		0x75, 0xdc, 0x76, 0xd9, 0x00, 0x3b, 0xf0, 0x92, 0x2c,
   245  		0xf3, 0xaa, 0x45, 0x28, 0x46, 0x4b, 0xab, 0x78, 0x0d,
   246  		0xba, 0x5e, 0x88, 0xac}
   247  
   248  	tests := []struct {
   249  		name     string // test description
   250  		txOut    wire.TxOut
   251  		relayFee uint64 // minimum relay transaction fee.
   252  		isDust   bool
   253  	}{
   254  		{
   255  			// Zero-valued output fails txscript.IsUnspendable.
   256  			"zero value with zero relay fee",
   257  			wire.TxOut{Value: 0, PkScript: pkScript},
   258  			0,
   259  			true,
   260  		},
   261  		{
   262  			// Zero value is dust with any relay fee"
   263  			"zero value with very small tx fee",
   264  			wire.TxOut{Value: 0, PkScript: pkScript},
   265  			1,
   266  			true,
   267  		},
   268  		{
   269  			"38 byte public key script with value 6419",
   270  			wire.TxOut{Value: 6419, PkScript: pkScript},
   271  			10,
   272  			true,
   273  		},
   274  		{
   275  			"38 byte public key script with value 6420",
   276  			wire.TxOut{Value: 6420, PkScript: pkScript},
   277  			10,
   278  			false,
   279  		},
   280  		{
   281  			// Maximum int64 value causes overflow.
   282  			"maximum int64 value",
   283  			wire.TxOut{Value: 1<<63 - 1, PkScript: pkScript},
   284  			1<<63 - 1,
   285  			true,
   286  		},
   287  		{
   288  			// Unspendable pkScript due to an invalid public key
   289  			// script.
   290  			"unspendable pkScript",
   291  			wire.TxOut{Value: 5000, PkScript: []byte{0x01}},
   292  			0, // no relay fee
   293  			true,
   294  		},
   295  	}
   296  	for _, test := range tests {
   297  		res := IsDust(&test.txOut, test.relayFee)
   298  		if res != test.isDust {
   299  			t.Fatalf("Dust test '%s' failed: want %v got %v",
   300  				test.name, test.isDust, res)
   301  		}
   302  	}
   303  }
   304  
   305  // Test InputInfo, ParseScriptType, ExtractScriptData, ExtractScriptAddrs, and
   306  // ExtractScriptHash with a non-standard script.
   307  func Test_nonstandardScript(t *testing.T) {
   308  	// The tx hash of a DCR testnet swap contract.
   309  	contractTx, err := chainhash.NewHashFromStr("4a14a2d79c1374d286ebd68d2c104343bcf8be44ed54045b5963fbf73667cecc")
   310  	if err != nil {
   311  		t.Fatal(err)
   312  	}
   313  	vout := 0 // the contract output index, 1 is change
   314  
   315  	// The contract output's P2SH pkScript and the corresponding redeem script
   316  	// (the actual contract).
   317  	scriptVersion := uint16(0)
   318  	pkScript, _ := hex.DecodeString("a9146d4bc656b3287a0e6b0d38802db6400f7053111787") // verboseTx.Vout[vout].ScriptPubKey.Hex from getrawtransaction(verbose)
   319  	contractScript, _ := hex.DecodeString("6382012088c020c6de3217594af525fb" +
   320  		"57eaf1f2aae04c305ddc67d465edd325151685fc5a5e428876a914479eddda81" +
   321  		"b6ed289515f2dbcc95f05ce80dff466704fe03865eb17576a91498a67ed502ad" +
   322  		"b04173d88fb1ef92d0317711c3816888ac")
   323  
   324  	scriptType := ParseScriptType(scriptVersion, pkScript)
   325  	if !scriptType.IsP2SH() {
   326  		t.Fatalf("script was not P2SH, got %v (see script.go)", scriptType)
   327  	}
   328  
   329  	// Double check that the pkScript's script hash matches the hash of the
   330  	// redeem (contract) script.
   331  	scriptHash := ExtractScriptHash(scriptVersion, pkScript)
   332  	if scriptHash == nil {
   333  		t.Fatalf("ExtractScriptHash failed")
   334  	}
   335  	if !bytes.Equal(dcrutil.Hash160(contractScript), scriptHash) {
   336  		t.Fatalf("script hash check failed for output %s,%d", contractTx, vout)
   337  	}
   338  
   339  	// ExtractScriptAddrs should detect non-standard scripts.
   340  	chainParams := chaincfg.TestNet3Params()
   341  	scriptType, _ = ExtractScriptAddrs(scriptVersion, contractScript, chainParams)
   342  	if scriptType != ScriptUnsupported {
   343  		t.Errorf("expected non-standard script")
   344  	}
   345  	// ... as should ExtractScriptData
   346  	scriptType, _, _ = ExtractScriptData(scriptVersion, contractScript, chainParams)
   347  	if scriptType != ScriptUnsupported {
   348  		t.Errorf("expected non-standard script")
   349  	}
   350  
   351  	// InputInfo currently calls ExtractScriptAddrs at the time of writing, but
   352  	// InputInfo should error regardless.
   353  	spendInfo, err := InputInfo(scriptVersion, pkScript, contractScript, chainParams)
   354  	if err != nil {
   355  		t.Fatalf("InputInfo failed: %v", err)
   356  	}
   357  	if spendInfo.ScriptType != ScriptP2SH {
   358  		t.Errorf("ScriptType should still be P2SH")
   359  	}
   360  	if !spendInfo.NonStandardScript {
   361  		t.Errorf("contract script should be non-standard")
   362  	}
   363  }
   364  
   365  func TestExtractScriptAddrs(t *testing.T) {
   366  	addrs := testAddresses()
   367  	type test struct {
   368  		addr   stdaddr.Address
   369  		nonStd bool
   370  		script []byte
   371  		pk     int
   372  		pkh    int
   373  		sigs   int
   374  	}
   375  
   376  	tests := []test{
   377  		{addrs.pkh, false, nil, 0, 1, 1},
   378  		{addrs.sh, false, nil, 0, 1, 1},
   379  		{nil, false, addrs.multiSig, 2, 0, 1},
   380  		{nil, true, []byte{1}, 0, 0, 0},
   381  	}
   382  
   383  	for _, tt := range tests {
   384  		s := tt.script
   385  		if s == nil {
   386  			_, s = tt.addr.PaymentScript()
   387  		}
   388  		scriptType, scriptAddrs := ExtractScriptAddrs(0, s, tParams)
   389  		if (scriptType == ScriptUnsupported) != tt.nonStd {
   390  			t.Fatalf("expected nonStd=%v, got %v", tt.nonStd, scriptType)
   391  		}
   392  		if len(scriptAddrs.PubKeys) != tt.pk {
   393  			t.Fatalf("wrong number of hash addresses. wanted %d, got %d", tt.pk, len(scriptAddrs.PubKeys))
   394  		}
   395  		if len(scriptAddrs.PkHashes) != tt.pkh {
   396  			t.Fatalf("wrong number of pubkey-hash addresses. wanted %d, got %d", tt.pkh, len(scriptAddrs.PkHashes))
   397  		}
   398  		if scriptAddrs.NRequired != tt.sigs {
   399  			t.Fatalf("wrong number of required signatures. wanted %d, got %d", tt.sigs, scriptAddrs.NRequired)
   400  		}
   401  	}
   402  
   403  }
   404  
   405  func TestExtractSwapDetails(t *testing.T) {
   406  	rAddr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   407  	recipient := rAddr.String()
   408  	sAddr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   409  	sender := sAddr.String()
   410  	keyHash := randBytes(32)
   411  	contract, err := MakeContract(recipient, sender, keyHash, tStamp, tParams)
   412  	if err != nil {
   413  		t.Fatalf("error creating contract: %v", err)
   414  	}
   415  
   416  	sa, ra, lockTime, secretHash, err := ExtractSwapDetails(contract, tParams)
   417  	if err != nil {
   418  		t.Fatalf("error for valid contract: %v", err)
   419  	}
   420  	if sa.String() != sender {
   421  		t.Fatalf("sender address mismatch. wanted %s, got %s", sender, sa.String())
   422  	}
   423  	if ra.String() != recipient {
   424  		t.Fatalf("recipient address mismatch. wanted %s, got %s", recipient, ra.String())
   425  	}
   426  	if lockTime != uint64(tStamp) {
   427  		t.Fatalf("incorrect lock time. wanted 5, got %d", lockTime)
   428  	}
   429  	if !bytes.Equal(secretHash, keyHash) {
   430  		t.Fatalf("wrong secret hash. wanted %x, got %x", keyHash, secretHash)
   431  	}
   432  
   433  	// incorrect length
   434  	_, _, _, _, err = ExtractSwapDetails(contract[:len(contract)-1], tParams)
   435  	if err == nil {
   436  		t.Fatalf("no error for vandalized contract")
   437  	} else if !strings.HasPrefix(err.Error(), "incorrect swap contract length") {
   438  		t.Errorf("incorrect error for incorrect swap contract length: %v", err)
   439  	}
   440  
   441  	// bad secret size
   442  	contract[3] = 250
   443  	_, _, _, _, err = ExtractSwapDetails(contract, tParams)
   444  	if err == nil {
   445  		t.Fatalf("no error for contract with invalid secret size")
   446  	} else if !strings.HasPrefix(err.Error(), "invalid secret size") {
   447  		t.Errorf("incorrect error for invalid secret size: %v", err)
   448  	}
   449  }
   450  
   451  func TestInputInfo(t *testing.T) {
   452  	addrs := testAddresses()
   453  	var spendInfo *SpendInfo
   454  	var err error
   455  
   456  	check := func(name string, sigScriptSize uint32, scriptType ScriptType) {
   457  		if spendInfo.SigScriptSize != sigScriptSize {
   458  			t.Fatalf("%s: wrong SigScriptSize, wanted %d, got %d", name, sigScriptSize, spendInfo.SigScriptSize)
   459  		}
   460  		if spendInfo.ScriptType != scriptType {
   461  			t.Fatalf("%s: wrong ScriptType, wanted %d, got %d", name, scriptType, spendInfo.ScriptType)
   462  		}
   463  	}
   464  
   465  	var script []byte
   466  	payToAddr := func(addr stdaddr.Address, redeem []byte) {
   467  		t.Helper()
   468  		_, script = addr.PaymentScript()
   469  		spendInfo, err = InputInfo(0, script, redeem, tParams)
   470  		if err != nil {
   471  			t.Fatalf("InputInfo script: %v", err)
   472  		}
   473  	}
   474  
   475  	payToAddr(addrs.pkh, nil)
   476  	check("p2pkh", P2PKHSigScriptSize, ScriptP2PKH)
   477  
   478  	payToAddr(addrs.sh, addrs.multiSig)
   479  	check("p2sh", 74+uint32(len(addrs.multiSig))+1, ScriptP2SH|ScriptMultiSig)
   480  
   481  	payToAddr(addrs.sh, []byte{1, 2, 3})
   482  	check("p2sh with non-standard redeemscript", 0 /* unknown sigscript size */, ScriptP2SH)
   483  	if !spendInfo.NonStandardScript {
   484  		t.Fatalf("non-standard redeemscript was not reported as such")
   485  	}
   486  
   487  	// bad version
   488  	_, script = addrs.pkh.PaymentScript()
   489  	spendInfo, err = InputInfo(1, script, nil, tParams)
   490  	if err != dex.UnsupportedScriptError {
   491  		t.Fatalf("InputInfo should have errored for script version 1")
   492  	}
   493  
   494  	// Unknown script type.
   495  	_, err = InputInfo(0, []byte{0x02, 0x03}, nil, tParams)
   496  	if err == nil {
   497  		t.Fatalf("no error for unknown script type")
   498  	}
   499  
   500  	// InputInfo P2SH requires a redeem script
   501  	version, script := addrs.sh.PaymentScript()
   502  	_, err = InputInfo(version, script, nil, tParams)
   503  	if err == nil {
   504  		t.Fatalf("no error for missing redeem script")
   505  	}
   506  }
   507  
   508  func TestFindKeyPush(t *testing.T) {
   509  	rAddr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   510  	recipient := rAddr.String()
   511  	sAddr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(randBytes(20), tParams)
   512  	sender := sAddr.String()
   513  
   514  	secret := randBytes(32)
   515  	secretHash := sha256.Sum256(secret)
   516  	contract, _ := MakeContract(recipient, sender, secretHash[:], tStamp, tParams)
   517  	contractHash := dcrutil.Hash160(contract)
   518  	sigScript, err := RedeemP2SHContract(contract, randBytes(73), randBytes(33), secret)
   519  	if err != nil {
   520  		t.Fatalf("error creating redeem script: %v", err)
   521  	}
   522  
   523  	key, err := FindKeyPush(0, sigScript, contractHash, tParams)
   524  	if err != nil {
   525  		t.Fatalf("findKeyPush error: %v", err)
   526  	}
   527  	if !bytes.Equal(key, secret) {
   528  		t.Fatalf("wrong secret. expected %x, got %x", secret, key)
   529  	}
   530  
   531  	// Empty script is an error.
   532  	_, err = FindKeyPush(0, []byte{}, contractHash, tParams)
   533  	if err == nil {
   534  		t.Fatalf("no error for empty script")
   535  	}
   536  
   537  	// Bad script
   538  	_, err = FindKeyPush(0, invalidScript, contractHash, tParams)
   539  	if err == nil {
   540  		t.Fatalf("no error for bad script")
   541  	}
   542  
   543  	// Random but valid contract won't work.
   544  	contract, _ = MakeContract(recipient, sender, randBytes(32), tStamp, tParams)
   545  	sigScript, err = RedeemP2SHContract(contract, randBytes(73), randBytes(33), secret)
   546  	if err != nil {
   547  		t.Fatalf("error creating contract: %v", err)
   548  	}
   549  	_, err = FindKeyPush(0, sigScript, contractHash, tParams)
   550  	if err == nil {
   551  		t.Fatalf("no error for bad script")
   552  	}
   553  }
   554  
   555  func TestDataPrefixSize(t *testing.T) {
   556  	tests := []struct {
   557  		name    string
   558  		theData []byte
   559  		want    uint8
   560  	}{
   561  		{
   562  			name:    "empty",
   563  			theData: nil,
   564  			want:    0,
   565  		},
   566  		{
   567  			name:    "oneLow",
   568  			theData: []byte{16},
   569  			want:    0,
   570  		},
   571  		{
   572  			name:    "OP_1NEGATE",
   573  			theData: []byte{0x81},
   574  			want:    0,
   575  		},
   576  		{
   577  			name:    "oneHigh",
   578  			theData: []byte{17},
   579  			want:    1,
   580  		},
   581  		{
   582  			name:    "smallMultiByte0",
   583  			theData: make([]byte, 2),
   584  			want:    1,
   585  		},
   586  		{
   587  			name:    "smallMultiByte1",
   588  			theData: make([]byte, 75),
   589  			want:    1,
   590  		},
   591  		{
   592  			name:    "mediumMultiByte0",
   593  			theData: make([]byte, 76),
   594  			want:    2,
   595  		},
   596  		{
   597  			name:    "contract",
   598  			theData: make([]byte, SwapContractSize),
   599  			want:    2,
   600  		},
   601  		{
   602  			name:    "mediumMultiByte1",
   603  			theData: make([]byte, 255),
   604  			want:    2,
   605  		},
   606  		{
   607  			name:    "largeMultiByte0",
   608  			theData: make([]byte, 256),
   609  			want:    3,
   610  		},
   611  		{
   612  			name:    "largeMultiByte1",
   613  			theData: make([]byte, 65535),
   614  			want:    3,
   615  		},
   616  		{
   617  			name:    "megaMultiByte0",
   618  			theData: make([]byte, 65536),
   619  			want:    5,
   620  		},
   621  	}
   622  	for _, tt := range tests {
   623  		t.Run(tt.name, func(t *testing.T) {
   624  			if got := DataPrefixSize(tt.theData); got != tt.want {
   625  				t.Errorf("DataPrefixSize() = %v, want %v", got, tt.want)
   626  			}
   627  		})
   628  	}
   629  }
   630  
   631  func hexBytes(h string) []byte {
   632  	b, err := hex.DecodeString(h)
   633  	if err != nil {
   634  		panic(err.Error())
   635  	}
   636  	return b
   637  }
   638  
   639  func TestIsRefundScript(t *testing.T) {
   640  	tests := []struct {
   641  		name          string
   642  		scriptVersion uint16
   643  		sigScript     []byte
   644  		contract      []byte
   645  		want          bool
   646  	}{
   647  		{
   648  			"redeem",
   649  			0,
   650  			hexBytes("47304402203cf1e969830a6255d02e40a9333b502d802f0c17331e54dc5d8028fb6a3bd54c02202cfc3673c8013416e38dd27d3c96082a4f069cf296ca2bbba7d039308df1bdc401210227b951b91a01e11600cdd1d3e9f2894e2e38567b6883b9b3e7a4f99946a3d445209a5a58c653c2c384825bc4217443a2b3e3dead04db5e0586570c774706d97a0d514c616382012088c020c66b3b91cffadc613689cf9c391c7792307e5d5390407ad3e33b6ff0bf4a95218876a91425e5d9b138e16fa526bc765a721193da79fc5c32670420489d63b17576a9147f1686f0a6f1b0afd5b9efaee37d234b417ca2ee6888ac"),
   651  			hexBytes("6382012088c020c66b3b91cffadc613689cf9c391c7792307e5d5390407ad3e33b6ff0bf4a95218876a91425e5d9b138e16fa526bc765a721193da79fc5c32670420489d63b17576a9147f1686f0a6f1b0afd5b9efaee37d234b417ca2ee6888ac"),
   652  			false,
   653  		},
   654  		{
   655  			"refund",
   656  			0,
   657  			hexBytes("473044022063793a405b3c60a37180d009f191bf68a8ce0560093718612220b019596ebd9602201f9028644d45744279f5676db18ba3621760eb33d18d6ba74909a2e98393e40c012102bc03f292e7ec067c10cdcbc22eb9dc49b2693a1b7dd7c3b4c4d9a0bf054f3f2d004c616382012088c020eec3b3ffb1bf921701653437600eba8a8fc95dd5bbefa65e977b3d91db9ca6248876a9145ca2a115488f1b264591a014734d33443bbfa379670410bf3563b17576a914462748b29df61bd1fedd7dc1a953392aa2c05d996888ac"),
   658  			hexBytes("6382012088c020eec3b3ffb1bf921701653437600eba8a8fc95dd5bbefa65e977b3d91db9ca6248876a9145ca2a115488f1b264591a014734d33443bbfa379670410bf3563b17576a914462748b29df61bd1fedd7dc1a953392aa2c05d996888ac"),
   659  			true,
   660  		},
   661  	}
   662  	for _, tt := range tests {
   663  		t.Run(tt.name, func(t *testing.T) {
   664  			if is := IsRefundScript(tt.scriptVersion, tt.sigScript, tt.contract); is != tt.want {
   665  				t.Errorf("want %v, got %v", tt.want, is)
   666  			}
   667  		})
   668  	}
   669  }