// newAddressPubKey returns a new dcrutil.AddressPubKey from the provided // serialized public key. It panics if an error occurs. This is only used in // the tests as a helper since the only way it can fail is if there is an error // in the test source code. func newAddressPubKey(serializedPubKey []byte) dcrutil.Address { addr, err := dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) if err != nil { panic("invalid public key in test source") } return addr }
// MakeSecp256k1MultiSigScript creates a multi-signature script that can be // redeemed with nRequired signatures of the passed keys and addresses. If the // address is a P2PKH address, the associated pubkey is looked up by the wallet // if possible, otherwise an error is returned for a missing pubkey. // // This function only works with secp256k1 pubkeys and P2PKH addresses derived // from them. func (w *Wallet) MakeSecp256k1MultiSigScript(secp256k1Addrs []dcrutil.Address, nRequired int) ([]byte, error) { secp256k1PubKeys := make([]*dcrutil.AddressSecpPubKey, len(secp256k1Addrs)) var dbtx walletdb.ReadTx var addrmgrNs walletdb.ReadBucket defer func() { if dbtx != nil { dbtx.Rollback() } }() // The address list will made up either of addreseses (pubkey hash), for // which we need to look up the keys in wallet, straight pubkeys, or a // mixture of the two. for i, addr := range secp256k1Addrs { switch addr := addr.(type) { default: return nil, errors.New("cannot make multisig script for " + "a non-secp256k1 public key or P2PKH address") case *dcrutil.AddressSecpPubKey: secp256k1PubKeys[i] = addr case *dcrutil.AddressPubKeyHash: if addr.DSA(w.chainParams) != chainec.ECTypeSecp256k1 { return nil, errors.New("cannot make multisig " + "script for a non-secp256k1 P2PKH address") } if dbtx == nil { var err error dbtx, err = w.db.BeginReadTx() if err != nil { return nil, err } addrmgrNs = dbtx.ReadBucket(waddrmgrNamespaceKey) } addrInfo, err := w.Manager.Address(addrmgrNs, addr) if err != nil { return nil, err } serializedPubKey := addrInfo.(waddrmgr.ManagedPubKeyAddress). PubKey().Serialize() pubKeyAddr, err := dcrutil.NewAddressSecpPubKey( serializedPubKey, w.chainParams) if err != nil { return nil, err } secp256k1PubKeys[i] = pubKeyAddr } } return txscript.MultiSigScript(secp256k1PubKeys, nRequired) }
// DepositScript constructs and returns a multi-signature redemption script where // a certain number (Series.reqSigs) of the public keys belonging to the series // with the given ID are required to sign the transaction for it to be successful. func (p *Pool) DepositScript(seriesID uint32, branch Branch, index Index) ([]byte, error) { series := p.Series(seriesID) if series == nil { str := fmt.Sprintf("series #%d does not exist", seriesID) return nil, newError(ErrSeriesNotExists, str, nil) } pubKeys, err := branchOrder(series.publicKeys, branch) if err != nil { return nil, err } pks := make([]*dcrutil.AddressSecpPubKey, len(pubKeys)) for i, key := range pubKeys { child, err := key.Child(uint32(index)) // TODO: implement getting the next index until we find a valid one, // in case there is a hdkeychain.ErrInvalidChild. if err != nil { str := fmt.Sprintf("child #%d for this pubkey %d does not exist", index, i) return nil, newError(ErrKeyChain, str, err) } pubkey, err := child.ECPubKey() if err != nil { str := fmt.Sprintf("child #%d for this pubkey %d does not exist", index, i) return nil, newError(ErrKeyChain, str, err) } pks[i], err = dcrutil.NewAddressSecpPubKey(pubkey.SerializeCompressed(), p.manager.ChainParams()) if err != nil { str := fmt.Sprintf( "child #%d for this pubkey %d could not be converted to an address", index, i) return nil, newError(ErrKeyChain, str, err) } } script, err := txscript.MultiSigScript(pks, int(series.reqSigs)) if err != nil { str := fmt.Sprintf("error while making multisig script hash, %d", len(pks)) return nil, newError(ErrScriptCreation, str, err) } return script, nil }
func (s *walletServer) NextAddress(ctx context.Context, req *pb.NextAddressRequest) ( *pb.NextAddressResponse, error) { var ( addr dcrutil.Address err error ) switch req.Kind { case pb.NextAddressRequest_BIP0044_EXTERNAL: addr, err = s.wallet.NewAddress(req.Account, waddrmgr.ExternalBranch) if err != nil { return nil, translateError(err) } case pb.NextAddressRequest_BIP0044_INTERNAL: addr, err = s.wallet.NewAddress(req.Account, waddrmgr.InternalBranch) if err != nil { return nil, translateError(err) } default: return nil, grpc.Errorf(codes.InvalidArgument, "kind=%v", req.Kind) } if err != nil { return nil, translateError(err) } pubKey, err := s.wallet.PubKeyForAddress(addr) if err != nil { return nil, translateError(err) } pubKeyAddr, err := dcrutil.NewAddressSecpPubKey(pubKey.Serialize(), s.wallet.ChainParams()) if err != nil { return nil, translateError(err) } return &pb.NextAddressResponse{ Address: addr.EncodeAddress(), PublicKey: pubKeyAddr.String(), }, nil }
// TestMultiSigScript ensures the MultiSigScript function returns the expected // scripts and errors. func TestMultiSigScript(t *testing.T) { t.Parallel() // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg p2pkCompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("02192d7"+ "4d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed): %v", err) return } p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(decodeHex("03b0bd"+ "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed 2): %v", err) return } p2pkUncompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("0411d"+ "b93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"+ "b2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b41"+ "2a3"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (uncompressed): %v", err) return } tests := []struct { keys []*dcrutil.AddressSecpPubKey nrequired int expected string err error }{ { []*dcrutil.AddressSecpPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 1, "1 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + "09273eb16e65 2 CHECKMULTISIG", nil, }, { []*dcrutil.AddressSecpPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 2, "2 DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c" + "3ebec3a957724895dca52c6b4 DATA_33 0x03b0bd634" + "234abbb1ba1e986e884185c61cf43e001f9137f23c2c4" + "09273eb16e65 2 CHECKMULTISIG", nil, }, { []*dcrutil.AddressSecpPubKey{ p2pkCompressedMain, p2pkCompressed2Main, }, 3, "", txscript.ErrBadNumRequired, }, { // By default compressed pubkeys are used in Decred. []*dcrutil.AddressSecpPubKey{ p2pkUncompressedMain, }, 1, "1 DATA_33 0x0311db93e1dcdb8a016b49840f8c53bc1eb68a3" + "82e97b1482ecad7b148a6909a5c 1 CHECKMULTISIG", nil, }, { []*dcrutil.AddressSecpPubKey{ p2pkUncompressedMain, }, 2, "", txscript.ErrBadNumRequired, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { script, err := txscript.MultiSigScript(test.keys, test.nrequired) if err != test.err { t.Errorf("MultiSigScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue } expected := mustParseShortForm(test.expected) if !bytes.Equal(script, expected) { t.Errorf("MultiSigScript #%d got: %x\nwant: %x", i, script, expected) continue } } }
// TestPayToAddrScript ensures the PayToAddrScript function generates the // correct scripts for the various types of addresses. func TestPayToAddrScript(t *testing.T) { t.Parallel() // 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX p2pkhMain, err := dcrutil.NewAddressPubKeyHash(decodeHex("e34cce70c863"+ "73273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams, secp) if err != nil { t.Errorf("Unable to create public key hash address: %v", err) return } // Taken from transaction: // b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d p2shMain, _ := dcrutil.NewAddressScriptHashFromHash(decodeHex("e8c300"+ "c87986efa84c37c0519929019ef86eb5b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create script hash address: %v", err) return } // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg p2pkCompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("02192d74"+ "d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed): %v", err) return } p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(decodeHex("03b0bd"+ "634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (compressed 2): %v", err) return } p2pkUncompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("0411db"+ "93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2"+ "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3"), &chaincfg.MainNetParams) if err != nil { t.Errorf("Unable to create pubkey address (uncompressed): %v", err) return } tests := []struct { in dcrutil.Address expected string err error }{ // pay-to-pubkey-hash address on mainnet 0 { p2pkhMain, "DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" + "91bb4a0e8488 CHECKSIG", nil, }, // pay-to-script-hash address on mainnet 1 { p2shMain, "HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" + "6eb5b4 EQUAL", nil, }, // pay-to-pubkey address on mainnet. compressed key. 2 { p2pkCompressedMain, "DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c3" + "ebec3a957724895dca52c6b4 CHECKSIG", nil, }, // pay-to-pubkey address on mainnet. compressed key (other way). 3 { p2pkCompressed2Main, "DATA_33 0x03b0bd634234abbb1ba1e986e884185c61cf43e001" + "f9137f23c2c409273eb16e65 CHECKSIG", nil, }, // pay-to-pubkey address on mainnet. for decred this would // be uncompressed, but standard for decred is 33 byte // compressed public keys. { p2pkUncompressedMain, "DATA_33 0x0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b" + "1482ecad7b148a6909a5cac", nil, }, // Supported address types with nil pointers. {(*dcrutil.AddressPubKeyHash)(nil), "", txscript.ErrUnsupportedAddress}, {(*dcrutil.AddressScriptHash)(nil), "", txscript.ErrUnsupportedAddress}, {(*dcrutil.AddressSecpPubKey)(nil), "", txscript.ErrUnsupportedAddress}, // Unsupported address type. {&bogusAddress{}, "", txscript.ErrUnsupportedAddress}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { pkScript, err := txscript.PayToAddrScript(test.in) if err != test.err { t.Errorf("PayToAddrScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue } expected := mustParseShortForm(test.expected) if !bytes.Equal(pkScript, expected) { t.Errorf("PayToAddrScript #%d got: %x\nwant: %x", i, pkScript, expected) continue } } }
// ExtractPkScriptAddrs returns the type of script, addresses and required // signatures associated with the passed PkScript. Note that it only works for // 'standard' transaction script types. Any data such as public keys which are // invalid are omitted from the results. func ExtractPkScriptAddrs(version uint16, pkScript []byte, chainParams *chaincfg.Params) (ScriptClass, []dcrutil.Address, int, error) { if version != DefaultScriptVersion { return NonStandardTy, nil, 0, fmt.Errorf("invalid script version") } var addrs []dcrutil.Address var requiredSigs int // No valid addresses or required signatures if the script doesn't // parse. pops, err := parseScript(pkScript) if err != nil { return NonStandardTy, nil, 0, err } scriptClass := typeOfScript(pops) switch scriptClass { case PubKeyHashTy: // A pay-to-pubkey-hash script is of the form: // OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG // Therefore the pubkey hash is the 3rd item on the stack. // Skip the pubkey hash if it's invalid for some reason. requiredSigs = 1 addr, err := dcrutil.NewAddressPubKeyHash(pops[2].data, chainParams, chainec.ECTypeSecp256k1) if err == nil { addrs = append(addrs, addr) } case PubkeyHashAltTy: // A pay-to-pubkey-hash script is of the form: // OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY <type> OP_CHECKSIGALT // Therefore the pubkey hash is the 3rd item on the stack. // Skip the pubkey hash if it's invalid for some reason. requiredSigs = 1 suite, _ := ExtractPkScriptAltSigType(pkScript) addr, err := dcrutil.NewAddressPubKeyHash(pops[2].data, chainParams, suite) if err == nil { addrs = append(addrs, addr) } case PubKeyTy: // A pay-to-pubkey script is of the form: // <pubkey> OP_CHECKSIG // Therefore the pubkey is the first item on the stack. // Skip the pubkey if it's invalid for some reason. requiredSigs = 1 addr, err := dcrutil.NewAddressSecpPubKey(pops[0].data, chainParams) if err == nil { addrs = append(addrs, addr) } case PubkeyAltTy: // A pay-to-pubkey alt script is of the form: // <pubkey> <type> OP_CHECKSIGALT // Therefore the pubkey is the first item on the stack. // Skip the pubkey if it's invalid for some reason. requiredSigs = 1 suite, _ := ExtractPkScriptAltSigType(pkScript) var addr dcrutil.Address err := fmt.Errorf("invalid signature suite for alt sig") switch suite { case chainec.ECTypeEdwards: addr, err = dcrutil.NewAddressEdwardsPubKey(pops[0].data, chainParams) case chainec.ECTypeSecSchnorr: addr, err = dcrutil.NewAddressSecSchnorrPubKey(pops[0].data, chainParams) } if err == nil { addrs = append(addrs, addr) } case StakeSubmissionTy: // A pay-to-stake-submission-hash script is of the form: // OP_SSTX ... P2PKH or P2SH var localAddrs []dcrutil.Address _, localAddrs, requiredSigs, err = ExtractPkScriptAddrs(version, getStakeOutSubscript(pkScript), chainParams) if err == nil { addrs = append(addrs, localAddrs...) } case StakeGenTy: // A pay-to-stake-generation-hash script is of the form: // OP_SSGEN ... P2PKH or P2SH var localAddrs []dcrutil.Address _, localAddrs, requiredSigs, err = ExtractPkScriptAddrs(version, getStakeOutSubscript(pkScript), chainParams) if err == nil { addrs = append(addrs, localAddrs...) } case StakeRevocationTy: // A pay-to-stake-revocation-hash script is of the form: // OP_SSRTX ... P2PKH or P2SH var localAddrs []dcrutil.Address _, localAddrs, requiredSigs, err = ExtractPkScriptAddrs(version, getStakeOutSubscript(pkScript), chainParams) if err == nil { addrs = append(addrs, localAddrs...) } case StakeSubChangeTy: // A pay-to-stake-submission-change-hash script is of the form: // OP_SSTXCHANGE ... P2PKH or P2SH var localAddrs []dcrutil.Address _, localAddrs, requiredSigs, err = ExtractPkScriptAddrs(version, getStakeOutSubscript(pkScript), chainParams) if err == nil { addrs = append(addrs, localAddrs...) } case ScriptHashTy: // A pay-to-script-hash script is of the form: // OP_HASH160 <scripthash> OP_EQUAL // Therefore the script hash is the 2nd item on the stack. // Skip the script hash if it's invalid for some reason. requiredSigs = 1 addr, err := dcrutil.NewAddressScriptHashFromHash(pops[1].data, chainParams) if err == nil { addrs = append(addrs, addr) } case MultiSigTy: // A multi-signature script is of the form: // <numsigs> <pubkey> <pubkey> <pubkey>... <numpubkeys> OP_CHECKMULTISIG // Therefore the number of required signatures is the 1st item // on the stack and the number of public keys is the 2nd to last // item on the stack. requiredSigs = asSmallInt(pops[0].opcode) numPubKeys := asSmallInt(pops[len(pops)-2].opcode) // Extract the public keys while skipping any that are invalid. addrs = make([]dcrutil.Address, 0, numPubKeys) for i := 0; i < numPubKeys; i++ { addr, err := dcrutil.NewAddressSecpPubKey(pops[i+1].data, chainParams) if err == nil { addrs = append(addrs, addr) } } case NullDataTy: // Null data transactions have no addresses or required // signatures. case NonStandardTy: // Don't attempt to extract addresses or required signatures for // nonstandard transactions. } return scriptClass, addrs, requiredSigs, nil }
func TestAddresses(t *testing.T) { tests := []struct { name string addr string encoded string valid bool result dcrutil.Address f func() (dcrutil.Address, error) net *chaincfg.Params }{ // Positive P2PKH tests. { name: "mainnet p2pkh", addr: "DsR4PRmFaVNSu6SJ6ERM7rPZeGvKviny2e1", encoded: "DsR4PRmFaVNSu6SJ6ERM7rPZeGvKviny2e1", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc, 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84}, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0xe3, 0x4c, 0xce, 0x70, 0xc8, 0x63, 0x73, 0x27, 0x3e, 0xfc, 0xc5, 0x4c, 0xe7, 0xd2, 0xa4, 0x91, 0xbb, 0x4a, 0x0e, 0x84} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pkh 2", addr: "DcXZ4zkDvDhJUqQ8tKu2KukVXzFo2R8PCwF", encoded: "DcXZ4zkDvDhJUqQ8tKu2KukVXzFo2R8PCwF", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa}, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.MainNetParams, }, { name: "testnet p2pkh", addr: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhipBc", encoded: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhipBc", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83, 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f}, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x78, 0xb3, 0x16, 0xa0, 0x86, 0x47, 0xd5, 0xb7, 0x72, 0x83, 0xe5, 0x12, 0xd3, 0x60, 0x3f, 0x1f, 0x1c, 0x8d, 0xe6, 0x8f} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.TestNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.TestNetParams, }, // Negative P2PKH tests. { name: "p2pkh wrong hash length", addr: "", valid: false, f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, }, { name: "p2pkh bad checksum", addr: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhipBc", valid: false, }, // Positive P2SH tests. { // Taken from transactions: // output: 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac // input: 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba. name: "mainnet p2sh", addr: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", encoded: "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10}, chaincfg.MainNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { txscript := []byte{ 0x52, 0x41, 0x04, 0x91, 0xbb, 0xa2, 0x51, 0x09, 0x12, 0xa5, 0xbd, 0x37, 0xda, 0x1f, 0xb5, 0xb1, 0x67, 0x30, 0x10, 0xe4, 0x3d, 0x2c, 0x6d, 0x81, 0x2c, 0x51, 0x4e, 0x91, 0xbf, 0xa9, 0xf2, 0xeb, 0x12, 0x9e, 0x1c, 0x18, 0x33, 0x29, 0xdb, 0x55, 0xbd, 0x86, 0x8e, 0x20, 0x9a, 0xac, 0x2f, 0xbc, 0x02, 0xcb, 0x33, 0xd9, 0x8f, 0xe7, 0x4b, 0xf2, 0x3f, 0x0c, 0x23, 0x5d, 0x61, 0x26, 0xb1, 0xd8, 0x33, 0x4f, 0x86, 0x41, 0x04, 0x86, 0x5c, 0x40, 0x29, 0x3a, 0x68, 0x0c, 0xb9, 0xc0, 0x20, 0xe7, 0xb1, 0xe1, 0x06, 0xd8, 0xc1, 0x91, 0x6d, 0x3c, 0xef, 0x99, 0xaa, 0x43, 0x1a, 0x56, 0xd2, 0x53, 0xe6, 0x92, 0x56, 0xda, 0xc0, 0x9e, 0xf1, 0x22, 0xb1, 0xa9, 0x86, 0x81, 0x8a, 0x7c, 0xb6, 0x24, 0x53, 0x2f, 0x06, 0x2c, 0x1d, 0x1f, 0x87, 0x22, 0x08, 0x48, 0x61, 0xc5, 0xc3, 0x29, 0x1c, 0xcf, 0xfe, 0xf4, 0xec, 0x68, 0x74, 0x41, 0x04, 0x8d, 0x24, 0x55, 0xd2, 0x40, 0x3e, 0x08, 0x70, 0x8f, 0xc1, 0xf5, 0x56, 0x00, 0x2f, 0x1b, 0x6c, 0xd8, 0x3f, 0x99, 0x2d, 0x08, 0x50, 0x97, 0xf9, 0x97, 0x4a, 0xb0, 0x8a, 0x28, 0x83, 0x8f, 0x07, 0x89, 0x6f, 0xba, 0xb0, 0x8f, 0x39, 0x49, 0x5e, 0x15, 0xfa, 0x6f, 0xad, 0x6e, 0xdb, 0xfb, 0x1e, 0x75, 0x4e, 0x35, 0xfa, 0x1c, 0x78, 0x44, 0xc4, 0x1f, 0x32, 0x2a, 0x18, 0x63, 0xd4, 0x62, 0x13, 0x53, 0xae} return dcrutil.NewAddressScriptHash(txscript, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { // Taken from transactions: // output: b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d // input: (not yet redeemed at time test was written) name: "mainnet p2sh 2", addr: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8", encoded: "3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37, 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4}, chaincfg.MainNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { hash := []byte{ 0xe8, 0xc3, 0x00, 0xc8, 0x79, 0x86, 0xef, 0xa8, 0x4c, 0x37, 0xc0, 0x51, 0x99, 0x29, 0x01, 0x9e, 0xf8, 0x6e, 0xb5, 0xb4} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { // Taken from bitcoind base58_keys_valid. name: "testnet p2sh", addr: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", encoded: "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e, 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a}, chaincfg.TestNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { hash := []byte{ 0xc5, 0x79, 0x34, 0x2c, 0x2c, 0x4c, 0x92, 0x20, 0x20, 0x5e, 0x2c, 0xdc, 0x28, 0x56, 0x17, 0x04, 0x0c, 0x92, 0x4a, 0x0a} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, // Negative P2SH tests. { name: "p2sh wrong hash length", addr: "", valid: false, f: func() (dcrutil.Address, error) { hash := []byte{ 0x00, 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams) }, }, // Positive P2PK tests. { name: "mainnet p2pk compressed (0x02)", addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4", encoded: "13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4}, dcrutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk compressed (0x03)", addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65", encoded: "15sHANNUBSh6nDp8XkDPmQcW6n3EFwmvE6", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65}, dcrutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk uncompressed (0x04)", addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2" + "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3", encoded: "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa3}, dcrutil.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa3} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk hybrid (0x06)", addr: "06192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4" + "0d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453e", encoded: "1Ja5rs7XBZnK88EuLVcFqYGMEbBitzchmX", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4, 0x0d, 0x45, 0x26, 0x48, 0x38, 0xc0, 0xbd, 0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73, 0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c, 0x44, 0xd3, 0x3f, 0x45, 0x3e}, dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4, 0x0d, 0x45, 0x26, 0x48, 0x38, 0xc0, 0xbd, 0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73, 0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c, 0x44, 0xd3, 0x3f, 0x45, 0x3e} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk hybrid (0x07)", addr: "07b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65" + "37a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b", encoded: "1ExqMmf6yMxcBMzHjbj41wbqYuqoX6uBLG", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65, 0x37, 0xa5, 0x76, 0x78, 0x2e, 0xba, 0x66, 0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71, 0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c, 0x1e, 0x09, 0x08, 0xef, 0x7b}, dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65, 0x37, 0xa5, 0x76, 0x78, 0x2e, 0xba, 0x66, 0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71, 0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c, 0x1e, 0x09, 0x08, 0xef, 0x7b} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "testnet p2pk compressed (0x02)", addr: "02192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4", encoded: "mhiDPVP2nJunaAgTjzWSHCYfAqxxrxzjmo", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4}, dcrutil.PKFCompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x02, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk compressed (0x03)", addr: "03b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65", encoded: "mkPETRTSzU8MZLHkFKBmbKppxmdw9qT42t", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65}, dcrutil.PKFCompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x03, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk uncompressed (0x04)", addr: "0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5" + "cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3", encoded: "mh8YhPYEAYs3E7EVyKtB5xrcfMExkkdEMF", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa3}, dcrutil.PKFUncompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa3} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk hybrid (0x06)", addr: "06192d74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b" + "40d45264838c0bd96852662ce6a847b197376830160c6d2eb5e6a4c44d33f453e", encoded: "my639vCVzbDZuEiX44adfTUg6anRomZLEP", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4, 0x0d, 0x45, 0x26, 0x48, 0x38, 0xc0, 0xbd, 0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73, 0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c, 0x44, 0xd3, 0x3f, 0x45, 0x3e}, dcrutil.PKFHybrid, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x06, 0x19, 0x2d, 0x74, 0xd0, 0xcb, 0x94, 0x34, 0x4c, 0x95, 0x69, 0xc2, 0xe7, 0x79, 0x01, 0x57, 0x3d, 0x8d, 0x79, 0x03, 0xc3, 0xeb, 0xec, 0x3a, 0x95, 0x77, 0x24, 0x89, 0x5d, 0xca, 0x52, 0xc6, 0xb4, 0x0d, 0x45, 0x26, 0x48, 0x38, 0xc0, 0xbd, 0x96, 0x85, 0x26, 0x62, 0xce, 0x6a, 0x84, 0x7b, 0x19, 0x73, 0x76, 0x83, 0x01, 0x60, 0xc6, 0xd2, 0xeb, 0x5e, 0x6a, 0x4c, 0x44, 0xd3, 0x3f, 0x45, 0x3e} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk hybrid (0x07)", addr: "07b0bd634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e6" + "537a576782eba668a7ef8bd3b3cfb1edb7117ab65129b8a2e681f3c1e0908ef7b", encoded: "muUnepk5nPPrxUTuTAhRqrpAQuSWS5fVii", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65, 0x37, 0xa5, 0x76, 0x78, 0x2e, 0xba, 0x66, 0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71, 0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c, 0x1e, 0x09, 0x08, 0xef, 0x7b}, dcrutil.PKFHybrid, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x07, 0xb0, 0xbd, 0x63, 0x42, 0x34, 0xab, 0xbb, 0x1b, 0xa1, 0xe9, 0x86, 0xe8, 0x84, 0x18, 0x5c, 0x61, 0xcf, 0x43, 0xe0, 0x01, 0xf9, 0x13, 0x7f, 0x23, 0xc2, 0xc4, 0x09, 0x27, 0x3e, 0xb1, 0x6e, 0x65, 0x37, 0xa5, 0x76, 0x78, 0x2e, 0xba, 0x66, 0x8a, 0x7e, 0xf8, 0xbd, 0x3b, 0x3c, 0xfb, 0x1e, 0xdb, 0x71, 0x17, 0xab, 0x65, 0x12, 0x9b, 0x8a, 0x2e, 0x68, 0x1f, 0x3c, 0x1e, 0x09, 0x08, 0xef, 0x7b} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, } for _, test := range tests { // Decode addr and compare error against valid. decoded, err := dcrutil.DecodeAddress(test.addr, test.net) if (err == nil) != test.valid { t.Errorf("%v: decoding test failed: %v", test.name, err) return } if err == nil { // Ensure the stringer returns the same address as the // original. if decodedStringer, ok := decoded.(fmt.Stringer); ok { if test.addr != decodedStringer.String() { t.Errorf("%v: String on decoded value does not match expected value: %v != %v", test.name, test.addr, decodedStringer.String()) return } } // Encode again and compare against the original. encoded := decoded.EncodeAddress() if test.encoded != encoded { t.Errorf("%v: decoding and encoding produced different addressess: %v != %v", test.name, test.encoded, encoded) return } // Perform type-specific calculations. var saddr []byte switch d := decoded.(type) { case *dcrutil.AddressPubKeyHash: saddr = dcrutil.TstAddressSAddr(encoded) case *dcrutil.AddressScriptHash: saddr = dcrutil.TstAddressSAddr(encoded) case *dcrutil.AddressSecpPubKey: // Ignore the error here since the script // address is checked below. saddr, _ = hex.DecodeString(d.String()) case *dcrutil.AddressEdwardsPubKey: // Ignore the error here since the script // address is checked below. saddr, _ = hex.DecodeString(d.String()) case *dcrutil.AddressSecSchnorrPubKey: // Ignore the error here since the script // address is checked below. saddr, _ = hex.DecodeString(d.String()) } // Check script address, as well as the Hash160 method for P2PKH and // P2SH addresses. if !bytes.Equal(saddr, decoded.ScriptAddress()) { t.Errorf("%v: script addresses do not match:\n%x != \n%x", test.name, saddr, decoded.ScriptAddress()) return } switch a := decoded.(type) { case *dcrutil.AddressPubKeyHash: if h := a.Hash160()[:]; !bytes.Equal(saddr, h) { t.Errorf("%v: hashes do not match:\n%x != \n%x", test.name, saddr, h) return } case *dcrutil.AddressScriptHash: if h := a.Hash160()[:]; !bytes.Equal(saddr, h) { t.Errorf("%v: hashes do not match:\n%x != \n%x", test.name, saddr, h) return } } // Ensure the address is for the expected network. if !decoded.IsForNet(test.net) { t.Errorf("%v: calculated network does not match expected", test.name) return } } if !test.valid { // If address is invalid, but a creation function exists, // verify that it returns a nil addr and non-nil error. if test.f != nil { _, err := test.f() if err == nil { t.Errorf("%v: address is invalid but creating new address succeeded", test.name) return } } continue } // Valid test, compare address created with f against expected result. addr, err := test.f() if err != nil { t.Errorf("%v: address is valid but creating new address failed with error %v", test.name, err) return } if !reflect.DeepEqual(addr, test.result) { t.Errorf("%v: created address does not match expected result", test.name) return } } }
func TestAddresses(t *testing.T) { tests := []struct { name string addr string saddr string encoded string valid bool result dcrutil.Address f func() (dcrutil.Address, error) net *chaincfg.Params }{ // Positive P2PKH tests. { name: "mainnet p2pkh", addr: "DsUZxxoHJSty8DCfwfartwTYbuhmVct7tJu", encoded: "DsUZxxoHJSty8DCfwfartwTYbuhmVct7tJu", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0x27, 0x89, 0xd5, 0x8c, 0xfa, 0x09, 0x57, 0xd2, 0x06, 0xf0, 0x25, 0xc2, 0xaf, 0x05, 0x6f, 0xc8, 0xa7, 0x7c, 0xeb, 0xb0}, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x27, 0x89, 0xd5, 0x8c, 0xfa, 0x09, 0x57, 0xd2, 0x06, 0xf0, 0x25, 0xc2, 0xaf, 0x05, 0x6f, 0xc8, 0xa7, 0x7c, 0xeb, 0xb0} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pkh 2", addr: "DsU7xcg53nxaKLLcAUSKyRndjG78Z2VZnX9", encoded: "DsU7xcg53nxaKLLcAUSKyRndjG78Z2VZnX9", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0x22, 0x9e, 0xba, 0xc3, 0x0e, 0xfd, 0x6a, 0x69, 0xee, 0xc9, 0xc1, 0xa4, 0x8e, 0x04, 0x8b, 0x7c, 0x97, 0x5c, 0x25, 0xf2}, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x22, 0x9e, 0xba, 0xc3, 0x0e, 0xfd, 0x6a, 0x69, 0xee, 0xc9, 0xc1, 0xa4, 0x8e, 0x04, 0x8b, 0x7c, 0x97, 0x5c, 0x25, 0xf2} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.MainNetParams, }, { name: "testnet p2pkh", addr: "Tso2MVTUeVrjHTBFedFhiyM7yVTbieqp91h", encoded: "Tso2MVTUeVrjHTBFedFhiyM7yVTbieqp91h", valid: true, result: dcrutil.TstAddressPubKeyHash( [ripemd160.Size]byte{ 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16}, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { pkHash := []byte{ 0xf1, 0x5d, 0xa1, 0xcb, 0x8d, 0x1b, 0xcb, 0x16, 0x2c, 0x6a, 0xb4, 0x46, 0xc9, 0x57, 0x57, 0xa6, 0xe7, 0x91, 0xc9, 0x16} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.TestNetParams, chainec.ECTypeSecp256k1) }, net: &chaincfg.TestNetParams, }, // Negative P2PKH tests. { name: "p2pkh wrong hash length", addr: "", valid: false, f: func() (dcrutil.Address, error) { pkHash := []byte{ 0x00, 0x0e, 0xf0, 0x30, 0x10, 0x7f, 0xd2, 0x6e, 0x0b, 0x6b, 0xf4, 0x05, 0x12, 0xbc, 0xa2, 0xce, 0xb1, 0xdd, 0x80, 0xad, 0xaa} return dcrutil.NewAddressPubKeyHash(pkHash, &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) }, }, { name: "p2pkh bad checksum", addr: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhip23", valid: false, net: &chaincfg.TestNetParams, }, { name: "p2pkh no default net", addr: "TsmWaPM77WSyA3aiQ2Q1KnwGDVWvEkhipBc", valid: false, }, // Positive P2SH tests. { // Taken from transactions: // output: 3c9018e8d5615c306d72397f8f5eef44308c98fb576a88e030c25456b4f3a7ac // input: 837dea37ddc8b1e3ce646f1a656e79bbd8cc7f558ac56a169626d649ebe2a3ba. name: "mainnet p2sh", addr: "DcuQKx8BES9wU7C6Q5VmLBjw436r27hayjS", encoded: "DcuQKx8BES9wU7C6Q5VmLBjw436r27hayjS", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0xf0, 0xb4, 0xe8, 0x51, 0x00, 0xae, 0xe1, 0xa9, 0x96, 0xf2, 0x29, 0x15, 0xeb, 0x3c, 0x3f, 0x76, 0x4d, 0x53, 0x77, 0x9a}, chaincfg.MainNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { txscript := []byte{ 0x51, 0x21, 0x03, 0xaa, 0x43, 0xf0, 0xa6, 0xc1, 0x57, 0x30, 0xd8, 0x86, 0xcc, 0x1f, 0x03, 0x42, 0x04, 0x6d, 0x20, 0x17, 0x54, 0x83, 0xd9, 0x0d, 0x7c, 0xcb, 0x65, 0x7f, 0x90, 0xc4, 0x89, 0x11, 0x1d, 0x79, 0x4c, 0x51, 0xae} return dcrutil.NewAddressScriptHash(txscript, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { // Taken from transactions: // output: b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d // input: (not yet redeemed at time test was written) name: "mainnet p2sh 2", addr: "DcqgK4N4Ccucu2Sq4VDAdu4wH4LASLhzLVp", encoded: "DcqgK4N4Ccucu2Sq4VDAdu4wH4LASLhzLVp", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0xc7, 0xda, 0x50, 0x95, 0x68, 0x34, 0x36, 0xf4, 0x43, 0x5f, 0xc4, 0xe7, 0x16, 0x3d, 0xca, 0xfd, 0xa1, 0xa2, 0xd0, 0x07}, chaincfg.MainNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { hash := []byte{ 0xc7, 0xda, 0x50, 0x95, 0x68, 0x34, 0x36, 0xf4, 0x43, 0x5f, 0xc4, 0xe7, 0x16, 0x3d, 0xca, 0xfd, 0xa1, 0xa2, 0xd0, 0x07} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { // Taken from bitcoind base58_keys_valid. name: "testnet p2sh", addr: "TccWLgcquqvwrfBocq5mcK5kBiyw8MvyvCi", encoded: "TccWLgcquqvwrfBocq5mcK5kBiyw8MvyvCi", valid: true, result: dcrutil.TstAddressScriptHash( [ripemd160.Size]byte{ 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84}, chaincfg.TestNetParams.ScriptHashAddrID), f: func() (dcrutil.Address, error) { hash := []byte{ 0x36, 0xc1, 0xca, 0x10, 0xa8, 0xa6, 0xa4, 0xb5, 0xd4, 0x20, 0x4a, 0xc9, 0x70, 0x85, 0x39, 0x79, 0x90, 0x3a, 0xa2, 0x84} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, // Negative P2SH tests. { name: "p2sh wrong hash length", addr: "", valid: false, f: func() (dcrutil.Address, error) { hash := []byte{ 0x00, 0xf8, 0x15, 0xb0, 0x36, 0xd9, 0xbb, 0xbc, 0xe5, 0xe9, 0xf2, 0xa0, 0x0a, 0xbd, 0x1b, 0xf3, 0xdc, 0x91, 0xe9, 0x55, 0x10} return dcrutil.NewAddressScriptHashFromHash(hash, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, // Positive P2PK tests. { name: "mainnet p2pk compressed (0x02)", addr: "DsT4FDqBKYG1Xr8aGrT1rKP3kiv6TZ5K5th", encoded: "DsT4FDqBKYG1Xr8aGrT1rKP3kiv6TZ5K5th", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x02, 0x8f, 0x53, 0x83, 0x8b, 0x76, 0x39, 0x56, 0x3f, 0x27, 0xc9, 0x48, 0x45, 0x54, 0x9a, 0x41, 0xe5, 0x14, 0x6b, 0xcd, 0x52, 0xe7, 0xfe, 0xf0, 0xea, 0x6d, 0xa1, 0x43, 0xa0, 0x2b, 0x0f, 0xe2, 0xed}, dcrutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x02, 0x8f, 0x53, 0x83, 0x8b, 0x76, 0x39, 0x56, 0x3f, 0x27, 0xc9, 0x48, 0x45, 0x54, 0x9a, 0x41, 0xe5, 0x14, 0x6b, 0xcd, 0x52, 0xe7, 0xfe, 0xf0, 0xea, 0x6d, 0xa1, 0x43, 0xa0, 0x2b, 0x0f, 0xe2, 0xed} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk compressed (0x03)", addr: "DsfiE2y23CGwKNxSGjbfPGeEW4xw1tamZdc", encoded: "DsfiE2y23CGwKNxSGjbfPGeEW4xw1tamZdc", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x03, 0xe9, 0x25, 0xaa, 0xfc, 0x1e, 0xdd, 0x44, 0xe7, 0xc7, 0xf1, 0xea, 0x4f, 0xb7, 0xd2, 0x65, 0xdc, 0x67, 0x2f, 0x20, 0x4c, 0x3d, 0x0c, 0x81, 0x93, 0x03, 0x89, 0xc1, 0x0b, 0x81, 0xfb, 0x75, 0xde}, dcrutil.PKFCompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x03, 0xe9, 0x25, 0xaa, 0xfc, 0x1e, 0xdd, 0x44, 0xe7, 0xc7, 0xf1, 0xea, 0x4f, 0xb7, 0xd2, 0x65, 0xdc, 0x67, 0x2f, 0x20, 0x4c, 0x3d, 0x0c, 0x81, 0x93, 0x03, 0x89, 0xc1, 0x0b, 0x81, 0xfb, 0x75, 0xde} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, /* XXX currently commented out due to issues with the tests that result in these errors: created address does not match expected result got 0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0, expected 0464c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0b87ca 4279b565d2130ce59f75bfbb2b88da794143d7cfd3e80808a1fa3203904 We are currently only handle compressed keys in dcrd, but the protocol does support hybrid and uncompressed so users may try to implement at some point { name: "mainnet p2pk uncompressed (0x04)", addr: "DkM3EyZ546GghVSkvzb6J47PvGDyntqiDtFgipQhNj78Xm2mUYRpf", encoded: "DsfFjaADsV8c5oHWx85ZqfxCZy74K8RFuhK", valid: true, saddr: "0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0", result: dcrutil.TstAddressPubKey( []byte{ 0x04, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, 0x1f, 0xa3, 0x20, 0x39, 0x04}, dcrutil.PKFUncompressed, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x04, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, 0x1f, 0xa3, 0x20, 0x39, 0x04} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk hybrid (0x06)", addr: "DkM3EyZ546GghVSkvzb6J47PvGDyntqiDtFgipQhNj78Xm2mUYRpf", encoded: "DsfFjaADsV8c5oHWx85ZqfxCZy74K8RFuhK", valid: true, saddr: "0264c44653d6567eff5753c5d24a682ddc2b2cadfe1b0c6433b16374dace6778f0", result: dcrutil.TstAddressPubKey( []byte{ 0x06, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, 0x1f, 0xa3, 0x20, 0x39, 0x04}, dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x06, 0x64, 0xc4, 0x46, 0x53, 0xd6, 0x56, 0x7e, 0xff, 0x57, 0x53, 0xc5, 0xd2, 0x4a, 0x68, 0x2d, 0xdc, 0x2b, 0x2c, 0xad, 0xfe, 0x1b, 0x0c, 0x64, 0x33, 0xb1, 0x63, 0x74, 0xda, 0xce, 0x67, 0x78, 0xf0, 0xb8, 0x7c, 0xa4, 0x27, 0x9b, 0x56, 0x5d, 0x21, 0x30, 0xce, 0x59, 0xf7, 0x5b, 0xfb, 0xb2, 0xb8, 0x8d, 0xa7, 0x94, 0x14, 0x3d, 0x7c, 0xfd, 0x3e, 0x80, 0x80, 0x8a, 0x1f, 0xa3, 0x20, 0x39, 0x04} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, { name: "mainnet p2pk hybrid (0x07)", addr: "DkRKh2aTdwjKKL1mkCb2DFp2Hr7SqMyx3zWqNwyc37PYiGpKmGRsi", encoded: "DskEQZMCs4nifL7wx7iHYGWxMQvR9ThCBKQ", valid: true, saddr: "03348d8aeb4253ca52456fe5da94ab1263bfee16bb8192497f666389ca964f8479", result: dcrutil.TstAddressPubKey( []byte{ 0x07, 0x34, 0x8d, 0x8a, 0xeb, 0x42, 0x53, 0xca, 0x52, 0x45, 0x6f, 0xe5, 0xda, 0x94, 0xab, 0x12, 0x63, 0xbf, 0xee, 0x16, 0xbb, 0x81, 0x92, 0x49, 0x7f, 0x66, 0x63, 0x89, 0xca, 0x96, 0x4f, 0x84, 0x79, 0x83, 0x75, 0x12, 0x9d, 0x79, 0x58, 0x84, 0x3b, 0x14, 0x25, 0x8b, 0x90, 0x5d, 0xc9, 0x4f, 0xae, 0xd3, 0x24, 0xdd, 0x8a, 0x9d, 0x67, 0xff, 0xac, 0x8c, 0xc0, 0xa8, 0x5b, 0xe8, 0x4b, 0xac, 0x5d}, dcrutil.PKFHybrid, chaincfg.MainNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x07, 0x34, 0x8d, 0x8a, 0xeb, 0x42, 0x53, 0xca, 0x52, 0x45, 0x6f, 0xe5, 0xda, 0x94, 0xab, 0x12, 0x63, 0xbf, 0xee, 0x16, 0xbb, 0x81, 0x92, 0x49, 0x7f, 0x66, 0x63, 0x89, 0xca, 0x96, 0x4f, 0x84, 0x79, 0x83, 0x75, 0x12, 0x9d, 0x79, 0x58, 0x84, 0x3b, 0x14, 0x25, 0x8b, 0x90, 0x5d, 0xc9, 0x4f, 0xae, 0xd3, 0x24, 0xdd, 0x8a, 0x9d, 0x67, 0xff, 0xac, 0x8c, 0xc0, 0xa8, 0x5b, 0xe8, 0x4b, 0xac, 0x5d} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.MainNetParams) }, net: &chaincfg.MainNetParams, }, */ { name: "testnet p2pk compressed (0x02)", addr: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e}, dcrutil.PKFCompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x02, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk compressed (0x03)", addr: "TsWZ1EzypJfMwBKAEDYKuyHRGctqGAxMje2", encoded: "TsWZ1EzypJfMwBKAEDYKuyHRGctqGAxMje2", valid: true, result: dcrutil.TstAddressPubKey( []byte{ 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, 0xd9, 0x1a, 0xf5}, dcrutil.PKFCompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x03, 0x08, 0x44, 0xee, 0x70, 0xd8, 0x38, 0x4d, 0x52, 0x50, 0xe9, 0xbb, 0x3a, 0x6a, 0x73, 0xd4, 0xb5, 0xbe, 0xc7, 0x70, 0xe8, 0xb3, 0x1d, 0x6a, 0x0a, 0xe9, 0xfb, 0x73, 0x90, 0x09, 0xd9, 0x1a, 0xf5} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, /* XXX These are commented out for the same reasons above. { name: "testnet p2pk uncompressed (0x04)", addr: "TkKmMiY5iDh4U3KkSopYgkU1AzhAcQZiSoVhYhFymZHGMi9LM9Fdt", encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", valid: true, saddr: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e", result: dcrutil.TstAddressPubKey( []byte{ 0x04, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, 0x7a, 0xce, 0xcf, 0x22, 0x44}, dcrutil.PKFUncompressed, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x04, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, 0x7a, 0xce, 0xcf, 0x22, 0x44} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk hybrid (0x06)", addr: "TkKmMiY5iDh4U3KkSopYgkU1AzhAcQZiSoVhYhFymZHGMi9LM9Fdt", encoded: "Tso9sQD3ALqRsmEkAm7KvPrkGbeG2Vun7Kv", valid: true, saddr: "026a40c403e74670c4de7656a09caa2353d4b383a9ce66eef51e1220eacf4be06e", result: dcrutil.TstAddressPubKey( []byte{ 0x06, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, 0x7a, 0xce, 0xcf, 0x22, 0x44}, dcrutil.PKFHybrid, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x06, 0x6a, 0x40, 0xc4, 0x03, 0xe7, 0x46, 0x70, 0xc4, 0xde, 0x76, 0x56, 0xa0, 0x9c, 0xaa, 0x23, 0x53, 0xd4, 0xb3, 0x83, 0xa9, 0xce, 0x66, 0xee, 0xf5, 0x1e, 0x12, 0x20, 0xea, 0xcf, 0x4b, 0xe0, 0x6e, 0xd5, 0x48, 0xc8, 0xc1, 0x6f, 0xb5, 0xeb, 0x90, 0x07, 0xcb, 0x94, 0x22, 0x0b, 0x3b, 0xb8, 0x94, 0x91, 0xd5, 0xa1, 0xfd, 0x2d, 0x77, 0x86, 0x7f, 0xca, 0x64, 0x21, 0x7a, 0xce, 0xcf, 0x22, 0x44} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, { name: "testnet p2pk hybrid (0x07)", addr: "TkQ5Ax2ieEZpBDA963VDH4y27KMpXtP8qyeykzwBNFocDc8ZKqTGz", encoded: "TsTFLdM32YVrYsEQDFxo2zmPuKFcFhH5ZT3", valid: true, saddr: "03edd40747de905a9becb14987a1a26c1adbd617c45e1583c142a635bfda9493df", result: dcrutil.TstAddressPubKey( []byte{ 0x07, 0xed, 0xd4, 0x07, 0x47, 0xde, 0x90, 0x5a, 0x9b, 0xec, 0xb1, 0x49, 0x87, 0xa1, 0xa2, 0x6c, 0x1a, 0xdb, 0xd6, 0x17, 0xc4, 0x5e, 0x15, 0x83, 0xc1, 0x42, 0xa6, 0x35, 0xbf, 0xda, 0x94, 0x93, 0xdf, 0xa1, 0xc6, 0xd3, 0x67, 0x35, 0x97, 0x49, 0x65, 0xfe, 0x7b, 0x86, 0x1e, 0x7f, 0x6f, 0xcc, 0x08, 0x7d, 0xc7, 0xfe, 0x47, 0x38, 0x0f, 0xa8, 0xbd, 0xe0, 0xd9, 0xc3, 0x22, 0xd5, 0x3c, 0x0e, 0x89}, dcrutil.PKFHybrid, chaincfg.TestNetParams.PubKeyHashAddrID), f: func() (dcrutil.Address, error) { serializedPubKey := []byte{ 0x07, 0xed, 0xd4, 0x07, 0x47, 0xde, 0x90, 0x5a, 0x9b, 0xec, 0xb1, 0x49, 0x87, 0xa1, 0xa2, 0x6c, 0x1a, 0xdb, 0xd6, 0x17, 0xc4, 0x5e, 0x15, 0x83, 0xc1, 0x42, 0xa6, 0x35, 0xbf, 0xda, 0x94, 0x93, 0xdf, 0xa1, 0xc6, 0xd3, 0x67, 0x35, 0x97, 0x49, 0x65, 0xfe, 0x7b, 0x86, 0x1e, 0x7f, 0x6f, 0xcc, 0x08, 0x7d, 0xc7, 0xfe, 0x47, 0x38, 0x0f, 0xa8, 0xbd, 0xe0, 0xd9, 0xc3, 0x22, 0xd5, 0x3c, 0x0e, 0x89} return dcrutil.NewAddressSecpPubKey(serializedPubKey, &chaincfg.TestNetParams) }, net: &chaincfg.TestNetParams, }, */ } for _, test := range tests { // Decode addr and compare error against valid. decoded, err := dcrutil.DecodeAddress(test.addr, test.net) if (err == nil) != test.valid { t.Errorf("%v: decoding test failed: %v", test.name, err) return } if err == nil { // Ensure the stringer returns the same address as the // original. if decodedStringer, ok := decoded.(fmt.Stringer); ok { if test.addr != decodedStringer.String() { t.Errorf("%v: String on decoded value does not match expected value: %v != %v", test.name, test.addr, decodedStringer.String()) return } } // Encode again and compare against the original. encoded := decoded.EncodeAddress() if test.encoded != encoded { t.Errorf("%v: decoding and encoding produced different addressess: %v != %v", test.name, test.encoded, encoded) return } // Perform type-specific calculations. var saddr []byte switch d := decoded.(type) { case *dcrutil.AddressPubKeyHash: saddr = dcrutil.TstAddressSAddr(encoded) case *dcrutil.AddressScriptHash: saddr = dcrutil.TstAddressSAddr(encoded) case *dcrutil.AddressSecpPubKey: // Ignore the error here since the script // address is checked below. saddr, err = hex.DecodeString(d.String()) if err != nil { saddr, _ = hex.DecodeString(test.saddr) } case *dcrutil.AddressEdwardsPubKey: // Ignore the error here since the script // address is checked below. saddr, _ = hex.DecodeString(d.String()) case *dcrutil.AddressSecSchnorrPubKey: // Ignore the error here since the script // address is checked below. saddr, _ = hex.DecodeString(d.String()) } // Check script address, as well as the Hash160 method for P2PKH and // P2SH addresses. if !bytes.Equal(saddr, decoded.ScriptAddress()) { t.Errorf("%v: script addresses do not match:\n%x != \n%x", test.name, saddr, decoded.ScriptAddress()) return } switch a := decoded.(type) { case *dcrutil.AddressPubKeyHash: if h := a.Hash160()[:]; !bytes.Equal(saddr, h) { t.Errorf("%v: hashes do not match:\n%x != \n%x", test.name, saddr, h) return } case *dcrutil.AddressScriptHash: if h := a.Hash160()[:]; !bytes.Equal(saddr, h) { t.Errorf("%v: hashes do not match:\n%x != \n%x", test.name, saddr, h) return } } // Ensure the address is for the expected network. if !decoded.IsForNet(test.net) { t.Errorf("%v: calculated network does not match expected", test.name) return } } if !test.valid { // If address is invalid, but a creation function exists, // verify that it returns a nil addr and non-nil error. if test.f != nil { _, err := test.f() if err == nil { t.Errorf("%v: address is invalid but creating new address succeeded", test.name) return } } continue } // Valid test, compare address created with f against expected result. addr, err := test.f() if err != nil { t.Errorf("%v: address is valid but creating new address failed with error %v", test.name, err) return } if !reflect.DeepEqual(addr.ScriptAddress(), test.result.ScriptAddress()) { t.Errorf("%v: created address does not match expected result \n "+ " got %x, expected %x", test.name, addr.ScriptAddress(), test.result.ScriptAddress()) return } } }