/
types.go
704 lines (625 loc) · 17.7 KB
/
types.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package types 实现了chain基础结构体、接口、常量等的定义
package types
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math"
"strings"
"time"
"unsafe"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
"github.com/assetcloud/chain/common"
"github.com/assetcloud/chain/common/address"
log "github.com/assetcloud/chain/common/log/log15"
// 注册默认的btc地址模式
_ "github.com/assetcloud/chain/system/address/btc"
"github.com/assetcloud/chain/types/jsonpb"
"github.com/golang/protobuf/proto"
// 注册system的crypto 加密算法
_ "github.com/assetcloud/chain/system/crypto/init"
)
var tlog = log.New("module", "types")
// Size1Kshiftlen tx消息大小1k
const Size1Kshiftlen uint = 10
// Message 声明proto.Message
type Message proto.Message
// ExecName 执行器name
func (c *ChainConfig) ExecName(name string) string {
if len(name) > 1 && name[0] == '#' {
return name[1:]
}
if IsParaExecName(name) {
return name
}
if c.IsPara() {
return c.GetTitle() + name
}
return name
}
// GetExecName 根据paraName 获取exec name
func GetExecName(exec, paraName string) string {
if len(exec) > 1 && exec[0] == '#' {
return exec[1:]
}
if IsParaExecName(exec) {
return exec
}
if len(paraName) > 0 {
return paraName + exec
}
return exec
}
// IsAllowExecName 默认的allow 规则->根据 GetRealExecName 来判断
// name 必须大于3 小于 100
func IsAllowExecName(name []byte, execer []byte) bool {
// name长度不能超过系统限制
if len(name) > address.MaxExecNameLength || len(execer) > address.MaxExecNameLength {
return false
}
if len(name) < 3 || len(execer) < 3 {
return false
}
// name中不允许有 "-"
if bytes.Contains(name, slash) || bytes.Contains(name, sharp) {
return false
}
if !bytes.Equal(name, execer) && !bytes.Equal(name, GetRealExecName(execer)) {
return false
}
if bytes.HasPrefix(name, UserKey) {
return true
}
for i := range AllowUserExec {
if bytes.Equal(AllowUserExec[i], name) {
return true
}
}
return false
}
var bytesExec = []byte("exec-")
var commonPrefix = []byte("mavl-")
// GetExecKey 获取执行器key
func GetExecKey(key []byte) (string, bool) {
n := 0
start := 0
end := 0
for i := len(commonPrefix); i < len(key); i++ {
if key[i] == '-' {
n = n + 1
if n == 2 {
start = i + 1
}
if n == 3 {
end = i
break
}
}
}
if start > 0 && end > 0 {
if bytes.Equal(key[start:end+1], bytesExec) {
//find addr
start = end + 1
for k := end; k < len(key); k++ {
if key[k] == ':' { //end+1
end = k
return string(key[start:end]), true
}
}
}
}
return "", false
}
// FindExecer 查找执行器
func FindExecer(key []byte) (execer []byte, err error) {
if !bytes.HasPrefix(key, commonPrefix) {
return nil, ErrMavlKeyNotStartWithMavl
}
for i := len(commonPrefix); i < len(key); i++ {
if key[i] == '-' {
return key[len(commonPrefix):i], nil
}
}
return nil, ErrNoExecerInMavlKey
}
// GetParaExec 获取平行链执行
func (c *ChainConfig) GetParaExec(execer []byte) []byte {
//必须是平行链
if !c.IsPara() {
return execer
}
//必须是相同的平行链
if !strings.HasPrefix(string(execer), c.GetTitle()) {
return execer
}
return execer[len(c.GetTitle()):]
}
// GetParaExecName 获取平行链上的执行器
func GetParaExecName(execer []byte) []byte {
if !bytes.HasPrefix(execer, ParaKey) {
return execer
}
count := 0
for i := 0; i < len(execer); i++ {
if execer[i] == '.' {
count++
}
if count == 3 && i < (len(execer)-1) {
newexec := execer[i+1:]
return newexec
}
}
return execer
}
// GetRealExecName 获取真实的执行器name
func GetRealExecName(execer []byte) []byte {
//平行链执行器,获取真实执行器的规则
execer = GetParaExecName(execer)
//平行链嵌套平行链是不被允许的
if bytes.HasPrefix(execer, ParaKey) {
return execer
}
if bytes.HasPrefix(execer, UserKey) {
//不是user.p. 的情况, 而是user. 的情况
count := 0
index := 0
for i := 0; i < len(execer); i++ {
if execer[i] == '.' {
count++
}
index = i
if count == 2 {
index--
break
}
}
e := execer[len(UserKey) : index+1]
if len(e) > 0 {
return e
}
}
return execer
}
// EncodeWithBuffer encode with input buffer
func EncodeWithBuffer(data proto.Message, buf *proto.Buffer) []byte {
return encodeProto(data, buf)
}
// Encode encode msg
func Encode(data proto.Message) []byte {
return encodeProto(data, nil)
}
// protobuf V2(golang/protobuf 1.4.0+)
// 版本默认Marshal接口不保证序列化结果一致性, 需要主动设置相关标志
// 即使设置了deterministic标志, protobuf官方也不保证后续版本升级以及跨语言的序列化结果一致
// 即该标志只能保证当前版本具备一致性
func encodeProto(data proto.Message, buf *proto.Buffer) []byte {
if buf == nil {
var b [0]byte
buf = proto.NewBuffer(b[:])
}
// 设置确定性编码
buf.SetDeterministic(true)
err := buf.Marshal(data)
if err != nil {
panic(err)
}
return buf.Bytes()
}
// Size 消息大小
func Size(data proto.Message) int {
return proto.Size(data)
}
// Decode 解码
func Decode(data []byte, msg proto.Message) error {
return proto.Unmarshal(data, msg)
}
// JSONToPB JSON格式转换成protobuffer格式
func JSONToPB(data []byte, msg proto.Message) error {
return jsonpb.Unmarshal(bytes.NewReader(data), msg)
}
// JSONToPBUTF8 默认解码utf8的字符串成bytes
func JSONToPBUTF8(data []byte, msg proto.Message) error {
decode := &jsonpb.Unmarshaler{EnableUTF8BytesToString: true}
return decode.Unmarshal(bytes.NewReader(data), msg)
}
// Hash 计算叶子节点的hash
func (leafnode *LeafNode) Hash() []byte {
data := Encode(leafnode)
return common.Sha256(data)
}
var sha256Len = 32
// Hash 计算中间节点的hash
func (innernode *InnerNode) Hash() []byte {
rightHash := innernode.RightHash
leftHash := innernode.LeftHash
hashLen := sha256Len
if len(innernode.RightHash) > hashLen {
innernode.RightHash = innernode.RightHash[len(innernode.RightHash)-hashLen:]
}
if len(innernode.LeftHash) > hashLen {
innernode.LeftHash = innernode.LeftHash[len(innernode.LeftHash)-hashLen:]
}
data := Encode(innernode)
innernode.RightHash = rightHash
innernode.LeftHash = leftHash
return common.Sha256(data)
}
// NewErrReceipt new一个新的Receipt
func NewErrReceipt(err error) *Receipt {
berr := err.Error()
errlog := &ReceiptLog{Ty: TyLogErr, Log: []byte(berr)}
return &Receipt{Ty: ExecErr, KV: nil, Logs: []*ReceiptLog{errlog}}
}
// CheckAmount 检测转账金额
func CheckAmount(amount, coinPrecision int64) bool {
if amount <= 0 || amount >= MaxCoin*coinPrecision {
return false
}
return true
}
// GetEventName 获取时间name通过事件id
func GetEventName(event int) string {
name, ok := eventName[event]
if ok {
return name
}
return "unknow-event"
}
// ConfigPrefix 配置前缀key
var ConfigPrefix = "mavl-config-"
// ConfigKey 原来实现有bug, 但生成的key在状态树里, 不可修改
// mavl-config–{key} key 前面两个-
func ConfigKey(key string) string {
return fmt.Sprintf("%s-%s", ConfigPrefix, key)
}
// ManagePrefix 超级管理员账户配置前缀key
var ManagePrefix = "mavl-"
// ManageKey 超级管理员账户key
func ManageKey(key string) string {
return fmt.Sprintf("%s-%s", ManagePrefix+"manage", key)
}
// ReceiptDataResult 回执数据
type ReceiptDataResult struct {
Ty int32 `json:"ty"`
TyName string `json:"tyname"`
Logs []*ReceiptLogResult `json:"logs"`
}
// ReceiptLogResult 回执log数据
type ReceiptLogResult struct {
Ty int32 `json:"ty"`
TyName string `json:"tyname"`
Log interface{} `json:"log"`
RawLog string `json:"rawlog"`
}
// DecodeReceiptLog 编码回执数据
func (r *ReceiptData) DecodeReceiptLog(execer []byte) (*ReceiptDataResult, error) {
result := &ReceiptDataResult{Ty: r.GetTy()}
switch r.Ty {
case 0:
result.TyName = "ExecErr"
case 1:
result.TyName = "ExecPack"
case 2:
result.TyName = "ExecOk"
default:
return nil, ErrLogType
}
logs := r.GetLogs()
for _, l := range logs {
var lTy string
var logIns interface{}
lLog, err := hex.DecodeString(common.ToHex(l.GetLog())[2:])
if err != nil {
return nil, err
}
logType := LoadLog(execer, int64(l.Ty))
if logType == nil {
//tlog.Error("DecodeReceiptLog:", "Faile to decodeLog with type value logtype", l.Ty)
return nil, ErrLogType
}
logIns, _ = logType.Decode(lLog)
lTy = logType.Name()
result.Logs = append(result.Logs, &ReceiptLogResult{Ty: l.Ty, TyName: lTy, Log: logIns, RawLog: common.ToHex(l.GetLog())})
}
return result, nil
}
// OutputReceiptDetails 输出回执数据详情
func (r *ReceiptData) OutputReceiptDetails(execer []byte, logger log.Logger) {
rds, err := r.DecodeReceiptLog(execer)
if err == nil {
logger.Debug("receipt decode", "receipt data", rds)
for _, rdl := range rds.Logs {
logger.Debug("receipt log", "log", rdl)
}
} else {
logger.Error("decodelogerr", "err", err)
}
}
// IterateRangeByStateHash 迭代查找
func (t *ReplyGetTotalCoins) IterateRangeByStateHash(key, value []byte) bool {
tlog.Debug("ReplyGetTotalCoins.IterateRangeByStateHash", "key", string(key))
var acc Account
err := Decode(value, &acc)
if err != nil {
tlog.Error("ReplyGetTotalCoins.IterateRangeByStateHash", "err", err)
return true
}
//tlog.Info("acc:", "value", acc)
if t.Num >= t.Count {
t.NextKey = key
return true
}
t.Num++
t.Amount += acc.Balance
return false
}
// GetTxTimeInterval 获取交易有效期
func GetTxTimeInterval() time.Duration {
return time.Second * 120
}
// ParaCrossTx 平行跨链交易
type ParaCrossTx interface {
IsParaCrossTx() bool
}
// PBToJSON 消息类型转换
func PBToJSON(r Message) ([]byte, error) {
encode := &jsonpb.Marshaler{EmitDefaults: true}
var buf bytes.Buffer
if err := encode.Marshal(&buf, r); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// PBToJSONUTF8 消息类型转换
func PBToJSONUTF8(r Message) ([]byte, error) {
encode := &jsonpb.Marshaler{EmitDefaults: true, EnableUTF8BytesToString: true}
var buf bytes.Buffer
if err := encode.Marshal(&buf, r); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// MustPBToJSON panic when error
func MustPBToJSON(req Message) []byte {
data, err := PBToJSON(req)
if err != nil {
panic(err)
}
return data
}
// MustDecode 数据是否已经编码
func MustDecode(data []byte, v interface{}) {
if data == nil {
return
}
err := json.Unmarshal(data, v)
if err != nil {
panic(err)
}
}
// AddItem 添加item
func (t *ReplyGetExecBalance) AddItem(execAddr, value []byte) {
var acc Account
err := Decode(value, &acc)
if err != nil {
tlog.Error("ReplyGetExecBalance.AddItem", "err", err)
return
}
tlog.Info("acc:", "value", &acc)
t.Amount += acc.Balance
t.Amount += acc.Frozen
t.AmountActive += acc.Balance
t.AmountFrozen += acc.Frozen
item := &ExecBalanceItem{ExecAddr: execAddr, Frozen: acc.Frozen, Active: acc.Balance}
t.Items = append(t.Items, item)
}
// CloneAccount copy account
func CloneAccount(acc *Account) *Account {
return &Account{
Currency: acc.Currency,
Balance: acc.Balance,
Frozen: acc.Frozen,
Addr: acc.Addr,
}
}
// Clone 克隆
func Clone(data proto.Message) proto.Message {
return proto.Clone(data)
}
// Clone 添加一个浅拷贝函数
func (sig *Signature) Clone() *Signature {
if sig == nil {
return nil
}
return &Signature{
Ty: sig.Ty,
Pubkey: sig.Pubkey,
Signature: sig.Signature,
}
}
// Clone 浅拷贝: BlockDetail
func (b *BlockDetail) Clone() *BlockDetail {
if b == nil {
return nil
}
return &BlockDetail{
Block: b.Block.Clone(),
Receipts: CloneReceipts(b.Receipts),
KV: cloneKVList(b.KV),
PrevStatusHash: b.PrevStatusHash,
}
}
// Clone 浅拷贝ReceiptData
func (r *ReceiptData) Clone() *ReceiptData {
if r == nil {
return nil
}
return &ReceiptData{
Ty: r.Ty,
Logs: cloneReceiptLogs(r.Logs),
}
}
// Clone 浅拷贝 receiptLog
func (r *ReceiptLog) Clone() *ReceiptLog {
if r == nil {
return nil
}
return &ReceiptLog{
Ty: r.Ty,
Log: r.Log,
}
}
// Clone KeyValue
func (kv *KeyValue) Clone() *KeyValue {
if kv == nil {
return nil
}
return &KeyValue{
Key: kv.Key,
Value: kv.Value,
}
}
// Clone Block 浅拷贝(所有的types.Message 进行了拷贝)
func (b *Block) Clone() *Block {
if b == nil {
return nil
}
return &Block{
Version: b.Version,
ParentHash: b.ParentHash,
TxHash: b.TxHash,
StateHash: b.StateHash,
Height: b.Height,
BlockTime: b.BlockTime,
Difficulty: b.Difficulty,
MainHash: b.MainHash,
MainHeight: b.MainHeight,
Signature: b.Signature.Clone(),
Txs: cloneTxs(b.Txs),
}
}
// Clone BlockBody 浅拷贝(所有的types.Message 进行了拷贝)
func (b *BlockBody) Clone() *BlockBody {
if b == nil {
return nil
}
return &BlockBody{
Txs: cloneTxs(b.Txs),
Receipts: CloneReceipts(b.Receipts),
MainHash: b.MainHash,
MainHeight: b.MainHeight,
Hash: b.Hash,
Height: b.Height,
}
}
// CloneReceipts 浅拷贝交易回报
func CloneReceipts(b []*ReceiptData) []*ReceiptData {
if b == nil {
return nil
}
rs := make([]*ReceiptData, len(b))
for i := 0; i < len(b); i++ {
rs[i] = b[i].Clone()
}
return rs
}
// cloneReceiptLogs 浅拷贝 ReceiptLogs
func cloneReceiptLogs(b []*ReceiptLog) []*ReceiptLog {
if b == nil {
return nil
}
rs := make([]*ReceiptLog, len(b))
for i := 0; i < len(b); i++ {
rs[i] = b[i].Clone()
}
return rs
}
// cloneKVList 拷贝kv 列表
func cloneKVList(b []*KeyValue) []*KeyValue {
if b == nil {
return nil
}
kv := make([]*KeyValue, len(b))
for i := 0; i < len(b); i++ {
kv[i] = b[i].Clone()
}
return kv
}
// Bytes2Str 高效字节数组转字符串
// 相比普通直接转化,性能提升35倍,提升程度和转换的byte长度线性相关,且不存在内存开销
// 需要注意b的修改会导致最终string的变更,比较适合临时变量转换,不适合
func Bytes2Str(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}
// Str2Bytes 高效字符串转字节数组
// 相比普通直接转化,性能提升13倍, 提升程度和转换的byte长度线性相关,且不存在内存开销
// 需要注意不能修改转换后的byte数组,本质上是修改了底层string,将会panic
func Str2Bytes(s string) []byte {
x := (*[2]uintptr)(unsafe.Pointer(&s))
h := [3]uintptr{x[0], x[1], x[1]}
return *(*[]byte)(unsafe.Pointer(&h))
}
// Hash 计算hash
func (hashes *ReplyHashes) Hash() []byte {
data := Encode(hashes)
return common.Sha256(data)
}
// FormatAmount2FloatDisplay 将传输、计算的amount值按精度格式化成浮点显示值,支持精度可配置
// strconv.FormatFloat(float64(amount/types.Int1E4)/types.Float1E4, 'f', 4, 64) 的方法在amount很大的时候会丢失精度
// 比如在9001234567812345678时候,float64 最大精度只能在900123456781234的大小,decimal处理可以完整保持精度
// 在coinPrecision支持可配时候,对不同精度统一处理,而不是限定在1e4
// round:是否需要对小数后四位值圆整,以912345678为例,912345678/1e8=9.1235, 非圆整例子:(912345678/1e4)/float(1e4)
func FormatAmount2FloatDisplay(amount, coinPrecision int64, round bool) string {
n := int64(math.Log10(float64(coinPrecision)))
//小数左移n位,0保持不变
d := decimal.NewFromInt(amount).Shift(int32(-n))
//coinPrecision:5~8,
//v=99.12345678 => 99.1234,需要先truncate掉,不然5678会round到前一位也就是99.1235
if n > ShowPrecisionNum {
//有些需要圆整上来的,比如交易费,0.12345678,圆整为0.1235
if round {
return d.StringFixedBank(int32(ShowPrecisionNum))
}
//有些需要直接truncate掉
return d.Truncate(int32(ShowPrecisionNum)).StringFixedBank(int32(ShowPrecisionNum))
}
return d.StringFixedBank(int32(n))
}
// FormatAmount2FixPrecisionDisplay 将传输、计算的amount值按配置精度格式化成浮点显示值,不设缺省精度
func FormatAmount2FixPrecisionDisplay(amount, coinPrecision int64) string {
n := int64(math.Log10(float64(coinPrecision)))
//小数左移n位,0保持不变
d := decimal.NewFromInt(amount).Shift(int32(-n))
return d.StringFixedBank(int32(n))
}
// FormatFloatDisplay2Value 将显示、输入的float amount值按精度格式化成计算值,小数点后精度只保留4位
// 浮点数算上浮点能精确表达最大16位长的数字(1234567.12345678),考虑到16个9会被表示为1e16,这里限制最多15个字符
// 本函数然后小数位只精确到4位,后面补0
func FormatFloatDisplay2Value(amount float64, coinPrecision int64) (int64, error) {
f := decimal.NewFromFloat(amount)
strVal := f.String()
if len(strVal) <= 0 {
return 0, errors.Wrapf(ErrInvalidParam, "input=%f", amount)
}
//小数位输入不能超过配置小数位精度
coinPrecisionNum := int(math.Log10(float64(coinPrecision)))
i := strings.Index(strVal, ".")
if i > 0 && len(strVal)-i-1 > coinPrecisionNum {
return 0, errors.Wrapf(ErrInvalidParam, "input decimalpoint num=%d great than config coinPrecision=%d", len(strVal)-i-1, coinPrecisionNum)
}
//因为float精度原因,限制输入浮点数最多字符数
if len(strVal) > MaxFloatCharNum {
return 0, errors.Wrapf(ErrInvalidParam, "input=%f,len=%d great than %v", amount, len(strVal), MaxFloatCharNum)
}
//如果配置精度超过4位,小数位只精确到后4位, 例如1.23456789 ->123450000
if int64(coinPrecisionNum) > ShowPrecisionNum {
return f.Truncate(int32(ShowPrecisionNum)).Shift(int32(coinPrecisionNum)).IntPart(), nil
}
//如果配置精度小于4位,乘精度
return f.Shift(int32(coinPrecisionNum)).IntPart(), nil
}