github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/txscript/standard_test.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package txscript_test 7 8 import ( 9 "bytes" 10 "encoding/hex" 11 "reflect" 12 "testing" 13 14 "github.com/BlockABC/godash/chaincfg" 15 "github.com/BlockABC/godash/txscript" 16 "github.com/BlockABC/godashutil" 17 ) 18 19 // decodeHex decodes the passed hex string and returns the resulting bytes. It 20 // panics if an error occurs. This is only used in the tests as a helper since 21 // the only way it can fail is if there is an error in the test source code. 22 func decodeHex(hexStr string) []byte { 23 b, err := hex.DecodeString(hexStr) 24 if err != nil { 25 panic("invalid hex string in test source: err " + err.Error() + 26 ", hex: " + hexStr) 27 } 28 29 return b 30 } 31 32 // mustParseShortForm parses the passed short form script and returns the 33 // resulting bytes. It panics if an error occurs. This is only used in the 34 // tests as a helper since the only way it can fail is if there is an error in 35 // the test source code. 36 func mustParseShortForm(script string) []byte { 37 s, err := parseShortForm(script) 38 if err != nil { 39 panic("invalid short form script in test source: err " + 40 err.Error() + ", script: " + script) 41 } 42 43 return s 44 } 45 46 // newAddressPubKey returns a new godashutil.AddressPubKey from the provided 47 // serialized public key. It panics if an error occurs. This is only used in 48 // the tests as a helper since the only way it can fail is if there is an error 49 // in the test source code. 50 func newAddressPubKey(serializedPubKey []byte) godashutil.Address { 51 addr, err := godashutil.NewAddressPubKey(serializedPubKey, 52 &chaincfg.MainNetParams) 53 if err != nil { 54 panic("invalid public key in test source") 55 } 56 57 return addr 58 } 59 60 // newAddressPubKeyHash returns a new godashutil.AddressPubKeyHash from the 61 // provided hash. It panics if an error occurs. This is only used in the tests 62 // as a helper since the only way it can fail is if there is an error in the 63 // test source code. 64 func newAddressPubKeyHash(pkHash []byte) godashutil.Address { 65 addr, err := godashutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams) 66 if err != nil { 67 panic("invalid public key hash in test source") 68 } 69 70 return addr 71 } 72 73 // newAddressScriptHash returns a new godashutil.AddressScriptHash from the 74 // provided hash. It panics if an error occurs. This is only used in the tests 75 // as a helper since the only way it can fail is if there is an error in the 76 // test source code. 77 func newAddressScriptHash(scriptHash []byte) godashutil.Address { 78 addr, err := godashutil.NewAddressScriptHashFromHash(scriptHash, 79 &chaincfg.MainNetParams) 80 if err != nil { 81 panic("invalid script hash in test source") 82 } 83 84 return addr 85 } 86 87 // TestExtractPkScriptAddrs ensures that extracting the type, addresses, and 88 // number of required signatures from PkScripts works as intended. 89 func TestExtractPkScriptAddrs(t *testing.T) { 90 t.Parallel() 91 92 tests := []struct { 93 name string 94 script []byte 95 addrs []godashutil.Address 96 reqSigs int 97 class txscript.ScriptClass 98 }{ 99 { 100 name: "standard p2pk with compressed pubkey (0x02)", 101 script: decodeHex("2102192d74d0cb94344c9569c2e7790157" + 102 "3d8d7903c3ebec3a957724895dca52c6b4ac"), 103 addrs: []godashutil.Address{ 104 newAddressPubKey(decodeHex("02192d74d0cb94344" + 105 "c9569c2e77901573d8d7903c3ebec3a95772" + 106 "4895dca52c6b4")), 107 }, 108 reqSigs: 1, 109 class: txscript.PubKeyTy, 110 }, 111 { 112 name: "standard p2pk with uncompressed pubkey (0x04)", 113 script: decodeHex("410411db93e1dcdb8a016b49840f8c53bc" + 114 "1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb" + 115 "84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643" + 116 "f656b412a3ac"), 117 addrs: []godashutil.Address{ 118 newAddressPubKey(decodeHex("0411db93e1dcdb8a0" + 119 "16b49840f8c53bc1eb68a382e97b1482ecad" + 120 "7b148a6909a5cb2e0eaddfb84ccf9744464f" + 121 "82e160bfa9b8b64f9d4c03f999b8643f656b" + 122 "412a3")), 123 }, 124 reqSigs: 1, 125 class: txscript.PubKeyTy, 126 }, 127 { 128 name: "standard p2pk with hybrid pubkey (0x06)", 129 script: decodeHex("4106192d74d0cb94344c9569c2e7790157" + 130 "3d8d7903c3ebec3a957724895dca52c6b40d45264838" + 131 "c0bd96852662ce6a847b197376830160c6d2eb5e6a4c" + 132 "44d33f453eac"), 133 addrs: []godashutil.Address{ 134 newAddressPubKey(decodeHex("06192d74d0cb94344" + 135 "c9569c2e77901573d8d7903c3ebec3a95772" + 136 "4895dca52c6b40d45264838c0bd96852662c" + 137 "e6a847b197376830160c6d2eb5e6a4c44d33" + 138 "f453e")), 139 }, 140 reqSigs: 1, 141 class: txscript.PubKeyTy, 142 }, 143 { 144 name: "standard p2pk with compressed pubkey (0x03)", 145 script: decodeHex("2103b0bd634234abbb1ba1e986e884185c" + 146 "61cf43e001f9137f23c2c409273eb16e65ac"), 147 addrs: []godashutil.Address{ 148 newAddressPubKey(decodeHex("03b0bd634234abbb1" + 149 "ba1e986e884185c61cf43e001f9137f23c2c" + 150 "409273eb16e65")), 151 }, 152 reqSigs: 1, 153 class: txscript.PubKeyTy, 154 }, 155 { 156 name: "2nd standard p2pk with uncompressed pubkey (0x04)", 157 script: decodeHex("4104b0bd634234abbb1ba1e986e884185c" + 158 "61cf43e001f9137f23c2c409273eb16e6537a576782e" + 159 "ba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c" + 160 "1e0908ef7bac"), 161 addrs: []godashutil.Address{ 162 newAddressPubKey(decodeHex("04b0bd634234abbb1" + 163 "ba1e986e884185c61cf43e001f9137f23c2c" + 164 "409273eb16e6537a576782eba668a7ef8bd3" + 165 "b3cfb1edb7117ab65129b8a2e681f3c1e090" + 166 "8ef7b")), 167 }, 168 reqSigs: 1, 169 class: txscript.PubKeyTy, 170 }, 171 { 172 name: "standard p2pk with hybrid pubkey (0x07)", 173 script: decodeHex("4107b0bd634234abbb1ba1e986e884185c" + 174 "61cf43e001f9137f23c2c409273eb16e6537a576782e" + 175 "ba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c" + 176 "1e0908ef7bac"), 177 addrs: []godashutil.Address{ 178 newAddressPubKey(decodeHex("07b0bd634234abbb1" + 179 "ba1e986e884185c61cf43e001f9137f23c2c" + 180 "409273eb16e6537a576782eba668a7ef8bd3" + 181 "b3cfb1edb7117ab65129b8a2e681f3c1e090" + 182 "8ef7b")), 183 }, 184 reqSigs: 1, 185 class: txscript.PubKeyTy, 186 }, 187 { 188 name: "standard p2pkh", 189 script: decodeHex("76a914ad06dd6ddee55cbca9a9e3713bd7" + 190 "587509a3056488ac"), 191 addrs: []godashutil.Address{ 192 newAddressPubKeyHash(decodeHex("ad06dd6ddee55" + 193 "cbca9a9e3713bd7587509a30564")), 194 }, 195 reqSigs: 1, 196 class: txscript.PubKeyHashTy, 197 }, 198 { 199 name: "standard p2sh", 200 script: decodeHex("a91463bcc565f9e68ee0189dd5cc67f1b0" + 201 "e5f02f45cb87"), 202 addrs: []godashutil.Address{ 203 newAddressScriptHash(decodeHex("63bcc565f9e68" + 204 "ee0189dd5cc67f1b0e5f02f45cb")), 205 }, 206 reqSigs: 1, 207 class: txscript.ScriptHashTy, 208 }, 209 // from real tx 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1, vout 0 210 { 211 name: "standard 1 of 2 multisig", 212 script: decodeHex("514104cc71eb30d653c0c3163990c47b97" + 213 "6f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473" + 214 "e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11" + 215 "fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381" + 216 "354d80e550078cb532a34bfa2fcfdeb7d76519aecc62" + 217 "770f5b0e4ef8551946d8a540911abe3e7854a26f39f5" + 218 "8b25c15342af52ae"), 219 addrs: []godashutil.Address{ 220 newAddressPubKey(decodeHex("04cc71eb30d653c0c" + 221 "3163990c47b976f3fb3f37cccdcbedb169a1" + 222 "dfef58bbfbfaff7d8a473e7e2e6d317b87ba" + 223 "fe8bde97e3cf8f065dec022b51d11fcdd0d3" + 224 "48ac4")), 225 newAddressPubKey(decodeHex("0461cbdcc5409fb4b" + 226 "4d42b51d33381354d80e550078cb532a34bf" + 227 "a2fcfdeb7d76519aecc62770f5b0e4ef8551" + 228 "946d8a540911abe3e7854a26f39f58b25c15" + 229 "342af")), 230 }, 231 reqSigs: 1, 232 class: txscript.MultiSigTy, 233 }, 234 // from real tx d646f82bd5fbdb94a36872ce460f97662b80c3050ad3209bef9d1e398ea277ab, vin 1 235 { 236 name: "standard 2 of 3 multisig", 237 script: decodeHex("524104cb9c3c222c5f7a7d3b9bd152f363" + 238 "a0b6d54c9eb312c4d4f9af1e8551b6c421a6a4ab0e29" + 239 "105f24de20ff463c1c91fcf3bf662cdde4783d4799f7" + 240 "87cb7c08869b4104ccc588420deeebea22a7e900cc8b" + 241 "68620d2212c374604e3487ca08f1ff3ae12bdc639514" + 242 "d0ec8612a2d3c519f084d9a00cbbe3b53d071e9b09e7" + 243 "1e610b036aa24104ab47ad1939edcb3db65f7fedea62" + 244 "bbf781c5410d3f22a7a3a56ffefb2238af8627363bdf" + 245 "2ed97c1f89784a1aecdb43384f11d2acc64443c7fc29" + 246 "9cef0400421a53ae"), 247 addrs: []godashutil.Address{ 248 newAddressPubKey(decodeHex("04cb9c3c222c5f7a7" + 249 "d3b9bd152f363a0b6d54c9eb312c4d4f9af1" + 250 "e8551b6c421a6a4ab0e29105f24de20ff463" + 251 "c1c91fcf3bf662cdde4783d4799f787cb7c0" + 252 "8869b")), 253 newAddressPubKey(decodeHex("04ccc588420deeebe" + 254 "a22a7e900cc8b68620d2212c374604e3487c" + 255 "a08f1ff3ae12bdc639514d0ec8612a2d3c51" + 256 "9f084d9a00cbbe3b53d071e9b09e71e610b0" + 257 "36aa2")), 258 newAddressPubKey(decodeHex("04ab47ad1939edcb3" + 259 "db65f7fedea62bbf781c5410d3f22a7a3a56" + 260 "ffefb2238af8627363bdf2ed97c1f89784a1" + 261 "aecdb43384f11d2acc64443c7fc299cef040" + 262 "0421a")), 263 }, 264 reqSigs: 2, 265 class: txscript.MultiSigTy, 266 }, 267 268 // The below are nonstandard script due to things such as 269 // invalid pubkeys, failure to parse, and not being of a 270 // standard form. 271 272 { 273 name: "p2pk with uncompressed pk missing OP_CHECKSIG", 274 script: decodeHex("410411db93e1dcdb8a016b49840f8c53bc" + 275 "1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb" + 276 "84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643" + 277 "f656b412a3"), 278 addrs: nil, 279 reqSigs: 0, 280 class: txscript.NonStandardTy, 281 }, 282 { 283 name: "valid signature from a sigscript - no addresses", 284 script: decodeHex("47304402204e45e16932b8af514961a1d3" + 285 "a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220" + 286 "181522ec8eca07de4860a4acdd12909d831cc56cbbac" + 287 "4622082221a8768d1d0901"), 288 addrs: nil, 289 reqSigs: 0, 290 class: txscript.NonStandardTy, 291 }, 292 // Note the technically the pubkey is the second item on the 293 // stack, but since the address extraction intentionally only 294 // works with standard PkScripts, this should not return any 295 // addresses. 296 { 297 name: "valid sigscript to reedeem p2pk - no addresses", 298 script: decodeHex("493046022100ddc69738bf2336318e4e04" + 299 "1a5a77f305da87428ab1606f023260017854350ddc02" + 300 "2100817af09d2eec36862d16009852b7e3a0f6dd7659" + 301 "8290b7834e1453660367e07a014104cd4240c198e125" + 302 "23b6f9cb9f5bed06de1ba37e96a1bbd13745fcf9d11c" + 303 "25b1dff9a519675d198804ba9962d3eca2d5937d58e5" + 304 "a75a71042d40388a4d307f887d"), 305 addrs: nil, 306 reqSigs: 0, 307 class: txscript.NonStandardTy, 308 }, 309 // from real tx 691dd277dc0e90a462a3d652a1171686de49cf19067cd33c7df0392833fb986a, vout 0 310 // invalid public keys 311 { 312 name: "1 of 3 multisig with invalid pubkeys", 313 script: decodeHex("51411c2200007353455857696b696c6561" + 314 "6b73204361626c6567617465204261636b75700a0a63" + 315 "61626c65676174652d3230313031323034313831312e" + 316 "377a0a0a446f41776e6c6f61642074686520666f6c6c" + 317 "6f77696e67207472616e73616374696f6e7320776974" + 318 "68205361746f736869204e616b616d6f746f27732064" + 319 "6f776e6c6f61416420746f6f6c2077686963680a6361" + 320 "6e20626520666f756e6420696e207472616e73616374" + 321 "696f6e20366335336364393837313139656637393764" + 322 "35616463636453ae"), 323 addrs: []godashutil.Address{}, 324 reqSigs: 1, 325 class: txscript.MultiSigTy, 326 }, 327 // from real tx: 691dd277dc0e90a462a3d652a1171686de49cf19067cd33c7df0392833fb986a, vout 44 328 // invalid public keys 329 { 330 name: "1 of 3 multisig with invalid pubkeys 2", 331 script: decodeHex("5141346333656332353963373464616365" + 332 "36666430383862343463656638630a63363662633139" + 333 "39366338623934613338313162333635363138666531" + 334 "65396231623541366361636365393933613339383861" + 335 "34363966636336643664616266640a32363633636661" + 336 "39636634633033633630396335393363336539316665" + 337 "64653730323921313233646434326432353633396433" + 338 "38613663663530616234636434340a00000053ae"), 339 addrs: []godashutil.Address{}, 340 reqSigs: 1, 341 class: txscript.MultiSigTy, 342 }, 343 { 344 name: "empty script", 345 script: []byte{}, 346 addrs: nil, 347 reqSigs: 0, 348 class: txscript.NonStandardTy, 349 }, 350 { 351 name: "script that does not parse", 352 script: []byte{txscript.OP_DATA_45}, 353 addrs: nil, 354 reqSigs: 0, 355 class: txscript.NonStandardTy, 356 }, 357 } 358 359 t.Logf("Running %d tests.", len(tests)) 360 for i, test := range tests { 361 class, addrs, reqSigs, err := txscript.ExtractPkScriptAddrs( 362 test.script, &chaincfg.MainNetParams) 363 if err != nil { 364 } 365 366 if !reflect.DeepEqual(addrs, test.addrs) { 367 t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+ 368 "addresses\ngot %v\nwant %v", i, test.name, 369 addrs, test.addrs) 370 continue 371 } 372 373 if reqSigs != test.reqSigs { 374 t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+ 375 "number of required signatures - got %d, "+ 376 "want %d", i, test.name, reqSigs, test.reqSigs) 377 continue 378 } 379 380 if class != test.class { 381 t.Errorf("ExtractPkScriptAddrs #%d (%s) unexpected "+ 382 "script type - got %s, want %s", i, test.name, 383 class, test.class) 384 continue 385 } 386 } 387 } 388 389 // TestCalcScriptInfo ensures the CalcScriptInfo provides the expected results 390 // for various valid and invalid script pairs. 391 func TestCalcScriptInfo(t *testing.T) { 392 t.Parallel() 393 394 tests := []struct { 395 name string 396 sigScript string 397 pkScript string 398 bip16 bool 399 scriptInfo txscript.ScriptInfo 400 scriptInfoErr error 401 }{ 402 { 403 // Invented scripts, the hashes do not match 404 // Truncated version of test below: 405 name: "pkscript doesn't parse", 406 sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + 407 "SWAP ABS EQUAL", 408 pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + 409 "3152205ec4f59c", 410 bip16: true, 411 scriptInfoErr: txscript.ErrStackShortScript, 412 }, 413 { 414 name: "sigScript doesn't parse", 415 // Truncated version of p2sh script below. 416 sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + 417 "SWAP ABS", 418 pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + 419 "3152205ec4f59c74 EQUAL", 420 bip16: true, 421 scriptInfoErr: txscript.ErrStackShortScript, 422 }, 423 { 424 // Invented scripts, the hashes do not match 425 name: "p2sh standard script", 426 sigScript: "1 81 DATA_25 DUP HASH160 DATA_20 0x010203" + 427 "0405060708090a0b0c0d0e0f1011121314 EQUALVERIFY " + 428 "CHECKSIG", 429 pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + 430 "3152205ec4f59c74 EQUAL", 431 bip16: true, 432 scriptInfo: txscript.ScriptInfo{ 433 PkScriptClass: txscript.ScriptHashTy, 434 NumInputs: 3, 435 ExpectedInputs: 3, // nonstandard p2sh. 436 SigOps: 1, 437 }, 438 }, 439 { 440 // from 567a53d1ce19ce3d07711885168484439965501536d0d0294c5d46d46c10e53b 441 // from the blockchain. 442 name: "p2sh nonstandard script", 443 sigScript: "1 81 DATA_8 2DUP EQUAL NOT VERIFY ABS " + 444 "SWAP ABS EQUAL", 445 pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + 446 "3152205ec4f59c74 EQUAL", 447 bip16: true, 448 scriptInfo: txscript.ScriptInfo{ 449 PkScriptClass: txscript.ScriptHashTy, 450 NumInputs: 3, 451 ExpectedInputs: -1, // nonstandard p2sh. 452 SigOps: 0, 453 }, 454 }, 455 { 456 // Script is invented, numbers all fake. 457 name: "multisig script", 458 // Extra 0 arg on the end for OP_CHECKMULTISIG bug. 459 sigScript: "1 1 1 0", 460 pkScript: "3 " + 461 "DATA_33 0x0102030405060708090a0b0c0d0e0f1011" + 462 "12131415161718191a1b1c1d1e1f2021 DATA_33 " + 463 "0x0102030405060708090a0b0c0d0e0f101112131415" + 464 "161718191a1b1c1d1e1f2021 DATA_33 0x010203040" + 465 "5060708090a0b0c0d0e0f101112131415161718191a1" + 466 "b1c1d1e1f2021 3 CHECKMULTISIG", 467 bip16: true, 468 scriptInfo: txscript.ScriptInfo{ 469 PkScriptClass: txscript.MultiSigTy, 470 NumInputs: 4, 471 ExpectedInputs: 4, 472 SigOps: 3, 473 }, 474 }, 475 } 476 477 for _, test := range tests { 478 sigScript := mustParseShortForm(test.sigScript) 479 pkScript := mustParseShortForm(test.pkScript) 480 si, err := txscript.CalcScriptInfo(sigScript, pkScript, 481 test.bip16) 482 if err != nil { 483 if err != test.scriptInfoErr { 484 t.Errorf("scriptinfo test \"%s\": got \"%v\""+ 485 "expected \"%v\"", test.name, err, 486 test.scriptInfoErr) 487 } 488 continue 489 } 490 if test.scriptInfoErr != nil { 491 t.Errorf("%s: succeeded when expecting \"%v\"", 492 test.name, test.scriptInfoErr) 493 continue 494 } 495 if *si != test.scriptInfo { 496 t.Errorf("%s: scriptinfo doesn't match expected. "+ 497 "got: \"%v\" expected \"%v\"", test.name, 498 *si, test.scriptInfo) 499 continue 500 } 501 } 502 } 503 504 // bogusAddress implements the godashutil.Address interface so the tests can ensure 505 // unsupported address types are handled properly. 506 type bogusAddress struct{} 507 508 // EncodeAddress simply returns an empty string. It exists to satsify the 509 // godashutil.Address interface. 510 func (b *bogusAddress) EncodeAddress() string { 511 return "" 512 } 513 514 // ScriptAddress simply returns an empty byte slice. It exists to satsify the 515 // godashutil.Address interface. 516 func (b *bogusAddress) ScriptAddress() []byte { 517 return nil 518 } 519 520 // IsForNet lies blatantly to satisfy the godashutil.Address interface. 521 func (b *bogusAddress) IsForNet(chainParams *chaincfg.Params) bool { 522 return true // why not? 523 } 524 525 // String simply returns an empty string. It exists to satsify the 526 // godashutil.Address interface. 527 func (b *bogusAddress) String() string { 528 return "" 529 } 530 531 // TestPayToAddrScript ensures the PayToAddrScript function generates the 532 // correct scripts for the various types of addresses. 533 func TestPayToAddrScript(t *testing.T) { 534 t.Parallel() 535 536 // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX 537 p2pkhMain, err := godashutil.NewAddressPubKeyHash(decodeHex("e34cce70c863"+ 538 "73273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams) 539 if err != nil { 540 t.Errorf("Unable to create public key hash address: %v", err) 541 return 542 } 543 544 // Taken from transaction: 545 // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d 546 p2shMain, _ := godashutil.NewAddressScriptHashFromHash(decodeHex("e8c300"+ 547 "c87986efa84c37c0519929019ef86eb5b4"), &chaincfg.MainNetParams) 548 if err != nil { 549 t.Errorf("Unable to create script hash address: %v", err) 550 return 551 } 552 553 // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg 554 p2pkCompressedMain, err := godashutil.NewAddressPubKey(decodeHex("02192d74"+ 555 "d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), 556 &chaincfg.MainNetParams) 557 if err != nil { 558 t.Errorf("Unable to create pubkey address (compressed): %v", 559 err) 560 return 561 } 562 p2pkCompressed2Main, err := godashutil.NewAddressPubKey(decodeHex("03b0bd"+ 563 "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), 564 &chaincfg.MainNetParams) 565 if err != nil { 566 t.Errorf("Unable to create pubkey address (compressed 2): %v", 567 err) 568 return 569 } 570 571 p2pkUncompressedMain, err := godashutil.NewAddressPubKey(decodeHex("0411db"+ 572 "93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2"+ 573 "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3"), 574 &chaincfg.MainNetParams) 575 if err != nil { 576 t.Errorf("Unable to create pubkey address (uncompressed): %v", 577 err) 578 return 579 } 580 581 tests := []struct { 582 in godashutil.Address 583 expected string 584 err error 585 }{ 586 // pay-to-pubkey-hash address on mainnet 587 { 588 p2pkhMain, 589 "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + 590 "91bb4a0e8488 CHECKSIG", 591 nil, 592 }, 593 // pay-to-script-hash address on mainnet 594 { 595 p2shMain, 596 "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + 597 "6eb5b4 EQUAL", 598 nil, 599 }, 600 // pay-to-pubkey address on mainnet. compressed key. 601 { 602 p2pkCompressedMain, 603 "DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c3" + 604 "ebec3a957724895dca52c6b4 CHECKSIG", 605 nil, 606 }, 607 // pay-to-pubkey address on mainnet. compressed key (other way). 608 { 609 p2pkCompressed2Main, 610 "DATA_33 0x03b0bd634234abbb1ba1e986e884185c61cf43e001" + 611 "f9137f23c2c409273eb16e65 CHECKSIG", 612 nil, 613 }, 614 // pay-to-pubkey address on mainnet. uncompressed key. 615 { 616 p2pkUncompressedMain, 617 "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" + 618 "97b1482ecad7b148a6909a5cb2e0eaddfb84ccf97444" + 619 "64f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 " + 620 "CHECKSIG", 621 nil, 622 }, 623 624 // Supported address types with nil pointers. 625 {(*godashutil.AddressPubKeyHash)(nil), "", txscript.ErrUnsupportedAddress}, 626 {(*godashutil.AddressScriptHash)(nil), "", txscript.ErrUnsupportedAddress}, 627 {(*godashutil.AddressPubKey)(nil), "", txscript.ErrUnsupportedAddress}, 628 629 // Unsupported address type. 630 {&bogusAddress{}, "", txscript.ErrUnsupportedAddress}, 631 } 632 633 t.Logf("Running %d tests", len(tests)) 634 for i, test := range tests { 635 pkScript, err := txscript.PayToAddrScript(test.in) 636 if err != test.err { 637 t.Errorf("PayToAddrScript #%d unexpected error - "+ 638 "got %v, want %v", i, err, test.err) 639 continue 640 } 641 642 expected := mustParseShortForm(test.expected) 643 if !bytes.Equal(pkScript, expected) { 644 t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", 645 i, pkScript, expected) 646 continue 647 } 648 } 649 } 650 651 // TestMultiSigScript ensures the MultiSigScript function returns the expected 652 // scripts and errors. 653 func TestMultiSigScript(t *testing.T) { 654 t.Parallel() 655 656 // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg 657 p2pkCompressedMain, err := godashutil.NewAddressPubKey(decodeHex("02192d7"+ 658 "4d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), 659 &chaincfg.MainNetParams) 660 if err != nil { 661 t.Errorf("Unable to create pubkey address (compressed): %v", 662 err) 663 return 664 } 665 p2pkCompressed2Main, err := godashutil.NewAddressPubKey(decodeHex("03b0bd"+ 666 "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), 667 &chaincfg.MainNetParams) 668 if err != nil { 669 t.Errorf("Unable to create pubkey address (compressed 2): %v", 670 err) 671 return 672 } 673 674 p2pkUncompressedMain, err := godashutil.NewAddressPubKey(decodeHex("0411d"+ 675 "b93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"+ 676 "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b41"+ 677 "2a3"), &chaincfg.MainNetParams) 678 if err != nil { 679 t.Errorf("Unable to create pubkey address (uncompressed): %v", 680 err) 681 return 682 } 683 684 tests := []struct { 685 keys []*godashutil.AddressPubKey 686 nrequired int 687 expected string 688 err error 689 }{ 690 { 691 []*godashutil.AddressPubKey{ 692 p2pkCompressedMain, 693 p2pkCompressed2Main, 694 }, 695 1, 696 "1 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + 697 "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + 698 "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + 699 "09273eb16e65 2 CHECKMULTISIG", 700 nil, 701 }, 702 { 703 []*godashutil.AddressPubKey{ 704 p2pkCompressedMain, 705 p2pkCompressed2Main, 706 }, 707 2, 708 "2 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + 709 "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + 710 "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + 711 "09273eb16e65 2 CHECKMULTISIG", 712 nil, 713 }, 714 { 715 []*godashutil.AddressPubKey{ 716 p2pkCompressedMain, 717 p2pkCompressed2Main, 718 }, 719 3, 720 "", 721 txscript.ErrBadNumRequired, 722 }, 723 { 724 []*godashutil.AddressPubKey{ 725 p2pkUncompressedMain, 726 }, 727 1, 728 "1 DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382" + 729 "e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf97444" + 730 "64f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 " + 731 "1 CHECKMULTISIG", 732 nil, 733 }, 734 { 735 []*godashutil.AddressPubKey{ 736 p2pkUncompressedMain, 737 }, 738 2, 739 "", 740 txscript.ErrBadNumRequired, 741 }, 742 } 743 744 t.Logf("Running %d tests", len(tests)) 745 for i, test := range tests { 746 script, err := txscript.MultiSigScript(test.keys, 747 test.nrequired) 748 if err != test.err { 749 t.Errorf("MultiSigScript #%d unexpected error - "+ 750 "got %v, want %v", i, err, test.err) 751 continue 752 } 753 754 expected := mustParseShortForm(test.expected) 755 if !bytes.Equal(script, expected) { 756 t.Errorf("MultiSigScript #%d got: %x\nwant: %x", 757 i, script, expected) 758 continue 759 } 760 } 761 } 762 763 // TestCalcMultiSigStats ensures the CalcMutliSigStats function returns the 764 // expected errors. 765 func TestCalcMultiSigStats(t *testing.T) { 766 t.Parallel() 767 768 tests := []struct { 769 name string 770 script string 771 err error 772 }{ 773 { 774 name: "short script", 775 script: "0x046708afdb0fe5548271967f1a67130b7105cd6a828" + 776 "e03909a67962e0ea1f61d", 777 err: txscript.ErrStackShortScript, 778 }, 779 { 780 name: "stack underflow", 781 script: "RETURN DATA_41 0x046708afdb0fe5548271967f1a" + 782 "67130b7105cd6a828e03909a67962e0ea1f61deb649f6" + 783 "bc3f4cef308", 784 err: txscript.ErrStackUnderflow, 785 }, 786 { 787 name: "multisig script", 788 script: "0 DATA_72 0x30450220106a3e4ef0b51b764a2887226" + 789 "2ffef55846514dacbdcbbdd652c849d395b4384022100" + 790 "e03ae554c3cbb40600d31dd46fc33f25e47bf8525b1fe" + 791 "07282e3b6ecb5f3bb2801 CODESEPARATOR 1 DATA_33 " + 792 "0x0232abdc893e7f0631364d7fd01cb33d24da45329a0" + 793 "0357b3a7886211ab414d55a 1 CHECKMULTISIG", 794 err: nil, 795 }, 796 } 797 798 for i, test := range tests { 799 script := mustParseShortForm(test.script) 800 if _, _, err := txscript.CalcMultiSigStats(script); err != test.err { 801 t.Errorf("CalcMultiSigStats #%d (%s) unexpected "+ 802 "error\ngot: %v\nwant: %v", i, test.name, err, 803 test.err) 804 } 805 } 806 } 807 808 // scriptClassTest houses a test used to ensure various scripts have the 809 // expected class. 810 type scriptClassTest struct { 811 name string 812 script string 813 class txscript.ScriptClass 814 } 815 816 // scriptClassTests houses several test scripts used to ensure various class 817 // determination is working as expected. It's defined as a test global versus 818 // inside a function scope since this spans both the standard tests and the 819 // consensus tests (pay-to-script-hash is part of consensus). 820 var scriptClassTests = []scriptClassTest{ 821 { 822 name: "Pay Pubkey", 823 script: "DATA_65 0x0411db93e1dcdb8a016b49840f8c53bc1eb68a382e" + 824 "97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e16" + 825 "0bfa9b8b64f9d4c03f999b8643f656b412a3 CHECKSIG", 826 class: txscript.PubKeyTy, 827 }, 828 // tx 599e47a8114fe098103663029548811d2651991b62397e057f0c863c2bc9f9ea 829 { 830 name: "Pay PubkeyHash", 831 script: "DUP HASH160 DATA_20 0x660d4ef3a743e3e696ad990364e555" + 832 "c271ad504b EQUALVERIFY CHECKSIG", 833 class: txscript.PubKeyHashTy, 834 }, 835 // part of tx 6d36bc17e947ce00bb6f12f8e7a56a1585c5a36188ffa2b05e10b4743273a74b 836 // codeseparator parts have been elided. (bitcoin core's checks for 837 // multisig type doesn't have codesep either). 838 { 839 name: "multisig", 840 script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4" + 841 "5329a00357b3a7886211ab414d55a 1 CHECKMULTISIG", 842 class: txscript.MultiSigTy, 843 }, 844 // tx e5779b9e78f9650debc2893fd9636d827b26b4ddfa6a8172fe8708c924f5c39d 845 { 846 name: "P2SH", 847 script: "HASH160 DATA_20 0x433ec2ac1ffa1b7b7d027f564529c57197f" + 848 "9ae88 EQUAL", 849 class: txscript.ScriptHashTy, 850 }, 851 { 852 // Nulldata with no data at all. 853 name: "nulldata", 854 script: "RETURN", 855 class: txscript.NullDataTy, 856 }, 857 { 858 // Nulldata with small data. 859 name: "nulldata2", 860 script: "RETURN DATA_8 0x046708afdb0fe554", 861 class: txscript.NullDataTy, 862 }, 863 { 864 // Nulldata with max allowed data. 865 name: "nulldata3", 866 script: "RETURN PUSHDATA1 0x50 0x046708afdb0fe5548271967f1a67" + 867 "130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" + 868 "046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" + 869 "962e0ea1f61deb649f6bc3f4cef3", 870 class: txscript.NullDataTy, 871 }, 872 { 873 // Nulldata with more than max allowed data (so therefore 874 // nonstandard) 875 name: "nulldata4", 876 script: "RETURN PUSHDATA1 0x51 0x046708afdb0fe5548271967f1a67" + 877 "130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3" + 878 "046708afdb0fe5548271967f1a67130b7105cd6a828e03909a67" + 879 "962e0ea1f61deb649f6bc3f4cef308", 880 class: txscript.NonStandardTy, 881 }, 882 { 883 // Almost nulldata, but add an additional opcode after the data 884 // to make it nonstandard. 885 name: "nulldata5", 886 script: "RETURN 4 TRUE", 887 class: txscript.NonStandardTy, 888 }, 889 890 // The next few are almost multisig (it is the more complex script type) 891 // but with various changes to make it fail. 892 { 893 // Multisig but invalid nsigs. 894 name: "strange 1", 895 script: "DUP DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da45" + 896 "329a00357b3a7886211ab414d55a 1 CHECKMULTISIG", 897 class: txscript.NonStandardTy, 898 }, 899 { 900 // Multisig but invalid pubkey. 901 name: "strange 2", 902 script: "1 1 1 CHECKMULTISIG", 903 class: txscript.NonStandardTy, 904 }, 905 { 906 // Multisig but no matching npubkeys opcode. 907 name: "strange 3", 908 script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4532" + 909 "9a00357b3a7886211ab414d55a DATA_33 0x0232abdc893e7f0" + 910 "631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a " + 911 "CHECKMULTISIG", 912 class: txscript.NonStandardTy, 913 }, 914 { 915 // Multisig but with multisigverify. 916 name: "strange 4", 917 script: "1 DATA_33 0x0232abdc893e7f0631364d7fd01cb33d24da4532" + 918 "9a00357b3a7886211ab414d55a 1 CHECKMULTISIGVERIFY", 919 class: txscript.NonStandardTy, 920 }, 921 { 922 // Multisig but wrong length. 923 name: "strange 5", 924 script: "1 CHECKMULTISIG", 925 class: txscript.NonStandardTy, 926 }, 927 { 928 name: "doesn't parse", 929 script: "DATA_5 0x01020304", 930 class: txscript.NonStandardTy, 931 }, 932 { 933 name: "multisig script with wrong number of pubkeys", 934 script: "2 " + 935 "DATA_33 " + 936 "0x027adf5df7c965a2d46203c781bd4dd8" + 937 "21f11844136f6673af7cc5a4a05cd29380 " + 938 "DATA_33 " + 939 "0x02c08f3de8ee2de9be7bd770f4c10eb0" + 940 "d6ff1dd81ee96eedd3a9d4aeaf86695e80 " + 941 "3 CHECKMULTISIG", 942 class: txscript.NonStandardTy, 943 }, 944 } 945 946 // TestScriptClass ensures all the scripts in scriptClassTests have the expected 947 // class. 948 func TestScriptClass(t *testing.T) { 949 t.Parallel() 950 951 for _, test := range scriptClassTests { 952 script := mustParseShortForm(test.script) 953 class := txscript.GetScriptClass(script) 954 if class != test.class { 955 t.Errorf("%s: expected %s got %s", test.name, 956 test.class, class) 957 return 958 } 959 } 960 } 961 962 // TestStringifyClass ensures the script class string returns the expected 963 // string for each script class. 964 func TestStringifyClass(t *testing.T) { 965 t.Parallel() 966 967 tests := []struct { 968 name string 969 class txscript.ScriptClass 970 stringed string 971 }{ 972 { 973 name: "nonstandardty", 974 class: txscript.NonStandardTy, 975 stringed: "nonstandard", 976 }, 977 { 978 name: "pubkey", 979 class: txscript.PubKeyTy, 980 stringed: "pubkey", 981 }, 982 { 983 name: "pubkeyhash", 984 class: txscript.PubKeyHashTy, 985 stringed: "pubkeyhash", 986 }, 987 { 988 name: "scripthash", 989 class: txscript.ScriptHashTy, 990 stringed: "scripthash", 991 }, 992 { 993 name: "multisigty", 994 class: txscript.MultiSigTy, 995 stringed: "multisig", 996 }, 997 { 998 name: "nulldataty", 999 class: txscript.NullDataTy, 1000 stringed: "nulldata", 1001 }, 1002 { 1003 name: "broken", 1004 class: txscript.ScriptClass(255), 1005 stringed: "Invalid", 1006 }, 1007 } 1008 1009 for _, test := range tests { 1010 typeString := test.class.String() 1011 if typeString != test.stringed { 1012 t.Errorf("%s: got %#q, want %#q", test.name, 1013 typeString, test.stringed) 1014 } 1015 } 1016 }