比特币地址
由一串字符和数字组成,类型主要有两种,一个是P2PKH地址,一个是P2SH地址。P2PKH地址其实是通过对160位二进制公钥哈希值进行base58check编码后的信息。
咱们看代码实现,btcd仅仅实现全节点,没有钱包功能,所以没有提供地址的创建的客户端,不过咱们可以大概分析下地址解码过程。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 1func DecodeAddress(addr string, defaultNet *chaincfg.Params) (Address, error) {
2 oneIndex := strings.LastIndexByte(addr, '1')
3 if oneIndex > 1 {
4 prefix := addr[:oneIndex+1]
5 if chaincfg.IsBech32SegwitPrefix(prefix) {
6 witnessVer, witnessProg, err := decodeSegWitAddress(addr)
7 if err != nil {
8 return nil, err
9 }
10
11 // We currently only support P2WPKH and P2WSH, which is
12 // witness version 0.
13 if witnessVer != 0 {
14 return nil, UnsupportedWitnessVerError(witnessVer)
15 }
16
17 // The HRP is everything before the found '1'.
18 hrp := prefix[:len(prefix)-1]
19
20 switch len(witnessProg) {
21 case 20:
22 return newAddressWitnessPubKeyHash(hrp, witnessProg)
23 case 32:
24 return newAddressWitnessScriptHash(hrp, witnessProg)
25 default:
26 return nil, UnsupportedWitnessProgLenError(len(witnessProg))
27 }
28 }
29 }
30
31 // Serialized public keys are either 65 bytes (130 hex chars) if
32 // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed.
33 if len(addr) == 130 || len(addr) == 66 {
34 serializedPubKey, err := hex.DecodeString(addr)
35 if err != nil {
36 return nil, err
37 }
38 return NewAddressPubKey(serializedPubKey, defaultNet)
39 }
40
41 // Switch on decoded length to determine the type.
42 decoded, netID, err := base58.CheckDecode(addr)
43 if err != nil {
44 if err == base58.ErrChecksum {
45 return nil, ErrChecksumMismatch
46 }
47 return nil, errors.New("decoded address is of unknown format")
48 }
49 switch len(decoded) {
50 case ripemd160.Size: // P2PKH or P2SH
51 isP2PKH := chaincfg.IsPubKeyHashAddrID(netID)
52 isP2SH := chaincfg.IsScriptHashAddrID(netID)
53 switch hash160 := decoded; {
54 case isP2PKH && isP2SH:
55 return nil, ErrAddressCollision
56 case isP2PKH:
57 return newAddressPubKeyHash(hash160, netID)
58 case isP2SH:
59 return newAddressScriptHashFromHash(hash160, netID)
60 default:
61 return nil, ErrUnknownAddressType
62 }
63
64 default:
65 return nil, errors.New("decoded address is of unknown size")
66 }
67}
68
1
2 1decoded, netID, err := base58.CheckDecode(addr)
2
对address使用base58解码
1
2 1NewAddressPubKey(serializedPubKey, defaultNet)
2
这个是验证公钥地址
1
2 1return newAddressPubKeyHash(hash160, netID)
2
这个是返回公钥Hash地址,方法里有判断条件len(pkHash) == ripemd160.Size
1
2 1return newAddressScriptHashFromHash(hash160, netID)
2
这个返回脚本Hash地址
Base58编码代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 1// Encode encodes a byte slice to a modified base58 string.
2func Encode(b []byte) string {
3 x := new(big.Int)
4 x.SetBytes(b)
5
6 answer := make([]byte, 0, len(b)*136/100)
7 for x.Cmp(bigZero) > 0 {
8 mod := new(big.Int)
9 x.DivMod(x, bigRadix, mod)
10 answer = append(answer, alphabet[mod.Int64()])
11 }
12
13 // leading zero bytes
14 for _, i := range b {
15 if i != 0 {
16 break
17}
18 answer = append(answer, alphabetIdx0)
19 }
20
21 // reverse
22 alen := len(answer)
23 for i := 0; i < alen/2; i++ {
24 answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
25 }
26
27 return string(answer)
28}
29
其中使用了alphabet字符集,如下:
1
2
3
4
5
6
7 1const (
2 // alphabet is the modified base58 alphabet used by Bitcoin.
3 alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
4
5 alphabetIdx0 = '1'
6)
7
另外,地址还分压缩地址、非压缩地址,常规交易的输入需要包含支付者的公钥,每一个压缩公钥比非压缩公钥占用空间少。
本文作者:architect.bian,欢迎收藏,转载请保留原文地址并保留版权声明!谢谢~
还没完!往下看!!!