Merge pull request #205 from guggero/schnorr-taproot
address: add AddressTaproot
This commit is contained in:
commit
9cdf59f60c
3 changed files with 309 additions and 127 deletions
265
address.go
265
address.go
|
@ -64,8 +64,8 @@ func encodeAddress(hash160 []byte, netID byte) string {
|
|||
return base58.CheckEncode(hash160[:ripemd160.Size], netID)
|
||||
}
|
||||
|
||||
// encodeSegWitAddress creates a bech32 encoded address string representation
|
||||
// from witness version and witness program.
|
||||
// encodeSegWitAddress creates a bech32 (or bech32m for SegWit v1) encoded
|
||||
// address string representation from witness version and witness program.
|
||||
func encodeSegWitAddress(hrp string, witnessVersion byte, witnessProgram []byte) (string, error) {
|
||||
// Group the address bytes into 5 bit groups, as this is what is used to
|
||||
// encode each character in the address string.
|
||||
|
@ -79,7 +79,19 @@ func encodeSegWitAddress(hrp string, witnessVersion byte, witnessProgram []byte)
|
|||
combined := make([]byte, len(converted)+1)
|
||||
combined[0] = witnessVersion
|
||||
copy(combined[1:], converted)
|
||||
bech, err := bech32.Encode(hrp, combined)
|
||||
|
||||
var bech string
|
||||
switch witnessVersion {
|
||||
case 0:
|
||||
bech, err = bech32.Encode(hrp, combined)
|
||||
|
||||
case 1:
|
||||
bech, err = bech32.EncodeM(hrp, combined)
|
||||
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported witness version %d",
|
||||
witnessVersion)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -149,8 +161,9 @@ func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
|
|||
}
|
||||
|
||||
// We currently only support P2WPKH and P2WSH, which is
|
||||
// witness version 0.
|
||||
if witnessVer != 0 {
|
||||
// witness version 0 and P2TR which is witness version
|
||||
// 1.
|
||||
if witnessVer != 0 && witnessVer != 1 {
|
||||
return nil, UnsupportedWitnessVerError(witnessVer)
|
||||
}
|
||||
|
||||
|
@ -161,6 +174,10 @@ func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
|
|||
case 20:
|
||||
return newAddressWitnessPubKeyHash(hrp, witnessProg)
|
||||
case 32:
|
||||
if witnessVer == 1 {
|
||||
return newAddressTaproot(hrp, witnessProg)
|
||||
}
|
||||
|
||||
return newAddressWitnessScriptHash(hrp, witnessProg)
|
||||
default:
|
||||
return nil, UnsupportedWitnessProgLenError(len(witnessProg))
|
||||
|
@ -210,7 +227,7 @@ func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
|
|||
// returns the witness version and witness program byte representation.
|
||||
func decodeSegWitAddress(address string) (byte, []byte, error) {
|
||||
// Decode the bech32 encoded address.
|
||||
_, data, err := bech32.Decode(address)
|
||||
_, data, bech32version, err := bech32.DecodeGeneric(address)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
@ -246,6 +263,18 @@ func decodeSegWitAddress(address string) (byte, []byte, error) {
|
|||
"version 0: %v", len(regrouped))
|
||||
}
|
||||
|
||||
// For witness version 0, the bech32 encoding must be used.
|
||||
if version == 0 && bech32version != bech32.Version0 {
|
||||
return 0, nil, fmt.Errorf("invalid checksum expected bech32 " +
|
||||
"encoding for address with witness version 0")
|
||||
}
|
||||
|
||||
// For witness version 1, the bech32m encoding must be used.
|
||||
if version == 1 && bech32version != bech32.VersionM {
|
||||
return 0, nil, fmt.Errorf("invalid checksum expected bech32m " +
|
||||
"encoding for address with witness version 1")
|
||||
}
|
||||
|
||||
return version, regrouped, nil
|
||||
}
|
||||
|
||||
|
@ -506,25 +535,88 @@ func (a *AddressPubKey) PubKey() *btcec.PublicKey {
|
|||
return a.pubKey
|
||||
}
|
||||
|
||||
// AddressSegWit is the base address type for all SegWit addresses.
|
||||
type AddressSegWit struct {
|
||||
hrp string
|
||||
witnessVersion byte
|
||||
witnessProgram []byte
|
||||
}
|
||||
|
||||
// EncodeAddress returns the bech32 (or bech32m for SegWit v1) string encoding
|
||||
// of an AddressSegWit.
|
||||
//
|
||||
// NOTE: This method is part of the Address interface.
|
||||
func (a *AddressSegWit) EncodeAddress() string {
|
||||
str, err := encodeSegWitAddress(
|
||||
a.hrp, a.witnessVersion, a.witnessProgram[:],
|
||||
)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// ScriptAddress returns the witness program for this address.
|
||||
//
|
||||
// NOTE: This method is part of the Address interface.
|
||||
func (a *AddressSegWit) ScriptAddress() []byte {
|
||||
return a.witnessProgram[:]
|
||||
}
|
||||
|
||||
// IsForNet returns whether the AddressSegWit is associated with the passed
|
||||
// bitcoin network.
|
||||
//
|
||||
// NOTE: This method is part of the Address interface.
|
||||
func (a *AddressSegWit) IsForNet(net *chaincfg.Params) bool {
|
||||
return a.hrp == net.Bech32HRPSegwit
|
||||
}
|
||||
|
||||
// String returns a human-readable string for the AddressWitnessPubKeyHash.
|
||||
// This is equivalent to calling EncodeAddress, but is provided so the type
|
||||
// can be used as a fmt.Stringer.
|
||||
//
|
||||
// NOTE: This method is part of the Address interface.
|
||||
func (a *AddressSegWit) String() string {
|
||||
return a.EncodeAddress()
|
||||
}
|
||||
|
||||
// Hrp returns the human-readable part of the bech32 (or bech32m for SegWit v1)
|
||||
// encoded AddressSegWit.
|
||||
func (a *AddressSegWit) Hrp() string {
|
||||
return a.hrp
|
||||
}
|
||||
|
||||
// WitnessVersion returns the witness version of the AddressSegWit.
|
||||
func (a *AddressSegWit) WitnessVersion() byte {
|
||||
return a.witnessVersion
|
||||
}
|
||||
|
||||
// WitnessProgram returns the witness program of the AddressSegWit.
|
||||
func (a *AddressSegWit) WitnessProgram() []byte {
|
||||
return a.witnessProgram[:]
|
||||
}
|
||||
|
||||
// AddressWitnessPubKeyHash is an Address for a pay-to-witness-pubkey-hash
|
||||
// (P2WPKH) output. See BIP 173 for further details regarding native segregated
|
||||
// witness address encoding:
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||
type AddressWitnessPubKeyHash struct {
|
||||
hrp string
|
||||
witnessVersion byte
|
||||
witnessProgram [20]byte
|
||||
AddressSegWit
|
||||
}
|
||||
|
||||
// NewAddressWitnessPubKeyHash returns a new AddressWitnessPubKeyHash.
|
||||
func NewAddressWitnessPubKeyHash(witnessProg []byte, net *chaincfg.Params) (*AddressWitnessPubKeyHash, error) {
|
||||
func NewAddressWitnessPubKeyHash(witnessProg []byte,
|
||||
net *chaincfg.Params) (*AddressWitnessPubKeyHash, error) {
|
||||
|
||||
return newAddressWitnessPubKeyHash(net.Bech32HRPSegwit, witnessProg)
|
||||
}
|
||||
|
||||
// newAddressWitnessPubKeyHash is an internal helper function to create an
|
||||
// AddressWitnessPubKeyHash with a known human-readable part, rather than
|
||||
// looking it up through its parameters.
|
||||
func newAddressWitnessPubKeyHash(hrp string, witnessProg []byte) (*AddressWitnessPubKeyHash, error) {
|
||||
func newAddressWitnessPubKeyHash(hrp string,
|
||||
witnessProg []byte) (*AddressWitnessPubKeyHash, error) {
|
||||
|
||||
// Check for valid program length for witness version 0, which is 20
|
||||
// for P2WPKH.
|
||||
if len(witnessProg) != 20 {
|
||||
|
@ -533,68 +625,22 @@ func newAddressWitnessPubKeyHash(hrp string, witnessProg []byte) (*AddressWitnes
|
|||
}
|
||||
|
||||
addr := &AddressWitnessPubKeyHash{
|
||||
AddressSegWit{
|
||||
hrp: strings.ToLower(hrp),
|
||||
witnessVersion: 0x00,
|
||||
witnessProgram: witnessProg,
|
||||
},
|
||||
}
|
||||
|
||||
copy(addr.witnessProgram[:], witnessProg)
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// EncodeAddress returns the bech32 string encoding of an
|
||||
// AddressWitnessPubKeyHash.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessPubKeyHash) EncodeAddress() string {
|
||||
str, err := encodeSegWitAddress(a.hrp, a.witnessVersion,
|
||||
a.witnessProgram[:])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// ScriptAddress returns the witness program for this address.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessPubKeyHash) ScriptAddress() []byte {
|
||||
return a.witnessProgram[:]
|
||||
}
|
||||
|
||||
// IsForNet returns whether or not the AddressWitnessPubKeyHash is associated
|
||||
// with the passed bitcoin network.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessPubKeyHash) IsForNet(net *chaincfg.Params) bool {
|
||||
return a.hrp == net.Bech32HRPSegwit
|
||||
}
|
||||
|
||||
// String returns a human-readable string for the AddressWitnessPubKeyHash.
|
||||
// This is equivalent to calling EncodeAddress, but is provided so the type
|
||||
// can be used as a fmt.Stringer.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessPubKeyHash) String() string {
|
||||
return a.EncodeAddress()
|
||||
}
|
||||
|
||||
// Hrp returns the human-readable part of the bech32 encoded
|
||||
// AddressWitnessPubKeyHash.
|
||||
func (a *AddressWitnessPubKeyHash) Hrp() string {
|
||||
return a.hrp
|
||||
}
|
||||
|
||||
// WitnessVersion returns the witness version of the AddressWitnessPubKeyHash.
|
||||
func (a *AddressWitnessPubKeyHash) WitnessVersion() byte {
|
||||
return a.witnessVersion
|
||||
}
|
||||
|
||||
// WitnessProgram returns the witness program of the AddressWitnessPubKeyHash.
|
||||
func (a *AddressWitnessPubKeyHash) WitnessProgram() []byte {
|
||||
return a.witnessProgram[:]
|
||||
}
|
||||
|
||||
// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
|
||||
// byte array.
|
||||
func (a *AddressWitnessPubKeyHash) Hash160() *[20]byte {
|
||||
return &a.witnessProgram
|
||||
var pubKeyHashWitnessProgram [20]byte
|
||||
copy(pubKeyHashWitnessProgram[:], a.witnessProgram)
|
||||
return &pubKeyHashWitnessProgram
|
||||
}
|
||||
|
||||
// AddressWitnessScriptHash is an Address for a pay-to-witness-script-hash
|
||||
|
@ -602,20 +648,22 @@ func (a *AddressWitnessPubKeyHash) Hash160() *[20]byte {
|
|||
// witness address encoding:
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||
type AddressWitnessScriptHash struct {
|
||||
hrp string
|
||||
witnessVersion byte
|
||||
witnessProgram [32]byte
|
||||
AddressSegWit
|
||||
}
|
||||
|
||||
// NewAddressWitnessScriptHash returns a new AddressWitnessPubKeyHash.
|
||||
func NewAddressWitnessScriptHash(witnessProg []byte, net *chaincfg.Params) (*AddressWitnessScriptHash, error) {
|
||||
func NewAddressWitnessScriptHash(witnessProg []byte,
|
||||
net *chaincfg.Params) (*AddressWitnessScriptHash, error) {
|
||||
|
||||
return newAddressWitnessScriptHash(net.Bech32HRPSegwit, witnessProg)
|
||||
}
|
||||
|
||||
// newAddressWitnessScriptHash is an internal helper function to create an
|
||||
// AddressWitnessScriptHash with a known human-readable part, rather than
|
||||
// looking it up through its parameters.
|
||||
func newAddressWitnessScriptHash(hrp string, witnessProg []byte) (*AddressWitnessScriptHash, error) {
|
||||
func newAddressWitnessScriptHash(hrp string,
|
||||
witnessProg []byte) (*AddressWitnessScriptHash, error) {
|
||||
|
||||
// Check for valid program length for witness version 0, which is 32
|
||||
// for P2WSH.
|
||||
if len(witnessProg) != 32 {
|
||||
|
@ -624,60 +672,49 @@ func newAddressWitnessScriptHash(hrp string, witnessProg []byte) (*AddressWitnes
|
|||
}
|
||||
|
||||
addr := &AddressWitnessScriptHash{
|
||||
AddressSegWit{
|
||||
hrp: strings.ToLower(hrp),
|
||||
witnessVersion: 0x00,
|
||||
witnessProgram: witnessProg,
|
||||
},
|
||||
}
|
||||
|
||||
copy(addr.witnessProgram[:], witnessProg)
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// EncodeAddress returns the bech32 string encoding of an
|
||||
// AddressWitnessScriptHash.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessScriptHash) EncodeAddress() string {
|
||||
str, err := encodeSegWitAddress(a.hrp, a.witnessVersion,
|
||||
a.witnessProgram[:])
|
||||
if err != nil {
|
||||
return ""
|
||||
// AddressTaproot is an Address for a pay-to-taproot (P2TR) output. See BIP 341
|
||||
// for further details.
|
||||
type AddressTaproot struct {
|
||||
AddressSegWit
|
||||
}
|
||||
|
||||
// NewAddressTaproot returns a new AddressTaproot.
|
||||
func NewAddressTaproot(witnessProg []byte,
|
||||
net *chaincfg.Params) (*AddressTaproot, error) {
|
||||
|
||||
return newAddressTaproot(net.Bech32HRPSegwit, witnessProg)
|
||||
}
|
||||
|
||||
// newAddressWitnessScriptHash is an internal helper function to create an
|
||||
// AddressWitnessScriptHash with a known human-readable part, rather than
|
||||
// looking it up through its parameters.
|
||||
func newAddressTaproot(hrp string,
|
||||
witnessProg []byte) (*AddressTaproot, error) {
|
||||
|
||||
// Check for valid program length for witness version 1, which is 32
|
||||
// for P2TR.
|
||||
if len(witnessProg) != 32 {
|
||||
return nil, errors.New("witness program must be 32 bytes for " +
|
||||
"p2tr")
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// ScriptAddress returns the witness program for this address.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessScriptHash) ScriptAddress() []byte {
|
||||
return a.witnessProgram[:]
|
||||
}
|
||||
addr := &AddressTaproot{
|
||||
AddressSegWit{
|
||||
hrp: strings.ToLower(hrp),
|
||||
witnessVersion: 0x01,
|
||||
witnessProgram: witnessProg,
|
||||
},
|
||||
}
|
||||
|
||||
// IsForNet returns whether or not the AddressWitnessScriptHash is associated
|
||||
// with the passed bitcoin network.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessScriptHash) IsForNet(net *chaincfg.Params) bool {
|
||||
return a.hrp == net.Bech32HRPSegwit
|
||||
}
|
||||
|
||||
// String returns a human-readable string for the AddressWitnessScriptHash.
|
||||
// This is equivalent to calling EncodeAddress, but is provided so the type
|
||||
// can be used as a fmt.Stringer.
|
||||
// Part of the Address interface.
|
||||
func (a *AddressWitnessScriptHash) String() string {
|
||||
return a.EncodeAddress()
|
||||
}
|
||||
|
||||
// Hrp returns the human-readable part of the bech32 encoded
|
||||
// AddressWitnessScriptHash.
|
||||
func (a *AddressWitnessScriptHash) Hrp() string {
|
||||
return a.hrp
|
||||
}
|
||||
|
||||
// WitnessVersion returns the witness version of the AddressWitnessScriptHash.
|
||||
func (a *AddressWitnessScriptHash) WitnessVersion() byte {
|
||||
return a.witnessVersion
|
||||
}
|
||||
|
||||
// WitnessProgram returns the witness program of the AddressWitnessScriptHash.
|
||||
func (a *AddressWitnessScriptHash) WitnessProgram() []byte {
|
||||
return a.witnessProgram[:]
|
||||
return addr, nil
|
||||
}
|
||||
|
|
118
address_test.go
118
address_test.go
|
@ -655,13 +655,123 @@ func TestAddresses(t *testing.T) {
|
|||
},
|
||||
net: &customParams,
|
||||
},
|
||||
// Unsupported witness versions (version 0 only supported at this point)
|
||||
|
||||
// P2TR address tests.
|
||||
{
|
||||
name: "segwit mainnet witness v1",
|
||||
addr: "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
|
||||
name: "segwit v1 mainnet p2tr",
|
||||
addr: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
|
||||
encoded: "bc1paardr2nczq0rx5rqpfwnvpzm497zvux64y0f7wjgcs7xuuuh2nnqwr2d5c",
|
||||
valid: true,
|
||||
result: btcutil.TstAddressTaproot(
|
||||
1, [32]byte{
|
||||
0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
|
||||
0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
|
||||
0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
|
||||
0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
|
||||
}, chaincfg.MainNetParams.Bech32HRPSegwit,
|
||||
),
|
||||
f: func() (btcutil.Address, error) {
|
||||
scriptHash := []byte{
|
||||
0xef, 0x46, 0xd1, 0xaa, 0x78, 0x10, 0x1e, 0x33,
|
||||
0x50, 0x60, 0x0a, 0x5d, 0x36, 0x04, 0x5b, 0xa9,
|
||||
0x7c, 0x26, 0x70, 0xda, 0xa9, 0x1e, 0x9f, 0x3a,
|
||||
0x48, 0xc4, 0x3c, 0x6e, 0x73, 0x97, 0x54, 0xe6,
|
||||
}
|
||||
return btcutil.NewAddressTaproot(
|
||||
scriptHash, &chaincfg.MainNetParams,
|
||||
)
|
||||
},
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
|
||||
// Invalid bech32m tests. Source:
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
|
||||
{
|
||||
name: "segwit v1 invalid human-readable part",
|
||||
addr: "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32 instead of bech32m",
|
||||
addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 testnet bech32 instead of bech32m",
|
||||
addr: "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
|
||||
valid: false,
|
||||
net: &chaincfg.TestNet3Params,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32 instead of bech32m upper case",
|
||||
addr: "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v0 mainnet bech32m instead of bech32",
|
||||
addr: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 testnet bech32 instead of bech32m second test",
|
||||
addr: "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
|
||||
valid: false,
|
||||
net: &chaincfg.TestNet3Params,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m invalid character in checksum",
|
||||
addr: "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit mainnet witness v17",
|
||||
addr: "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m invalid program length (1 byte)",
|
||||
addr: "bc1pw5dgrnzv",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m invalid program length (41 bytes)",
|
||||
addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 testnet bech32m mixed case",
|
||||
addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
|
||||
valid: false,
|
||||
net: &chaincfg.TestNet3Params,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m zero padding of more than 4 bits",
|
||||
addr: "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m non-zero padding in 8-to-5-conversion",
|
||||
addr: "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
|
||||
valid: false,
|
||||
net: &chaincfg.TestNet3Params,
|
||||
},
|
||||
{
|
||||
name: "segwit v1 mainnet bech32m empty data section",
|
||||
addr: "bc1gmk9yu",
|
||||
valid: false,
|
||||
net: &chaincfg.MainNetParams,
|
||||
},
|
||||
|
||||
// Unsupported witness versions (version 0 and 1 only supported at this point)
|
||||
{
|
||||
name: "segwit mainnet witness v16",
|
||||
addr: "BC1SW50QA3JX3S",
|
||||
|
@ -788,6 +898,8 @@ func TestAddresses(t *testing.T) {
|
|||
saddr = btcutil.TstAddressSegwitSAddr(encoded)
|
||||
case *btcutil.AddressWitnessScriptHash:
|
||||
saddr = btcutil.TstAddressSegwitSAddr(encoded)
|
||||
case *btcutil.AddressTaproot:
|
||||
saddr = btcutil.TstAddressTaprootSAddr(encoded)
|
||||
}
|
||||
|
||||
// Check script address, as well as the Hash160 method for P2PKH and
|
||||
|
|
|
@ -59,9 +59,11 @@ func TstAddressWitnessPubKeyHash(version byte, program [20]byte,
|
|||
hrp string) *AddressWitnessPubKeyHash {
|
||||
|
||||
return &AddressWitnessPubKeyHash{
|
||||
AddressSegWit{
|
||||
hrp: hrp,
|
||||
witnessVersion: version,
|
||||
witnessProgram: program,
|
||||
witnessProgram: program[:],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,9 +73,24 @@ func TstAddressWitnessScriptHash(version byte, program [32]byte,
|
|||
hrp string) *AddressWitnessScriptHash {
|
||||
|
||||
return &AddressWitnessScriptHash{
|
||||
AddressSegWit{
|
||||
hrp: hrp,
|
||||
witnessVersion: version,
|
||||
witnessProgram: program,
|
||||
witnessProgram: program[:],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TstAddressTaproot creates an AddressTaproot, initiating the fields as given.
|
||||
func TstAddressTaproot(version byte, program [32]byte,
|
||||
hrp string) *AddressTaproot {
|
||||
|
||||
return &AddressTaproot{
|
||||
AddressSegWit{
|
||||
hrp: hrp,
|
||||
witnessVersion: version,
|
||||
witnessProgram: program[:],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,3 +129,19 @@ func TstAddressSegwitSAddr(addr string) []byte {
|
|||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// TstAddressTaprootSAddr returns the expected witness program bytes for a
|
||||
// bech32m encoded P2TR bitcoin address.
|
||||
func TstAddressTaprootSAddr(addr string) []byte {
|
||||
_, data, err := bech32.Decode(addr)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// First byte is version, rest is base 32 encoded data.
|
||||
data, err = bech32.ConvertBits(data[1:], 5, 8, false)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue