比特币地址由一串字符和数字组成,类型主要有两种,一个是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,欢迎收藏,转载请保留原文地址并保留版权声明!谢谢~
还没完!往下看!!!