-
Notifications
You must be signed in to change notification settings - Fork 126
/
validation.go
139 lines (126 loc) · 3.4 KB
/
validation.go
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package nervos
import (
"encoding/hex"
"errors"
"fmt"
"strings"
"github.com/MixinNetwork/mixin/crypto"
"github.com/MixinNetwork/mixin/util/bech32"
)
var (
NervosChainBase string
NervosChainId crypto.Hash
)
func init() {
NervosChainBase = "d243386e-6d84-42e6-be03-175be17bf275"
NervosChainId = crypto.NewHash([]byte(NervosChainBase))
}
func VerifyAssetKey(assetKey string) error {
if assetKey == NervosChainBase {
return nil
}
return fmt.Errorf("invalid nervos asset key %s", assetKey)
}
func VerifyAddress(address string) error {
if strings.TrimSpace(address) != address {
return fmt.Errorf("invalid nervos address %s", address)
}
prefix, payload, err := DecodeAddress(address)
if err != nil {
return fmt.Errorf("invalid nervos address %s %v", address, err)
}
if prefix != PrefixMainNet {
return fmt.Errorf("invalid nervos address prefix %s", address)
}
if len(payload) <= 1 {
return fmt.Errorf("invalid nervos address payload length %s", address)
}
if payload[1] != CodeHashIndexSingle && payload[1] != CodeHashIndexAnyoneCanPay && payload[1] != 155 && payload[1] != 147 {
return fmt.Errorf("invalid nervos address payload[1] %s", address)
}
ckbAddress, err := EncodeAddress(payload)
if err != nil {
return fmt.Errorf("invalid nervos address encode %s %s", address, err)
}
if address != ckbAddress {
ckbAddress, err = EncodeBech32mAddress(payload)
if err != nil {
return fmt.Errorf("invalid nervos address bech32m %s %s", address, err)
}
if ckbAddress != address {
return fmt.Errorf("invalid nervos address verify %s", address)
}
}
return nil
}
func VerifyTransactionHash(hash string) error {
if len(hash) != 66 {
return fmt.Errorf("invalid nervos transaction hash %s", hash)
}
if !strings.HasPrefix(hash, "0x") {
return fmt.Errorf("invalid nervos transaction hash %s", hash)
}
if strings.ToLower(hash) != hash {
return fmt.Errorf("invalid nervos transaction hash %s", hash)
}
h, err := hex.DecodeString(hash[2:])
if err != nil {
return fmt.Errorf("invalid nervos transaction hash %s %s", hash, err.Error())
}
if len(h) != 32 {
return fmt.Errorf("invalid nervos transaction hash %s", hash)
}
return nil
}
func GenerateAssetId(assetKey string) crypto.Hash {
switch assetKey {
case NervosChainBase:
return NervosChainId
default:
panic(assetKey)
}
}
const (
CodeHashIndexSingle byte = 0
CodeHashIndexAnyoneCanPay byte = 2
PrefixMainNet = "ckb"
)
func EncodeAddress(payload []byte) (string, error) {
data, err := bech32.ConvertBits(payload, 8, 5, true)
if err != nil {
return "", err
}
address, err := bech32.Encode(PrefixMainNet, data)
if err != nil {
return "", err
}
return address, nil
}
func EncodeBech32mAddress(payload []byte) (string, error) {
data, err := bech32.ConvertBits(payload, 8, 5, true)
if err != nil {
return "", err
}
address, err := bech32.EncodeM(PrefixMainNet, data)
if err != nil {
return "", err
}
return address, nil
}
func DecodeAddress(address string) (prefix string, payload []byte, err error) {
prefix, data, err := bech32.DecodeNoLimit(address)
if err != nil {
return "", nil, err
}
if prefix != PrefixMainNet {
return "", nil, err
}
payload, err = bech32.ConvertBits(data, 5, 8, false)
if err != nil {
return "", nil, err
}
if payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x04 {
return "", nil, errors.New("unknown address format type")
}
return prefix, payload, nil
}