*signers.Signer
Alias string
Tags map[string]interface{}
+ Address common.Address
}
// Create creates a new Account.
}
return decoder, true
}
-
+/* {"actions": [
+ {"type": "spend", "asset_id": "%s", "amount": 100},
+ {"type": "control_account", "asset_id": "%s", "amount": 100, "account_id": "%s"}
+ ]}`
+*/
func (a *BlockchainReactor) buildSingle(ctx context.Context, req *BuildRequest) (*txbuilder.Template, error) {
err := a.filterAliases(ctx, req)
if err != nil {
return tpl, nil
}
+
func Sign(ctx context.Context, tpl *Template, xpubs []chainkd.XPub, auth string, signFn SignFunc) error {
for i, sigInst := range tpl.SigningInstructions {
for j, sw := range sigInst.SignatureWitnesses {
// assumes that everything already in the arg list before this call
// to Materialize is input to the signature program, so N is
// len(*args).
+ // 0 sig1 sig2 ... program 100 sig1 sig2 ... program
*args = append(*args, vm.Int64Bytes(int64(len(*args))))
var nsigs int
--- /dev/null
+package common
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/bytom/consensus"
+ "github.com/bytom/common/bech32"
+)
+
+var (
+ // ErrChecksumMismatch describes an error where decoding failed due
+ // to a bad checksum.
+ ErrChecksumMismatch = errors.New("checksum mismatch")
+
+ // ErrUnknownAddressType describes an error where an address can not
+ // decoded as a specific address type due to the string encoding
+ // begining with an identifier byte unknown to any standard or
+ // registered (via chaincfg.Register) network.
+ ErrUnknownAddressType = errors.New("unknown address type")
+
+ // ErrAddressCollision describes an error where an address can not
+ // be uniquely determined as either a pay-to-pubkey-hash or
+ // pay-to-script-hash address since the leading identifier is used for
+ // describing both address kinds, but for different networks. Rather
+ // than assuming or defaulting to one or the other, this error is
+ // returned and the caller must decide how to decode the address.
+ ErrAddressCollision = errors.New("address collision")
+
+ // ErrUnsupportedWitnessVer describes an error where a segwit address being
+ // decoded has an unsupported witness version.
+ ErrUnsupportedWitnessVer = errors.New("unsupported witness version")
+
+ // ErrUnsupportedWitnessProgLen describes an error where a segwit address
+ // being decoded has an unsupported witness program length.
+ ErrUnsupportedWitnessProgLen = errors.New("unsupported witness program length")
+
+
+)
+
+// Address is an interface type for any type of destination a transaction
+// output may spend to. This includes pay-to-pubkey (P2PK), pay-to-pubkey-hash
+// (P2PKH), and pay-to-script-hash (P2SH). Address is designed to be generic
+// enough that other kinds of addresses may be added in the future without
+// changing the decoding and encoding API.
+type Address interface {
+ // String returns the string encoding of the transaction output
+ // destination.
+ //
+ // Please note that String differs subtly from EncodeAddress: String
+ // will return the value as a string without any conversion, while
+ // EncodeAddress may convert destination types (for example,
+ // converting pubkeys to P2PKH addresses) before encoding as a
+ // payment address string.
+ String() string
+
+ // EncodeAddress returns the string encoding of the payment address
+ // associated with the Address value. See the comment on String
+ // for how this method differs from String.
+ EncodeAddress() string
+
+ // ScriptAddress returns the raw bytes of the address to be used
+ // when inserting the address into a txout's script.
+ ScriptAddress() []byte
+
+ // IsForNet returns whether or not the address is associated with the
+ // passed bytom network.
+ IsForNet(*consensus.Params) bool
+}
+
+
+
+// encodeSegWitAddress creates a bech32 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.
+ converted, err := bech32.ConvertBits(witnessProgram, 8, 5, true)
+ if err != nil {
+ return "", err
+ }
+
+ // Concatenate the witness version and program, and encode the resulting
+ // bytes using bech32 encoding.
+ combined := make([]byte, len(converted)+1)
+ combined[0] = witnessVersion
+ copy(combined[1:], converted)
+ bech, err := bech32.Encode(hrp, combined)
+ if err != nil {
+ return "", err
+ }
+
+ // Check validity by decoding the created address.
+ version, program, err := decodeSegWitAddress(bech)
+ if err != nil {
+ return "", fmt.Errorf("invalid segwit address: %v", err)
+ }
+
+ if version != witnessVersion || !bytes.Equal(program, witnessProgram) {
+ return "", fmt.Errorf("invalid segwit address")
+ }
+
+ return bech, nil
+}
+
+
+
+// DecodeAddress decodes the string encoding of an address and returns
+// the Address if addr is a valid encoding for a known address type.
+//
+// The bytom network the address is associated with is extracted if possible.
+// When the address does not encode the network, such as in the case of a raw
+// public key, the address will be associated with the passed defaultNet.
+func DecodeAddress(addr string, param *consensus.Params) (Address, error) {
+ // Bech32 encoded segwit addresses start with a human-readable part
+ // (hrp) followed by '1'. For Bytom mainnet the hrp is "bm", and for
+ // testnet it is "tm". If the address string has a prefix that matches
+ // one of the prefixes for the known networks, we try to decode it as
+ // a segwit address.
+ oneIndex := strings.LastIndexByte(addr, '1')
+ if oneIndex > 1 {
+ prefix := addr[:oneIndex+1]
+ if consensus.IsBech32SegwitPrefix(prefix, param) {
+ witnessVer, witnessProg, err := decodeSegWitAddress(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ // We currently only support P2WPKH and P2WSH, which is
+ // witness version 0.
+ if witnessVer != 0 {
+ return nil, ErrUnsupportedWitnessVer
+ }
+
+ // The HRP is everything before the found '1'.
+ hrp := prefix[:len(prefix)-1]
+
+ switch len(witnessProg) {
+ case 20:
+ return newAddressWitnessPubKeyHash(hrp, witnessProg)
+ case 32:
+ return newAddressWitnessScriptHash(hrp, witnessProg)
+ default:
+ return nil, ErrUnsupportedWitnessProgLen
+ }
+ }
+ }
+ return nil, ErrUnknownAddressType
+}
+
+// decodeSegWitAddress parses a bech32 encoded segwit address string and
+// 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)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ // The first byte of the decoded address is the witness version, it must
+ // exist.
+ if len(data) < 1 {
+ return 0, nil, fmt.Errorf("no witness version")
+ }
+
+ // ...and be <= 16.
+ version := data[0]
+ if version > 16 {
+ return 0, nil, fmt.Errorf("invalid witness version: %v", version)
+ }
+
+ // The remaining characters of the address returned are grouped into
+ // words of 5 bits. In order to restore the original witness program
+ // bytes, we'll need to regroup into 8 bit words.
+ regrouped, err := bech32.ConvertBits(data[1:], 5, 8, false)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ // The regrouped data must be between 2 and 40 bytes.
+ if len(regrouped) < 2 || len(regrouped) > 40 {
+ return 0, nil, fmt.Errorf("invalid data length")
+ }
+
+ // For witness version 0, address MUST be exactly 20 or 32 bytes.
+ if version == 0 && len(regrouped) != 20 && len(regrouped) != 32 {
+ return 0, nil, fmt.Errorf("invalid data length for witness "+
+ "version 0: %v", len(regrouped))
+ }
+
+ return version, regrouped, nil
+}
+
+
+// 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
+}
+
+// NewAddressWitnessPubKeyHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessPubKeyHash(witnessProg []byte, param *consensus.Params) (*AddressWitnessPubKeyHash, error) {
+ return newAddressWitnessPubKeyHash(param.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) {
+ // Check for valid program length for witness version 0, which is 20
+ // for P2WPKH.
+ if len(witnessProg) != 20 {
+ return nil, errors.New("witness program must be 20 " +
+ "bytes for p2wpkh")
+ }
+
+ addr := &AddressWitnessPubKeyHash{
+ hrp: strings.ToLower(hrp),
+ witnessVersion: 0x00,
+ }
+
+ 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(param *consensus.Params) bool {
+ return a.hrp == param.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
+}
+
+// AddressWitnessScriptHash is an Address for a pay-to-witness-script-hash
+// (P2WSH) output. See BIP 173 for further details regarding native segregated
+// witness address encoding:
+// https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+type AddressWitnessScriptHash struct {
+ hrp string
+ witnessVersion byte
+ witnessProgram [32]byte
+}
+
+// NewAddressWitnessScriptHash returns a new AddressWitnessPubKeyHash.
+func NewAddressWitnessScriptHash(witnessProg []byte, param *consensus.Params) (*AddressWitnessScriptHash, error) {
+ return newAddressWitnessScriptHash(param.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) {
+ // Check for valid program length for witness version 0, which is 32
+ // for P2WSH.
+ if len(witnessProg) != 32 {
+ return nil, errors.New("witness program must be 32 " +
+ "bytes for p2wsh")
+ }
+
+ addr := &AddressWitnessScriptHash{
+ hrp: strings.ToLower(hrp),
+ witnessVersion: 0x00,
+ }
+
+ 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 ""
+ }
+ return str
+}
+
+// ScriptAddress returns the witness program for this address.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) ScriptAddress() []byte {
+ return a.witnessProgram[:]
+}
+
+// IsForNet returns whether or not the AddressWitnessScriptHash is associated
+// with the passed bytom network.
+// Part of the Address interface.
+func (a *AddressWitnessScriptHash) IsForNet(param *consensus.Params) bool {
+ return a.hrp == param.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[:]
+}
+
+// Hash160 returns the witness program of the AddressWitnessPubKeyHash as a
+// byte array.
+func (a *AddressWitnessScriptHash) Sha256() *[32]byte {
+ return &a.witnessProgram
+}
\ No newline at end of file
--- /dev/null
+package common
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/bytom/consensus"
+ "github.com/bytom/common/bech32"
+
+)
+
+func TestAddresses(t *testing.T) {
+ tests := []struct {
+ name string
+ addr string
+ encoded string
+ valid bool
+ result Address
+ f func() (Address, error)
+ net *consensus.Params
+ }{
+ // Segwit address tests.
+ {
+ name: "segwit mainnet p2wpkh v0",
+ addr: "BM1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7K23GYYF",
+ encoded: "bm1qw508d6qejxtdg4y5r3zarvary0c5xw7k23gyyf",
+ valid: true,
+ result: tstAddressWitnessPubKeyHash(
+ 0,
+ [20]byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+ consensus.MainNetParams.Bech32HRPSegwit),
+ f: func() (Address, error) {
+ pkHash := []byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+ return NewAddressWitnessPubKeyHash(pkHash, &consensus.MainNetParams)
+ },
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit mainnet p2wsh v0",
+ addr: "bm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qk5egtg",
+ encoded: "bm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qk5egtg",
+ valid: true,
+ result: tstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+ consensus.MainNetParams.Bech32HRPSegwit),
+ f: func() (Address, error) {
+ scriptHash := []byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+ return NewAddressWitnessScriptHash(scriptHash, &consensus.MainNetParams)
+ },
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit testnet p2wpkh v0",
+ addr: "tm1qw508d6qejxtdg4y5r3zarvary0c5xw7kw8fqyc",
+ encoded: "tm1qw508d6qejxtdg4y5r3zarvary0c5xw7kw8fqyc",
+ valid: true,
+ result: tstAddressWitnessPubKeyHash(
+ 0,
+ [20]byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6},
+ consensus.TestNetParams.Bech32HRPSegwit),
+ f: func() (Address, error) {
+ pkHash := []byte{
+ 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
+ 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}
+ return NewAddressWitnessPubKeyHash(pkHash, &consensus.TestNetParams)
+ },
+ net: &consensus.TestNetParams,
+ },
+ {
+ name: "segwit testnet p2wsh v0",
+ addr: "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qqq379v",
+ encoded: "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qqq379v",
+ valid: true,
+ result: tstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62},
+ consensus.TestNetParams.Bech32HRPSegwit),
+ f: func() (Address, error) {
+ scriptHash := []byte{
+ 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68,
+ 0x04, 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13,
+ 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d, 0x27, 0xa1,
+ 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}
+ return NewAddressWitnessScriptHash(scriptHash, &consensus.TestNetParams)
+ },
+ net: &consensus.TestNetParams,
+ },
+ {
+ name: "segwit testnet p2wsh witness v0",
+ addr: "tm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesvkesyk",
+ encoded: "tm1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesvkesyk",
+ valid: true,
+ result: tstAddressWitnessScriptHash(
+ 0,
+ [32]byte{
+ 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+ 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+ 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+ 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33},
+ consensus.TestNetParams.Bech32HRPSegwit),
+ f: func() (Address, error) {
+ scriptHash := []byte{
+ 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62,
+ 0x21, 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66,
+ 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c, 0x6c, 0xe2,
+ 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}
+ return NewAddressWitnessScriptHash(scriptHash, &consensus.TestNetParams)
+ },
+ net: &consensus.TestNetParams,
+ },
+ // Unsupported witness versions (version 0 only supported at this point)
+ {
+ name: "segwit mainnet witness v1",
+ addr: "bm1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit mainnet witness v16",
+ addr: "BM1SW50QA3JX3S",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit mainnet witness v2",
+ addr: "bm1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ // Invalid segwit addresses
+ {
+ name: "segwit invalid hrp",
+ addr: "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
+ valid: false,
+ net: &consensus.TestNetParams,
+ },
+ {
+ name: "segwit invalid checksum",
+ addr: "bm1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit invalid witness version",
+ addr: "BM13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length",
+ addr: "bm1rw5uspcuh",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length",
+ addr: "bm10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit invalid program length for witness version 0 (per BIP141)",
+ addr: "BM1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
+ valid: false,
+ net: &consensus.MainNetParams,
+ },
+ {
+ name: "segwit mixed case",
+ addr: "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
+ valid: false,
+ net: &consensus.TestNetParams,
+ },
+ {
+ name: "segwit zero padding of more than 4 bits",
+ addr: "tm1pw508d6qejxtdg4y5r3zarqfsj6c3",
+ valid: false,
+ net: &consensus.TestNetParams,
+ },
+ {
+ name: "segwit non-zero padding in 8-to-5 conversion",
+ addr: "tm1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
+ valid: false,
+ net: &consensus.TestNetParams,
+ },
+ }
+
+ for _, test := range tests {
+ // Decode addr and compare error against valid.
+ decoded, err := 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 {
+ addr := test.addr
+
+ // For Segwit addresses the string representation
+ // will always be lower case, so in that case we
+ // convert the original to lower case first.
+ if strings.Contains(test.name, "segwit") {
+ addr = strings.ToLower(addr)
+ }
+
+ if 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 decoded.(type) {
+
+ case *AddressWitnessPubKeyHash:
+ saddr = tstAddressSegwitSAddr(encoded)
+ case *AddressWitnessScriptHash:
+ saddr = tstAddressSegwitSAddr(encoded)
+ }
+
+ // 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 *AddressWitnessPubKeyHash:
+ if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+ t.Errorf("%v: hrps do not match:\n%x != \n%x",
+ test.name, test.net.Bech32HRPSegwit, hrp)
+ return
+ }
+
+ expVer := test.result.(*AddressWitnessPubKeyHash).WitnessVersion()
+ if v := a.WitnessVersion(); v != expVer {
+ t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+ test.name, expVer, v)
+ return
+ }
+
+ if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+ t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+ test.name, saddr, p)
+ return
+ }
+
+ case *AddressWitnessScriptHash:
+ if hrp := a.Hrp(); test.net.Bech32HRPSegwit != hrp {
+ t.Errorf("%v: hrps do not match:\n%x != \n%x",
+ test.name, test.net.Bech32HRPSegwit, hrp)
+ return
+ }
+
+ expVer := test.result.(*AddressWitnessScriptHash).WitnessVersion()
+ if v := a.WitnessVersion(); v != expVer {
+ t.Errorf("%v: witness versions do not match:\n%x != \n%x",
+ test.name, expVer, v)
+ return
+ }
+
+ if p := a.WitnessProgram(); !bytes.Equal(saddr, p) {
+ t.Errorf("%v: witness programs do not match:\n%x != \n%x",
+ test.name, saddr, p)
+ 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
+ }
+ }
+}
+
+
+// TstAddressWitnessPubKeyHash creates an AddressWitnessPubKeyHash, initiating
+// the fields as given.
+func tstAddressWitnessPubKeyHash(version byte, program [20]byte,
+ hrp string) *AddressWitnessPubKeyHash {
+
+ return &AddressWitnessPubKeyHash{
+ hrp: hrp,
+ witnessVersion: version,
+ witnessProgram: program,
+ }
+}
+
+// TstAddressWitnessScriptHash creates an AddressWitnessScriptHash, initiating
+// the fields as given.
+func tstAddressWitnessScriptHash(version byte, program [32]byte,
+ hrp string) *AddressWitnessScriptHash {
+
+ return &AddressWitnessScriptHash{
+ hrp: hrp,
+ witnessVersion: version,
+ witnessProgram: program,
+ }
+}
+
+// TstAddressSegwitSAddr returns the expected witness program bytes for
+// bech32 encoded P2WPKH and P2WSH bitcoin addresses.
+func tstAddressSegwitSAddr(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
+}
+++ /dev/null
-// Package bech32 reference implementation for Bech32 and segwit addresses.
-// Copyright (c) 2017 Takatoshi Nakagawa
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-package common
-
-import (
- "bytes"
- "fmt"
- "strings"
-)
-
-var charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
-
-var generator = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
-
-func polymod(values []int) int {
- chk := 1
- for _, v := range values {
- top := chk >> 25
- chk = (chk&0x1ffffff)<<5 ^ v
- for i := 0; i < 5; i++ {
- if (top>>uint(i))&1 == 1 {
- chk ^= generator[i]
- }
- }
- }
- return chk
-}
-
-func hrpExpand(hrp string) []int {
- ret := []int{}
- for _, c := range hrp {
- ret = append(ret, int(c>>5))
- }
- ret = append(ret, 0)
- for _, c := range hrp {
- ret = append(ret, int(c&31))
- }
- return ret
-}
-
-func verifyChecksum(hrp string, data []int) bool {
- return polymod(append(hrpExpand(hrp), data...)) == 1
-}
-
-func createChecksum(hrp string, data []int) []int {
- values := append(append(hrpExpand(hrp), data...), []int{0, 0, 0, 0, 0, 0}...)
- mod := polymod(values) ^ 1
- ret := make([]int, 6)
- for p := 0; p < len(ret); p++ {
- ret[p] = (mod >> uint(5*(5-p))) & 31
- }
- return ret
-}
-
-// Encode encodes hrp(human-readable part) and data(32bit data array), returns Bech32 / or error
-// if hrp is uppercase, return uppercase Bech32
-func Encode(hrp string, data []int) (string, error) {
- if (len(hrp) + len(data) + 7) > 90 {
- return "", fmt.Errorf("too long : hrp length=%d, data length=%d", len(hrp), len(data))
- }
- if len(hrp) < 1 {
- return "", fmt.Errorf("invalid hrp : hrp=%v", hrp)
- }
- for p, c := range hrp {
- if c < 33 || c > 126 {
- return "", fmt.Errorf("invalid character human-readable part : hrp[%d]=%d", p, c)
- }
- }
- if strings.ToUpper(hrp) != hrp && strings.ToLower(hrp) != hrp {
- return "", fmt.Errorf("mix case : hrp=%v", hrp)
- }
- lower := strings.ToLower(hrp) == hrp
- hrp = strings.ToLower(hrp)
- combined := append(data, createChecksum(hrp, data)...)
- var ret bytes.Buffer
- ret.WriteString(hrp)
- ret.WriteString("1")
- for idx, p := range combined {
- if p < 0 || p >= len(charset) {
- return "", fmt.Errorf("invalid data : data[%d]=%d", idx, p)
- }
- ret.WriteByte(charset[p])
- }
- if lower {
- return ret.String(), nil
- }
- return strings.ToUpper(ret.String()), nil
-}
-
-// Decode decodes bechString(Bech32) returns hrp(human-readable part) and data(32bit data array) / or error
-func Decode(bechString string) (string, []int, error) {
- if len(bechString) > 90 {
- return "", nil, fmt.Errorf("too long : len=%d", len(bechString))
- }
- if strings.ToLower(bechString) != bechString && strings.ToUpper(bechString) != bechString {
- return "", nil, fmt.Errorf("mixed case")
- }
- bechString = strings.ToLower(bechString)
- pos := strings.LastIndex(bechString, "1")
- if pos < 1 || pos+7 > len(bechString) {
- return "", nil, fmt.Errorf("separator '1' at invalid position : pos=%d , len=%d", pos, len(bechString))
- }
- hrp := bechString[0:pos]
- for p, c := range hrp {
- if c < 33 || c > 126 {
- return "", nil, fmt.Errorf("invalid character human-readable part : bechString[%d]=%d", p, c)
- }
- }
- data := []int{}
- for p := pos + 1; p < len(bechString); p++ {
- d := strings.Index(charset, fmt.Sprintf("%c", bechString[p]))
- if d == -1 {
- return "", nil, fmt.Errorf("invalid character data part : bechString[%d]=%d", p, bechString[p])
- }
- data = append(data, d)
- }
- if !verifyChecksum(hrp, data) {
- return "", nil, fmt.Errorf("invalid checksum")
- }
- return hrp, data[:len(data)-6], nil
-}
-
-func convertbits(data []int, frombits, tobits uint, pad bool) ([]int, error) {
- acc := 0
- bits := uint(0)
- ret := []int{}
- maxv := (1 << tobits) - 1
- for idx, value := range data {
- if value < 0 || (value>>frombits) != 0 {
- return nil, fmt.Errorf("invalid data range : data[%d]=%d (frombits=%d)", idx, value, frombits)
- }
- acc = (acc << frombits) | value
- bits += frombits
- for bits >= tobits {
- bits -= tobits
- ret = append(ret, (acc>>bits)&maxv)
- }
- }
- if pad {
- if bits > 0 {
- ret = append(ret, (acc<<(tobits-bits))&maxv)
- }
- } else if bits >= frombits {
- return nil, fmt.Errorf("illegal zero padding")
- } else if ((acc << (tobits - bits)) & maxv) != 0 {
- return nil, fmt.Errorf("non-zero padding")
- }
- return ret, nil
-}
-
-// AddressDecode decodes hrp(human-readable part) Address(string), returns version(int) and data(bytes array) / or error
-func AddressDecode(hrp, addr string) (int, []int, error) {
- dechrp, data, err := Decode(addr)
- if err != nil {
- return -1, nil, err
- }
- if dechrp != hrp {
- return -1, nil, fmt.Errorf("invalid human-readable part : %s != %s", hrp, dechrp)
- }
- if len(data) < 1 {
- return -1, nil, fmt.Errorf("invalid decode data length : %d", len(data))
- }
- if data[0] > 16 {
- return -1, nil, fmt.Errorf("invalid address version : %d", data[0])
- }
- res, err := convertbits(data[1:], 5, 8, false)
- if err != nil {
- return -1, nil, err
- }
- if len(res) < 2 || len(res) > 40 {
- return -1, nil, fmt.Errorf("invalid convertbits length : %d", len(res))
- }
- if data[0] == 0 && len(res) != 20 && len(res) != 32 {
- return -1, nil, fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(res))
- }
- return data[0], res, nil
-}
-
-// AddressEncode encodes hrp(human-readable part) , version(int) and data(bytes array), returns Address / or error
-func AddressEncode(hrp string, version int, pubkey []int) (string, error) {
- if version < 0 || version > 16 {
- return "", fmt.Errorf("invalid version : %d", version)
- }
- if len(pubkey) < 2 || len(pubkey) > 40 {
- return "", fmt.Errorf("invalid pubkey hash length : %d", len(pubkey))
- }
- if version == 0 && len(pubkey) != 20 && len(pubkey) != 32 {
- return "", fmt.Errorf("invalid program length for witness version 0 (per BIP141) : %d", len(pubkey))
- }
- data, err := convertbits(pubkey, 8, 5, true)
- if err != nil {
- return "", err
- }
- ret, err := Encode(hrp, append([]int{version}, data...))
- if err != nil {
- return "", err
- }
- return ret, nil
-}
--- /dev/null
+bech32
+==========
+
+[![Build Status](http://img.shields.io/travis/btcsuite/btcutil.svg)](https://travis-ci.org/btcsuite/btcutil)
+[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
+[![GoDoc](https://godoc.org/github.com/btcsuite/btcutil/bech32?status.png)](http://godoc.org/github.com/btcsuite/btcutil/bech32)
+
+Package bech32 provides a Go implementation of the bech32 format specified in
+[BIP 173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
+
+Test vectors from BIP 173 are added to ensure compatibility with the BIP.
+
+## Installation and Updating
+
+```bash
+$ go get -u github.com/btcsuite/btcutil/bech32
+```
+
+## Examples
+
+* [Bech32 decode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-Bech32Decode)
+ Demonstrates how to decode a bech32 encoded string.
+* [Bech32 encode Example](http://godoc.org/github.com/btcsuite/btcutil/bech32#example-BechEncode)
+ Demonstrates how to encode data into a bech32 string.
+
+## License
+
+Package bech32 is licensed under the [copyfree](http://copyfree.org) ISC
+License.
--- /dev/null
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32
+
+import (
+ "fmt"
+ "strings"
+)
+
+const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+
+var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
+
+// Decode decodes a bech32 encoded string, returning the human-readable
+// part and the data part excluding the checksum.
+func Decode(bech string) (string, []byte, error) {
+ // The maximum allowed length for a bech32 string is 90. It must also
+ // be at least 8 characters, since it needs a non-empty HRP, a
+ // separator, and a 6 character checksum.
+ if len(bech) < 8 || len(bech) > 90 {
+ return "", nil, fmt.Errorf("invalid bech32 string length %d",
+ len(bech))
+ }
+ // Only ASCII characters between 33 and 126 are allowed.
+ for i := 0; i < len(bech); i++ {
+ if bech[i] < 33 || bech[i] > 126 {
+ return "", nil, fmt.Errorf("invalid character in "+
+ "string: '%c'", bech[i])
+ }
+ }
+
+ // The characters must be either all lowercase or all uppercase.
+ lower := strings.ToLower(bech)
+ upper := strings.ToUpper(bech)
+ if bech != lower && bech != upper {
+ return "", nil, fmt.Errorf("string not all lowercase or all " +
+ "uppercase")
+ }
+
+ // We'll work with the lowercase string from now on.
+ bech = lower
+
+ // The string is invalid if the last '1' is non-existent, it is the
+ // first character of the string (no human-readable part) or one of the
+ // last 6 characters of the string (since checksum cannot contain '1'),
+ // or if the string is more than 90 characters in total.
+ one := strings.LastIndexByte(bech, '1')
+ if one < 1 || one+7 > len(bech) {
+ return "", nil, fmt.Errorf("invalid index of 1")
+ }
+
+ // The human-readable part is everything before the last '1'.
+ hrp := bech[:one]
+ data := bech[one+1:]
+
+ // Each character corresponds to the byte with value of the index in
+ // 'charset'.
+ decoded, err := toBytes(data)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed converting data to bytes: "+
+ "%v", err)
+ }
+
+ if !bech32VerifyChecksum(hrp, decoded) {
+ moreInfo := ""
+ checksum := bech[len(bech)-6:]
+ expected, err := toChars(bech32Checksum(hrp,
+ decoded[:len(decoded)-6]))
+ if err == nil {
+ moreInfo = fmt.Sprintf("Expected %v, got %v.",
+ expected, checksum)
+ }
+ return "", nil, fmt.Errorf("checksum failed. " + moreInfo)
+ }
+
+ // We exclude the last 6 bytes, which is the checksum.
+ return hrp, decoded[:len(decoded)-6], nil
+}
+
+// Encode encodes a byte slice into a bech32 string with the
+// human-readable part hrb. Note that the bytes must each encode 5 bits
+// (base32).
+func Encode(hrp string, data []byte) (string, error) {
+ // Calculate the checksum of the data and append it at the end.
+ checksum := bech32Checksum(hrp, data)
+ combined := append(data, checksum...)
+
+ // The resulting bech32 string is the concatenation of the hrp, the
+ // separator 1, data and checksum. Everything after the separator is
+ // represented using the specified charset.
+ dataChars, err := toChars(combined)
+ if err != nil {
+ return "", fmt.Errorf("unable to convert data bytes to chars: "+
+ "%v", err)
+ }
+ return hrp + "1" + dataChars, nil
+}
+
+// toBytes converts each character in the string 'chars' to the value of the
+// index of the correspoding character in 'charset'.
+func toBytes(chars string) ([]byte, error) {
+ decoded := make([]byte, 0, len(chars))
+ for i := 0; i < len(chars); i++ {
+ index := strings.IndexByte(charset, chars[i])
+ if index < 0 {
+ return nil, fmt.Errorf("invalid character not part of "+
+ "charset: %v", chars[i])
+ }
+ decoded = append(decoded, byte(index))
+ }
+ return decoded, nil
+}
+
+// toChars converts the byte slice 'data' to a string where each byte in 'data'
+// encodes the index of a character in 'charset'.
+func toChars(data []byte) (string, error) {
+ result := make([]byte, 0, len(data))
+ for _, b := range data {
+ if int(b) >= len(charset) {
+ return "", fmt.Errorf("invalid data byte: %v", b)
+ }
+ result = append(result, charset[b])
+ }
+ return string(result), nil
+}
+
+// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
+// to a byte slice where each byte is encoding toBits bits.
+func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ([]byte, error) {
+ if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 {
+ return nil, fmt.Errorf("only bit groups between 1 and 8 allowed")
+ }
+
+ // The final bytes, each byte encoding toBits bits.
+ var regrouped []byte
+
+ // Keep track of the next byte we create and how many bits we have
+ //Â added to it out of the toBits goal.
+ nextByte := byte(0)
+ filledBits := uint8(0)
+
+ for _, b := range data {
+
+ // Discard unused bits.
+ b = b << (8 - fromBits)
+
+ // How many bits remaining to extract from the input data.
+ remFromBits := fromBits
+ for remFromBits > 0 {
+ // How many bits remaining to be added to the next byte.
+ remToBits := toBits - filledBits
+
+ // The number of bytes to next extract is the minimum of
+ // remFromBits and remToBits.
+ toExtract := remFromBits
+ if remToBits < toExtract {
+ toExtract = remToBits
+ }
+
+ // Add the next bits to nextByte, shifting the already
+ // added bits to the left.
+ nextByte = (nextByte << toExtract) | (b >> (8 - toExtract))
+
+ // Discard the bits we just extracted and get ready for
+ // next iteration.
+ b = b << toExtract
+ remFromBits -= toExtract
+ filledBits += toExtract
+
+ // If the nextByte is completely filled, we add it to
+ //Â our regrouped bytes and start on the next byte.
+ if filledBits == toBits {
+ regrouped = append(regrouped, nextByte)
+ filledBits = 0
+ nextByte = 0
+ }
+ }
+ }
+
+ // We pad any unfinished group if specified.
+ if pad && filledBits > 0 {
+ nextByte = nextByte << (toBits - filledBits)
+ regrouped = append(regrouped, nextByte)
+ filledBits = 0
+ nextByte = 0
+ }
+
+ // Any incomplete group must be <= 4 bits, and all zeroes.
+ if filledBits > 0 && (filledBits > 4 || nextByte != 0) {
+ return nil, fmt.Errorf("invalid incomplete group")
+ }
+
+ return regrouped, nil
+}
+
+// For more details on the checksum calculation, please refer to BIP 173.
+func bech32Checksum(hrp string, data []byte) []byte {
+ // Convert the bytes to list of integers, as this is needed for the
+ // checksum calculation.
+ integers := make([]int, len(data))
+ for i, b := range data {
+ integers[i] = int(b)
+ }
+ values := append(bech32HrpExpand(hrp), integers...)
+ values = append(values, []int{0, 0, 0, 0, 0, 0}...)
+ polymod := bech32Polymod(values) ^ 1
+ var res []byte
+ for i := 0; i < 6; i++ {
+ res = append(res, byte((polymod>>uint(5*(5-i)))&31))
+ }
+ return res
+}
+
+// For more details on the polymod calculation, please refer to BIP 173.
+func bech32Polymod(values []int) int {
+ chk := 1
+ for _, v := range values {
+ b := chk >> 25
+ chk = (chk&0x1ffffff)<<5 ^ v
+ for i := 0; i < 5; i++ {
+ if (b>>uint(i))&1 == 1 {
+ chk ^= gen[i]
+ }
+ }
+ }
+ return chk
+}
+
+// For more details on HRP expansion, please refer to BIP 173.
+func bech32HrpExpand(hrp string) []int {
+ v := make([]int, 0, len(hrp)*2+1)
+ for i := 0; i < len(hrp); i++ {
+ v = append(v, int(hrp[i]>>5))
+ }
+ v = append(v, 0)
+ for i := 0; i < len(hrp); i++ {
+ v = append(v, int(hrp[i]&31))
+ }
+ return v
+}
+
+// For more details on the checksum verification, please refer to BIP 173.
+func bech32VerifyChecksum(hrp string, data []byte) bool {
+ integers := make([]int, len(data))
+ for i, b := range data {
+ integers[i] = int(b)
+ }
+ concat := append(bech32HrpExpand(hrp), integers...)
+ return bech32Polymod(concat) == 1
+}
--- /dev/null
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32_test
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/btcsuite/btcutil/bech32"
+)
+
+func TestBech32(t *testing.T) {
+ tests := []struct {
+ str string
+ valid bool
+ }{
+ {"A12UEL5L", true},
+ {"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", true},
+ {"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", true},
+ {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", true},
+ {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", true},
+ {"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", false}, // invalid checksum
+ {"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", false}, // invalid character (space) in hrp
+ {"spl" + string(127) + "t1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false}, // invalid character (DEL) in hrp
+ {"split1cheo2y9e2w", false}, // invalid character (o) in data part
+ {"split1a2y9w", false}, // too short data part
+ {"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", false}, // empty hrp
+ {"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", false}, // too long
+ }
+
+ for _, test := range tests {
+ str := test.str
+ hrp, decoded, err := bech32.Decode(str)
+ if !test.valid {
+ // Invalid string decoding should result in error.
+ if err == nil {
+ t.Error("expected decoding to fail for "+
+ "invalid string %v", test.str)
+ }
+ continue
+ }
+
+ // Valid string decoding should result in no error.
+ if err != nil {
+ t.Errorf("expected string to be valid bech32: %v", err)
+ }
+
+ // Check that it encodes to the same string
+ encoded, err := bech32.Encode(hrp, decoded)
+ if err != nil {
+ t.Errorf("encoding failed: %v", err)
+ }
+
+ if encoded != strings.ToLower(str) {
+ t.Errorf("expected data to encode to %v, but got %v",
+ str, encoded)
+ }
+
+ // Flip a bit in the string an make sure it is caught.
+ pos := strings.LastIndexAny(str, "1")
+ flipped := str[:pos+1] + string((str[pos+1] ^ 1)) + str[pos+2:]
+ _, _, err = bech32.Decode(flipped)
+ if err == nil {
+ t.Error("expected decoding to fail")
+ }
+ }
+}
--- /dev/null
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+/*
+Package bech32 provides a Go implementation of the bech32 format specified in
+BIP 173.
+
+Bech32 strings consist of a human-readable part (hrp), followed by the
+separator 1, then a checksummed data part encoded using the 32 characters
+"qpzry9x8gf2tvdw0s3jn54khce6mua7l".
+
+More info: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+*/
+package bech32
--- /dev/null
+// Copyright (c) 2017 The btcsuite developers
+// Use of this source code is governed by an ISC
+// license that can be found in the LICENSE file.
+
+package bech32_test
+
+import (
+ "encoding/hex"
+ "fmt"
+
+ "github.com/btcsuite/btcutil/bech32"
+)
+
+// This example demonstrates how to decode a bech32 encoded string.
+func ExampleDecode() {
+ encoded := "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"
+ hrp, decoded, err := bech32.Decode(encoded)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+
+ // Show the decoded data.
+ fmt.Println("Decoded human-readable part:", hrp)
+ fmt.Println("Decoded Data:", hex.EncodeToString(decoded))
+
+ // Output:
+ // Decoded human-readable part: bc
+ // Decoded Data: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
+}
+
+// This example demonstrates how to encode data into a bech32 string.
+func ExampleEncode() {
+ data := []byte("Test data")
+ // Convert test data to base32:
+ conv, err := bech32.ConvertBits(data, 8, 5, true)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+ encoded, err := bech32.Encode("customHrp!11111q", conv)
+ if err != nil {
+ fmt.Println("Error:", err)
+ }
+
+ // Show the encoded data.
+ fmt.Println("Encoded Data:", encoded)
+
+ // Output:
+ // Encoded Data: customHrp!11111q123jhxapqv3shgcgumastr
+}
+++ /dev/null
-// Copyright (c) 2017 Takatoshi Nakagawa
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-package common
-
-import (
- "reflect"
- "strings"
- "testing"
-)
-
-func ScriptPubkey(version int, program []int) []int {
- if version != 0 {
- version += 0x50
- }
- return append(append([]int{version}, len(program)), program...)
-}
-
-var validChecksum = []string{
- "A12UEL5L",
- "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
- "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
- "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
- "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
-}
-
-type item struct {
- address string
- scriptpubkey []int
-}
-
-var validAddress = []item{
- item{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
- []int{
- 0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
- 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
- },
- },
- item{"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
- []int{
- 0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
- 0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
- 0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
- 0x62,
- },
- },
- item{"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
- []int{
- 0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
- 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
- 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
- 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
- },
- },
- item{"BC1SW50QA3JX3S",
- []int{
- 0x60, 0x02, 0x75, 0x1e,
- },
- },
- item{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
- []int{
- 0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
- 0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23,
- },
- },
- item{"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
- []int{
- 0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
- 0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
- 0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
- 0x33,
- },
- },
-}
-
-var invalidAddress = []string{
- "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
- "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
- "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
- "bc1rw5uspcuh",
- "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
- "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
- "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
- "tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
- "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
-}
-
-func TestValidChecksum(t *testing.T) {
- for _, test := range validChecksum {
- hrp, data, err := Decode(test)
- if err != nil {
- t.Errorf("Valid checksum for %s : FAIL / error %+v\n", test, err)
- } else {
- t.Logf("Valid checksum for %s : ok / hrp : %+v , data : %+v\n", test, hrp, data)
- }
- }
-}
-
-func TestValidAddress(t *testing.T) {
- for _, test := range validAddress {
- hrp := "bc"
- version, program, err := AddressDecode(hrp, test.address)
- if err != nil {
- hrp = "tb"
- version, program, err = AddressDecode(hrp, test.address)
- }
- ok := err == nil
- if ok {
- output := ScriptPubkey(version, program)
- ok = reflect.DeepEqual(output, test.scriptpubkey)
- }
- if ok {
- recreate, err := AddressEncode(hrp, version, program)
- if err == nil {
- ok = recreate == strings.ToLower(test.address)
- }
- }
- if ok {
- t.Logf("Valid address %v : ok\n", test.address)
- } else {
- t.Errorf("Valid address %v : FAIL\n", test.address)
- }
- }
-}
-
-func TestInvalidAddress(t *testing.T) {
- for _, test := range invalidAddress {
- _, _, bcErr := AddressDecode("bc", test)
- t.Logf("bc error:%v\n", bcErr)
- _, _, tbErr := AddressDecode("tb", test)
- t.Logf("tb error:%v\n", tbErr)
- if bcErr != nil && tbErr != nil {
- t.Logf("Invalid address %v : ok\n", test)
- } else {
- t.Errorf("Invalid address %v : FAIL\n", test)
- }
- }
-}
-
-// add coverage tests
-
-func TestCoverage(t *testing.T) {
- var err error
- var bech32String string
- var hrp string
- var data []int
-
- // AddressEncode
- bech32String, err = AddressEncode("bc", 1, []int{0, 1})
- if err != nil {
- t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
- } else {
- t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
- }
- data = make([]int, 40)
- bech32String, err = AddressEncode("bc", 16, data)
- if err != nil {
- t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
- } else {
- t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
- }
- data = make([]int, 20)
- bech32String, err = AddressEncode("bc", 0, data)
- if err != nil {
- t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
- } else {
- t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
- }
- data = make([]int, 32)
- bech32String, err = AddressEncode("bc", 0, data)
- if err != nil {
- t.Errorf("Coverage AddressEncode normal case : FAIL / error : %+v\n", err)
- } else {
- t.Log("Coverage AddressEncode normal case : ok / bech32String :", bech32String)
- }
- data = make([]int, 1)
- _, err = AddressEncode("bc", 1, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid program length error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid program length error case : ok / error :", err)
- }
- data = make([]int, 41)
- _, err = AddressEncode("bc", 1, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid program length error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid program length error case : ok / error :", err)
- }
- data = make([]int, 26)
- _, err = AddressEncode("bc", 0, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid program length for witness version 0 (per BIP141) error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid program length for witness version 0 (per BIP141) error case : ok / error :", err)
- }
- data = make([]int, 20)
- _, err = AddressEncode("Bc", 0, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode Encode error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode Encode error case : ok / error :", err)
- }
- _, err = AddressEncode("bc", 1, []int{-1, 0})
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid data range error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid data range error case : ok / error :", err)
- }
- _, err = AddressEncode("bc", -1, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid witness version error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid witness version error case : ok / error :", err)
- }
- _, err = AddressEncode("bc", 17, data)
- if err == nil {
- t.Errorf("Coverage AddressEncode invalid witness version error case : FAIL")
- } else {
- t.Log("Coverage AddressEncode invalid witness version error case : ok / error :", err)
- }
-
- // SegwitAddrDecode
- _, _, err = AddressDecode("a", "A12UEL5L")
- if err == nil {
- t.Errorf("Coverage SegwitAddrDecode invalid decode data length error case : FAIL")
- } else {
- t.Log("Coverage SegwitAddrDecode invalid decode data length error case : ok / error :", err)
- }
-
- // Decode
- _, _, err = Decode("!~1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc356v3")
- if err != nil {
- t.Errorf("Coverage Decode normal case : FAIL / error :%v", err)
- } else {
- t.Log("Coverage Decode normal case : ok")
- }
- _, _, err = Decode("a1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq")
- if err == nil {
- t.Errorf("Coverage Decode too long error case : FAIL")
- } else {
- t.Log("Coverage Decode too long error case : ok / error :", err)
- }
- _, _, err = Decode("1")
- if err == nil {
- t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL")
- } else {
- t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err)
- }
- _, _, err = Decode("a1qqqqq")
- if err == nil {
- t.Errorf("Coverage Decode separator '1' at invalid position error case : FAIL")
- } else {
- t.Log("Coverage Decode separator '1' at invalid position error case : ok / error :", err)
- }
- _, _, err = Decode("a" + string(32) + "1qqqqqq")
- if err == nil {
- t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL")
- } else {
- t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err)
- }
- _, _, err = Decode("a" + string(127) + "1qqqqqq")
- if err == nil {
- t.Errorf("Coverage Decode invalid character human-readable part error case : FAIL")
- } else {
- t.Log("Coverage Decode invalid character human-readable part error case : ok / error :", err)
- }
- _, _, err = Decode("a1qqqqqb")
- if err == nil {
- t.Errorf("Coverage Decode invalid character data part error case : FAIL")
- } else {
- t.Log("Coverage Decode invalid character data part erroer case : ok / error :", err)
- }
-
- // Encode
- hrp = "bc"
- data = []int{}
- bech32String, err = Encode(hrp, data)
- if err != nil || bech32String != strings.ToLower(bech32String) {
- t.Errorf("Coverage Encode lower case : FAIL / bech32String : %v , error : %v", bech32String, err)
- } else {
- t.Log("Coverage Encode lower case : ok / bech32String : ", bech32String)
- }
- hrp = "BC"
- bech32String, err = Encode(hrp, data)
- if err != nil || bech32String != strings.ToUpper(bech32String) {
- t.Errorf("Coverage Encode upper case : FAIL / bech32String : %v , error : %v", bech32String, err)
- } else {
- t.Log("Coverage Encode upper case : ok / bech32String : ", bech32String)
- }
- hrp = "bc"
- data = make([]int, 90-7-len(hrp)+1)
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode too long error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode too long error case : ok / error : ", err)
- }
- hrp = ""
- data = make([]int, 90-7-len(hrp))
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode invalid hrp error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode invalid hrp error case : ok / error : ", err)
- }
- hrp = "Bc"
- data = make([]int, 90-7-len(hrp))
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode mix case error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode mix case error case : ok / error : ", err)
- }
- hrp = string(33) + string(126)
- data = make([]int, 90-7-len(hrp))
- bech32String, err = Encode(hrp, data)
- if err != nil {
- t.Errorf("Coverage Encode normal case : FAIL / error : %v", err)
- } else {
- t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String)
- }
- hrp = string(32) + "c"
- data = make([]int, 90-7-len(hrp))
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err)
- }
- hrp = "b" + string(127)
- data = make([]int, 90-7-len(hrp))
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode invalid character human-readable part error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode invalid character human-readable part error case : ok / error : ", err)
- }
- hrp = "bc"
- data = []int{0, 31}
- bech32String, err = Encode(hrp, data)
- if err != nil {
- t.Errorf("Coverage Encode normal case : FAIL / error : %v", err)
- } else {
- t.Log("Coverage Encode normal case : ok / bech32String : ", bech32String)
- }
- hrp = "bc"
- data = []int{-1}
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode invalid data error case : ok / error : ", err)
- }
- hrp = "bc"
- data = []int{32}
- bech32String, err = Encode(hrp, data)
- if err == nil {
- t.Errorf("Coverage Encode invalid data error case : FAIL / bech32String : %v", bech32String)
- } else {
- t.Log("Coverage Encode invalid data error case : ok / error : ", err)
- }
-}
}
/////////// Address
+/*
func BytesToAddress(b []byte) Address {
var a Address
a.SetBytes(b)
return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4])
}
+*/
\ No newline at end of file
type Config struct {
// Top level options use an anonymous struct
BaseConfig `mapstructure:",squash"`
-
+ ChainConfig
// Options for services
RPC *RPCConfig `mapstructure:"rpc"`
P2P *P2PConfig `mapstructure:"p2p"`
// This should be set in viper so it can unmarshal into this struct
RootDir string `mapstructure:"home"`
- // The ID of the chain to join (should be signed with every transaction and vote)
- ChainID string `mapstructure:"chain_id"`
-
// A JSON file containing the initial validator set and other meta data
Genesis string `mapstructure:"genesis_file"`
return fmt.Sprintf("state:info,*:%s", DefaultLogLevel())
}
+
+//-----------------------------------------------------------------------------
+// ChainConfig
+
+type ChainConfig struct {
+ // The ID of the chain to join (should be signed with every transaction and vote)
+ ChainID string `mapstructure:"chain_id"`
+ // Human-readable part for Bech32 encoded segwit addresses, as defined
+ // in BIP 173.
+ Bech32HRPSegwit string `mapstructure:"bech32_hrp"`
+
+}
+
+func DefaultChainConfig() *ChainConfig {
+ return &ChainConfig{
+ ChainID: "bytom-main",
+ Bech32HRPSegwit: "bm"
+ }
+}
+
//-----------------------------------------------------------------------------
// RPCConfig
package consensus
import (
+ "strings"
"github.com/bytom/protocol/bc"
)
func InitBlock() []byte {
return []byte("0301000000000000000000000000000000000000000000000000000000000000000000ece090e7eb2b4078a79ed5c640a026361c4af77a37342e503cc68493229996e11dd9be38b18f5b492159980684155da19e87de0d1b37b35c1a1123770ec1dcc710aabe77607cce00b1c5a181808080802e0107010700ece090e7eb2b000001012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8080ccdee2a69fb314010151000000")
}
+
+
+// IsBech32SegwitPrefix returns whether the prefix is a known prefix for segwit
+// addresses on any default or registered network. This is used when decoding
+// an address string into a specific address type.
+func IsBech32SegwitPrefix(prefix string, params *Params) bool {
+ prefix = strings.ToLower(prefix)
+ if prefix == params.Bech32HRPSegwit+"1" {
+ return true
+ } else {
+ return false
+ }
+}
+
+
+type Params struct {
+ // Name defines a human-readable identifier for the network.
+ Name string
+
+ Bech32HRPSegwit string
+
+}
+
+
+var MainNetParams = Params {
+ Name: "main",
+ Bech32HRPSegwit: "bm",
+}
+
+
+var TestNetParams = Params {
+ Name: "test",
+ Bech32HRPSegwit: "tm",
+}
+