比特币全节点Go语言实现BTCD之地址编码解析

比特币地址由一串字符和数字组成,类型主要有两种,一个是P2PKH地址,一个是P2SH地址。P2PKH地址其实是通过对160位二进制公钥哈希值进行base58check编码后的信息。

咱们看代码实现,btcd仅仅实现全节点,没有钱包功能,所以没有提供地址的创建的客户端,不过咱们可以大概分析下地址解码过程。

func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
   oneIndex := strings.LastIndexByte(addr, '1')
   if oneIndex > 1 {
      prefix := addr[:oneIndex+1]
      if chaincfg.IsBech32SegwitPrefix(prefix) {
         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, UnsupportedWitnessVerError(witnessVer)
         }

         // 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, UnsupportedWitnessProgLenError(len(witnessProg))
         }
      }
   }

   // Serialized public keys are either 65 bytes (130 hex chars) if
   // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed.
   if len(addr) == 130 || len(addr) == 66 {
      serializedPubKey, err := hex.DecodeString(addr)
      if err != nil {
         return nil, err
      }
      return NewAddressPubKey(serializedPubKey, defaultNet)
   }

   // Switch on decoded length to determine the type.
   decoded, netID, err := base58.CheckDecode(addr)
   if err != nil {
      if err == base58.ErrChecksum {
         return nil, ErrChecksumMismatch
      }
      return nil, errors.New("decoded address is of unknown format")
   }
   switch len(decoded) {
   case ripemd160.Size: // P2PKH or P2SH
      isP2PKH := chaincfg.IsPubKeyHashAddrID(netID)
      isP2SH := chaincfg.IsScriptHashAddrID(netID)
      switch hash160 := decoded; {
      case isP2PKH && isP2SH:
         return nil, ErrAddressCollision
      case isP2PKH:
         return newAddressPubKeyHash(hash160, netID)
      case isP2SH:
         return newAddressScriptHashFromHash(hash160, netID)
      default:
         return nil, ErrUnknownAddressType
      }

   default:
      return nil, errors.New("decoded address is of unknown size")
   }
}

 
 
decoded, netID, err := base58.CheckDecode(addr)

对address使用base58解码

NewAddressPubKey(serializedPubKey, defaultNet)

这个是验证公钥地址

return newAddressPubKeyHash(hash160, netID)

这个是返回公钥Hash地址,方法里有判断条件len(pkHash) == ripemd160.Size

return newAddressScriptHashFromHash(hash160, netID)

这个返回脚本Hash地址


Base58编码代码:

// Encode encodes a byte slice to a modified base58 string.
func Encode(b []byte) string {
   x := new(big.Int)
   x.SetBytes(b)

   answer := make([]byte, 0, len(b)*136/100)
   for x.Cmp(bigZero) > 0 {
      mod := new(big.Int)
      x.DivMod(x, bigRadix, mod)
      answer = append(answer, alphabet[mod.Int64()])
   }

   // leading zero bytes
   for _, i := range b {
      if i != 0 {
         break
      }
      answer = append(answer, alphabetIdx0)
   }

   // reverse
   alen := len(answer)
   for i := 0; i < alen/2; i++ {
      answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
   }

   return string(answer)
}

其中使用了alphabet字符集,如下:

const (
   // alphabet is the modified base58 alphabet used by Bitcoin.
   alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

   alphabetIdx0 = '1'
)


另外,地址还分压缩地址、非压缩地址,常规交易的输入需要包含支付者的公钥,每一个压缩公钥比非压缩公钥占用空间少。




本文作者:architect.bian,欢迎收藏,转载请保留原文地址并保留版权声明!谢谢~
还没完!往下看!!!

猜你喜欢

转载自blog.csdn.net/vohyeah/article/details/80703951