decred.org/dcrdex@v1.0.3/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 }