github.com/turingchain2020/turingchain@v1.1.21/types/tx.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package types 6 7 import ( 8 "bytes" 9 "encoding/hex" 10 "encoding/json" 11 "reflect" 12 "sort" 13 "time" 14 15 lru "github.com/hashicorp/golang-lru" 16 17 "strconv" 18 19 "github.com/turingchain2020/turingchain/common" 20 "github.com/turingchain2020/turingchain/common/address" 21 "github.com/turingchain2020/turingchain/common/crypto" 22 ) 23 24 var ( 25 bCoins = []byte("coins") 26 bToken = []byte("token") 27 withdraw = "withdraw" 28 txCache *lru.Cache 29 ) 30 31 func init() { 32 var err error 33 txCache, err = lru.New(10240) 34 if err != nil { 35 panic(err) 36 } 37 } 38 39 //TxCacheGet 某些交易的cache 加入缓存中,防止重复进行解析或者计算 40 func TxCacheGet(tx *Transaction) (*TransactionCache, bool) { 41 txc, ok := txCache.Get(tx) 42 if !ok { 43 return nil, ok 44 } 45 return txc.(*TransactionCache), ok 46 } 47 48 //TxCacheSet 设置 cache 49 func TxCacheSet(tx *Transaction, txc *TransactionCache) { 50 if txc == nil { 51 txCache.Remove(tx) 52 return 53 } 54 txCache.Add(tx, txc) 55 } 56 57 // CreateTxGroup 创建组交易, feeRate传入交易费率, 建议通过系统GetProperFee获取 58 func CreateTxGroup(txs []*Transaction, feeRate int64) (*Transactions, error) { 59 if len(txs) < 2 { 60 return nil, ErrTxGroupCountLessThanTwo 61 } 62 txgroup := &Transactions{} 63 txgroup.Txs = txs 64 totalfee := int64(0) 65 minfee := int64(0) 66 header := txs[0].Hash() 67 for i := len(txs) - 1; i >= 0; i-- { 68 txs[i].GroupCount = int32(len(txs)) 69 totalfee += txs[i].GetFee() 70 // Header和Fee设置是为了GetRealFee里面Size的计算,Fee是否为0和不同大小,size也是有差别的,header是否为空差别是common.Sha256Len+2 71 // 这里直接设置Header兼容性更好, Next不需要,已经设置过了,唯一不同的是,txs[0].fee会跟实际计算有差别,这里设置一个超大值只做计算 72 txs[i].Header = header 73 if i == 0 { 74 //对txs[0].fee设置一个超大值,大于后面实际计算出的fee,也就>=check时候计算出的fee, 对size影响10个字节,在1000临界值时候有差别 75 txs[i].Fee = 1 << 62 76 } else { 77 txs[i].Fee = 0 78 } 79 realfee, err := txs[i].GetRealFee(feeRate) 80 if err != nil { 81 return nil, err 82 } 83 minfee += realfee 84 if i == 0 { 85 if totalfee < minfee { 86 totalfee = minfee 87 } 88 txs[0].Fee = totalfee 89 header = txs[0].Hash() 90 } else { 91 txs[i].Fee = 0 92 txs[i-1].Next = txs[i].Hash() 93 } 94 } 95 for i := 0; i < len(txs); i++ { 96 txs[i].Header = header 97 } 98 return txgroup, nil 99 } 100 101 //Tx 这比用于检查的交易,包含了所有的交易。 102 //主要是为了兼容原来的设计 103 func (txgroup *Transactions) Tx() *Transaction { 104 if len(txgroup.GetTxs()) < 2 { 105 return nil 106 } 107 headtx := txgroup.GetTxs()[0] 108 //不会影响原来的tx 109 copytx := *headtx 110 data := Encode(txgroup) 111 //放到header中不影响交易的Hash 112 copytx.Header = data 113 return ©tx 114 } 115 116 //GetTxGroup 获取交易组 117 func (txgroup *Transactions) GetTxGroup() *Transactions { 118 return txgroup 119 } 120 121 //SignN 对交易组的第n笔交易签名 122 func (txgroup *Transactions) SignN(n int, ty int32, priv crypto.PrivKey) error { 123 if n >= len(txgroup.GetTxs()) { 124 return ErrIndex 125 } 126 txgroup.GetTxs()[n].Sign(ty, priv) 127 return nil 128 } 129 130 //CheckSign 检测交易组的签名 131 func (txgroup *Transactions) CheckSign() bool { 132 txs := txgroup.Txs 133 for i := 0; i < len(txs); i++ { 134 if !txs[i].checkSign() { 135 return false 136 } 137 } 138 return true 139 } 140 141 //RebuiltGroup 交易内容有变化时需要重新构建交易组 142 func (txgroup *Transactions) RebuiltGroup() { 143 header := txgroup.Txs[0].Hash() 144 for i := len(txgroup.Txs) - 1; i >= 0; i-- { 145 txgroup.Txs[i].Header = header 146 if i == 0 { 147 header = txgroup.Txs[0].Hash() 148 } else { 149 txgroup.Txs[i-1].Next = txgroup.Txs[i].Hash() 150 } 151 } 152 for i := 0; i < len(txgroup.Txs); i++ { 153 txgroup.Txs[i].Header = header 154 } 155 } 156 157 //SetExpire 设置交易组中交易的过期时间 158 func (txgroup *Transactions) SetExpire(cfg *TuringchainConfig, n int, expire time.Duration) { 159 if n >= len(txgroup.GetTxs()) { 160 return 161 } 162 txgroup.GetTxs()[n].SetExpire(cfg, expire) 163 } 164 165 //IsExpire 交易是否过期 166 func (txgroup *Transactions) IsExpire(cfg *TuringchainConfig, height, blocktime int64) bool { 167 txs := txgroup.Txs 168 for i := 0; i < len(txs); i++ { 169 if txs[i].isExpire(cfg, height, blocktime) { 170 return true 171 } 172 } 173 return false 174 } 175 176 //CheckWithFork 和fork 无关的有个检查函数 177 func (txgroup *Transactions) CheckWithFork(cfg *TuringchainConfig, checkFork, paraFork bool, height, minfee, maxFee int64) error { 178 txs := txgroup.Txs 179 if len(txs) < 2 { 180 return ErrTxGroupCountLessThanTwo 181 } 182 para := make(map[string]bool) 183 for i := 0; i < len(txs); i++ { 184 if txs[i] == nil { 185 return ErrTxGroupEmpty 186 } 187 err := txs[i].check(cfg, height, 0, maxFee) 188 if err != nil { 189 return err 190 } 191 if title, ok := GetParaExecTitleName(string(txs[i].Execer)); ok { 192 para[title] = true 193 } 194 } 195 //txgroup 只允许一条平行链的交易, 且平行链txgroup须全部是平行链tx 196 //如果平行链已经在主链分叉高度前运行了一段时间且有跨链交易,平行链需要自己设置这个fork 197 if paraFork { 198 if len(para) > 1 { 199 tlog.Info("txgroup has multi para transaction") 200 return ErrTxGroupParaCount 201 } 202 if len(para) > 0 { 203 for _, tx := range txs { 204 if !IsParaExecName(string(tx.Execer)) { 205 tlog.Error("para txgroup has main chain transaction") 206 return ErrTxGroupParaMainMixed 207 } 208 } 209 } 210 } 211 212 for i := 1; i < len(txs); i++ { 213 if txs[i].Fee != 0 { 214 return ErrTxGroupFeeNotZero 215 } 216 } 217 //检查txs[0] 的费用是否满足要求 218 totalfee := int64(0) 219 for i := 0; i < len(txs); i++ { 220 fee, err := txs[i].GetRealFee(minfee) 221 if err != nil { 222 return err 223 } 224 totalfee += fee 225 } 226 if txs[0].Fee < totalfee { 227 return ErrTxFeeTooLow 228 } 229 if txs[0].Fee > maxFee && maxFee > 0 && checkFork { 230 return ErrTxFeeTooHigh 231 } 232 //检查hash是否符合要求 233 for i := 0; i < len(txs); i++ { 234 //检查头部是否等于头部hash 235 if i == 0 { 236 if !bytes.Equal(txs[i].Hash(), txs[i].Header) { 237 return ErrTxGroupHeader 238 } 239 } else { 240 if !bytes.Equal(txs[0].Header, txs[i].Header) { 241 return ErrTxGroupHeader 242 } 243 } 244 //检查group count 245 if txs[i].GroupCount > MaxTxGroupSize { 246 return ErrTxGroupCountBigThanMaxSize 247 } 248 if txs[i].GroupCount != int32(len(txs)) { 249 return ErrTxGroupCount 250 } 251 //检查next 252 if i < len(txs)-1 { 253 if !bytes.Equal(txs[i].Next, txs[i+1].Hash()) { 254 return ErrTxGroupNext 255 } 256 } else { 257 if txs[i].Next != nil { 258 return ErrTxGroupNext 259 } 260 } 261 } 262 return nil 263 } 264 265 //Check height == 0 的时候,不做检查 266 func (txgroup *Transactions) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error { 267 paraFork := cfg.IsFork(height, "ForkTxGroupPara") 268 checkFork := cfg.IsFork(height, "ForkBlockCheck") 269 return txgroup.CheckWithFork(cfg, checkFork, paraFork, height, minfee, maxFee) 270 } 271 272 //TransactionCache 交易缓存结构 273 type TransactionCache struct { 274 *Transaction 275 txGroup *Transactions 276 hash []byte 277 size int 278 signok int //init 0, ok 1, err 2 279 checkok error //init 0, ok 1, err 2 280 checked bool 281 payload reflect.Value 282 plname string 283 plerr error 284 } 285 286 //NewTransactionCache new交易缓存 287 func NewTransactionCache(tx *Transaction) *TransactionCache { 288 return &TransactionCache{Transaction: tx} 289 } 290 291 //Hash 交易hash 292 func (tx *TransactionCache) Hash() []byte { 293 if tx.hash == nil { 294 tx.hash = tx.Transaction.Hash() 295 } 296 return tx.hash 297 } 298 299 //SetPayloadValue 设置payload 的cache 300 func (tx *TransactionCache) SetPayloadValue(plname string, payload reflect.Value, plerr error) { 301 tx.payload = payload 302 tx.plerr = plerr 303 tx.plname = plname 304 } 305 306 //GetPayloadValue 设置payload 的cache 307 func (tx *TransactionCache) GetPayloadValue() (plname string, payload reflect.Value, plerr error) { 308 if tx.plerr != nil || tx.plname != "" { 309 return tx.plname, tx.payload, tx.plerr 310 } 311 exec := LoadExecutorType(string(tx.Execer)) 312 if exec == nil { 313 tx.SetPayloadValue("", reflect.ValueOf(nil), ErrExecNotFound) 314 return "", reflect.ValueOf(nil), ErrExecNotFound 315 } 316 plname, payload, plerr = exec.DecodePayloadValue(tx.Tx()) 317 tx.SetPayloadValue(plname, payload, plerr) 318 return 319 } 320 321 //Size 交易缓存的大小 322 func (tx *TransactionCache) Size() int { 323 if tx.size == 0 { 324 tx.size = Size(tx.Tx()) 325 } 326 return tx.size 327 } 328 329 //Tx 交易缓存中tx信息 330 func (tx *TransactionCache) Tx() *Transaction { 331 return tx.Transaction 332 } 333 334 //Check 交易缓存中交易组合费用的检测 335 func (tx *TransactionCache) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error { 336 if !tx.checked { 337 tx.checked = true 338 txs, err := tx.GetTxGroup() 339 if err != nil { 340 tx.checkok = err 341 return err 342 } 343 if txs == nil { 344 tx.checkok = tx.check(cfg, height, minfee, maxFee) 345 } else { 346 tx.checkok = txs.Check(cfg, height, minfee, maxFee) 347 } 348 } 349 return tx.checkok 350 } 351 352 //GetTotalFee 获取交易真实费用 353 func (tx *TransactionCache) GetTotalFee(minFee int64) (int64, error) { 354 txgroup, err := tx.GetTxGroup() 355 if err != nil { 356 tx.checkok = err 357 return 0, err 358 } 359 var totalfee int64 360 if txgroup == nil { 361 return tx.GetRealFee(minFee) 362 } 363 txs := txgroup.Txs 364 for i := 0; i < len(txs); i++ { 365 fee, err := txs[i].GetRealFee(minFee) 366 if err != nil { 367 return 0, err 368 } 369 totalfee += fee 370 } 371 return totalfee, nil 372 } 373 374 //GetTxGroup 获取交易组 375 func (tx *TransactionCache) GetTxGroup() (*Transactions, error) { 376 var err error 377 if tx.txGroup == nil { 378 tx.txGroup, err = tx.Transaction.GetTxGroup() 379 if err != nil { 380 return nil, err 381 } 382 } 383 return tx.txGroup, nil 384 } 385 386 //CheckSign 检测签名 387 func (tx *TransactionCache) CheckSign() bool { 388 if tx.signok == 0 { 389 tx.signok = 2 390 group, err := tx.GetTxGroup() 391 if err != nil { 392 return false 393 } 394 if group == nil { 395 //非group,简单校验签名 396 if ok := tx.checkSign(); ok { 397 tx.signok = 1 398 } 399 } else { 400 if ok := group.CheckSign(); ok { 401 tx.signok = 1 402 } 403 } 404 } 405 return tx.signok == 1 406 } 407 408 //TxsToCache 缓存交易信息 409 func TxsToCache(txs []*Transaction) (caches []*TransactionCache) { 410 caches = make([]*TransactionCache, len(txs)) 411 for i := 0; i < len(caches); i++ { 412 caches[i] = NewTransactionCache(txs[i]) 413 } 414 return caches 415 } 416 417 //CacheToTxs 从缓存中获取交易信息 418 func CacheToTxs(caches []*TransactionCache) (txs []*Transaction) { 419 txs = make([]*Transaction, len(caches)) 420 for i := 0; i < len(caches); i++ { 421 txs[i] = caches[i].Tx() 422 } 423 return txs 424 } 425 426 //HashSign hash 不包含签名,用户通过修改签名无法重新发送交易 427 func (tx *Transaction) HashSign() []byte { 428 copytx := *tx 429 copytx.Signature = nil 430 data := Encode(©tx) 431 return common.Sha256(data) 432 } 433 434 //Tx 交易详情 435 func (tx *Transaction) Tx() *Transaction { 436 return tx 437 } 438 439 //GetTxGroup 交易组装成交易组格式 440 func (tx *Transaction) GetTxGroup() (*Transactions, error) { 441 if tx.GroupCount < 0 || tx.GroupCount == 1 || tx.GroupCount > 20 { 442 return nil, ErrTxGroupCount 443 } 444 if tx.GroupCount > 0 { 445 var txs Transactions 446 err := Decode(tx.Header, &txs) 447 if err != nil { 448 return nil, err 449 } 450 return &txs, nil 451 } 452 if tx.Next != nil || tx.Header != nil { 453 return nil, ErrNomalTx 454 } 455 return nil, nil 456 } 457 458 //Size 交易大小 459 func (tx *Transaction) Size() int { 460 return Size(tx) 461 } 462 463 //Sign 交易签名 464 func (tx *Transaction) Sign(ty int32, priv crypto.PrivKey) { 465 tx.Signature = nil 466 data := Encode(tx) 467 pub := priv.PubKey() 468 sign := priv.Sign(data) 469 tx.Signature = &Signature{ 470 Ty: ty, 471 Pubkey: pub.Bytes(), 472 Signature: sign.Bytes(), 473 } 474 } 475 476 //CheckSign tx 有些时候是一个交易组 477 func (tx *Transaction) CheckSign() bool { 478 return tx.checkSign() 479 } 480 481 //txgroup 的情况 482 func (tx *Transaction) checkSign() bool { 483 copytx := *tx 484 copytx.Signature = nil 485 data := Encode(©tx) 486 if tx.GetSignature() == nil { 487 return false 488 } 489 return CheckSign(data, string(tx.Execer), tx.GetSignature()) 490 } 491 492 //Check 交易检测 493 func (tx *Transaction) Check(cfg *TuringchainConfig, height, minfee, maxFee int64) error { 494 group, err := tx.GetTxGroup() 495 if err != nil { 496 return err 497 } 498 if group == nil { 499 return tx.check(cfg, height, minfee, maxFee) 500 } 501 return group.Check(cfg, height, minfee, maxFee) 502 } 503 504 func (tx *Transaction) check(cfg *TuringchainConfig, height, minfee, maxFee int64) error { 505 if minfee == 0 { 506 return nil 507 } 508 // 获取当前交易最小交易费 509 realFee, err := tx.GetRealFee(minfee) 510 if err != nil { 511 return err 512 } 513 // 检查交易费是否小于最低值 514 if tx.Fee < realFee { 515 return ErrTxFeeTooLow 516 } 517 if tx.Fee > maxFee && maxFee > 0 && cfg.IsFork(height, "ForkBlockCheck") { 518 return ErrTxFeeTooHigh 519 } 520 return nil 521 } 522 523 //SetExpire 设置交易过期时间 524 func (tx *Transaction) SetExpire(cfg *TuringchainConfig, expire time.Duration) { 525 //Txheight处理 526 if cfg.IsEnable("TxHeight") && int64(expire) > TxHeightFlag { 527 tx.Expire = int64(expire) 528 return 529 } 530 531 if int64(expire) > ExpireBound { 532 if expire < time.Second*120 { 533 expire = time.Second * 120 534 } 535 //用秒数来表示的时间 536 tx.Expire = Now().Unix() + int64(expire/time.Second) 537 } else { 538 tx.Expire = int64(expire) 539 } 540 } 541 542 //GetRealFee 获取交易真实费用 543 func (tx *Transaction) GetRealFee(minFee int64) (int64, error) { 544 txSize := Size(tx) 545 //如果签名为空,那么加上签名的空间 546 if tx.Signature == nil { 547 txSize += 300 548 } 549 if txSize > MaxTxSize { 550 return 0, ErrTxMsgSizeTooBig 551 } 552 // 检查交易费是否小于最低值 553 realFee := int64(txSize/1000+1) * minFee 554 return realFee, nil 555 } 556 557 //SetRealFee 设置交易真实费用 558 func (tx *Transaction) SetRealFee(minFee int64) error { 559 if tx.Fee == 0 { 560 fee, err := tx.GetRealFee(minFee) 561 if err != nil { 562 return err 563 } 564 tx.Fee = fee 565 } 566 return nil 567 } 568 569 //ExpireBound 交易过期边界值 570 var ExpireBound int64 = 1000000000 // 交易过期分界线,小于expireBound比较height,大于expireBound比较blockTime 571 572 //IsExpire 交易是否过期 573 func (tx *Transaction) IsExpire(cfg *TuringchainConfig, height, blocktime int64) bool { 574 group, _ := tx.GetTxGroup() 575 if group == nil { 576 return tx.isExpire(cfg, height, blocktime) 577 } 578 return group.IsExpire(cfg, height, blocktime) 579 } 580 581 //GetTxFee 获取交易的费用,区分单笔交易和交易组 582 func (tx *Transaction) GetTxFee() int64 { 583 group, _ := tx.GetTxGroup() 584 if group == nil { 585 return tx.Fee 586 } 587 return group.Txs[0].Fee 588 } 589 590 //From 交易from地址 591 func (tx *Transaction) From() string { 592 return address.PubKeyToAddr(tx.GetSignature().GetPubkey()) 593 } 594 595 //检查交易是否过期,过期返回true,未过期返回false 596 func (tx *Transaction) isExpire(cfg *TuringchainConfig, height, blocktime int64) bool { 597 valid := tx.Expire 598 // Expire为0,返回false 599 if valid == 0 { 600 return false 601 } 602 if valid <= ExpireBound { 603 //Expire小于1e9,为height valid > height 未过期返回false else true过期 604 return valid <= height 605 } 606 //EnableTxHeight 选项开启, 并且符合条件 607 if txHeight := GetTxHeight(cfg, valid, height); txHeight > 0 { 608 if txHeight-LowAllowPackHeight <= height && height <= txHeight+HighAllowPackHeight { 609 return false 610 } 611 return true 612 } 613 // Expire大于1e9,为blockTime valid > blocktime返回false 未过期 else true过期 614 return valid <= blocktime 615 } 616 617 //GetTxHeight 获取交易高度 618 func GetTxHeight(cfg *TuringchainConfig, valid int64, height int64) int64 { 619 if cfg.IsPara() { 620 return -1 621 } 622 if cfg.IsEnableFork(height, "ForkTxHeight", cfg.IsEnable("TxHeight")) && valid > TxHeightFlag { 623 return valid - TxHeightFlag 624 } 625 return -1 626 } 627 628 //JSON Transaction交易信息转成json结构体 629 func (tx *Transaction) JSON() string { 630 type transaction struct { 631 Hash string `json:"hash,omitempty"` 632 Execer string `json:"execer,omitempty"` 633 Payload string `json:"payload,omitempty"` 634 Signature *Signature `json:"signature,omitempty"` 635 Fee int64 `json:"fee,omitempty"` 636 Expire int64 `json:"expire,omitempty"` 637 // 随机ID,可以防止payload 相同的时候,交易重复 638 Nonce int64 `json:"nonce,omitempty"` 639 // 对方地址,如果没有对方地址,可以为空 640 To string `json:"to,omitempty"` 641 GroupCount int32 `json:"groupCount,omitempty"` 642 Header string `json:"header,omitempty"` 643 Next string `json:"next,omitempty"` 644 ChainID int32 `json:"chainID,omitempty"` 645 } 646 647 newtx := &transaction{} 648 newtx.Hash = hex.EncodeToString(tx.Hash()) 649 newtx.Execer = string(tx.Execer) 650 newtx.Payload = hex.EncodeToString(tx.Payload) 651 newtx.Signature = tx.Signature 652 newtx.Fee = tx.Fee 653 newtx.Expire = tx.Expire 654 newtx.Nonce = tx.Nonce 655 newtx.To = tx.To 656 newtx.GroupCount = tx.GroupCount 657 newtx.Header = hex.EncodeToString(tx.Header) 658 newtx.Next = hex.EncodeToString(tx.Next) 659 newtx.ChainID = tx.ChainID 660 661 data, err := json.MarshalIndent(newtx, "", "\t") 662 if err != nil { 663 return err.Error() 664 } 665 return string(data) 666 } 667 668 //Amount 解析tx的payload获取amount值 669 func (tx *Transaction) Amount() (int64, error) { 670 // TODO 原来有很多执行器 在这里没有代码, 用默认 0, nil 先 671 exec := LoadExecutorType(string(tx.Execer)) 672 if exec == nil { 673 return 0, nil 674 } 675 return exec.Amount(tx) 676 } 677 678 //Assets 获取交易中的资产 679 func (tx *Transaction) Assets() ([]*Asset, error) { 680 exec := LoadExecutorType(string(tx.Execer)) 681 if exec == nil { 682 return nil, nil 683 } 684 return exec.GetAssets(tx) 685 } 686 687 //GetRealToAddr 解析tx的payload获取real to值 688 func (tx *Transaction) GetRealToAddr() string { 689 exec := LoadExecutorType(string(tx.Execer)) 690 if exec == nil { 691 return tx.To 692 } 693 return exec.GetRealToAddr(tx) 694 } 695 696 //GetViewFromToAddr 解析tx的payload获取view from to 值 697 func (tx *Transaction) GetViewFromToAddr() (string, string) { 698 exec := LoadExecutorType(string(tx.Execer)) 699 if exec == nil { 700 return tx.From(), tx.To 701 } 702 return exec.GetViewFromToAddr(tx) 703 } 704 705 //ActionName 获取tx交易的Actionname 706 func (tx *Transaction) ActionName() string { 707 execName := string(tx.Execer) 708 exec := LoadExecutorType(execName) 709 if exec == nil { 710 //action name 不会影响系统状态,主要是做显示使用 711 realname := GetRealExecName(tx.Execer) 712 exec = LoadExecutorType(string(realname)) 713 if exec == nil { 714 return "unknown" 715 } 716 } 717 return exec.ActionName(tx) 718 } 719 720 //IsWithdraw 判断交易是withdraw交易,需要做from和to地址的swap,方便上层客户理解 721 func (tx *Transaction) IsWithdraw() bool { 722 if bytes.Equal(tx.GetExecer(), bCoins) || bytes.Equal(tx.GetExecer(), bToken) { 723 if tx.ActionName() == withdraw { 724 return true 725 } 726 } 727 return false 728 } 729 730 // ParseExpire parse expire to int from during or height 731 func ParseExpire(expire string) (int64, error) { 732 if len(expire) == 0 { 733 return 0, ErrInvalidParam 734 } 735 if expire[0] == 'H' && expire[1] == ':' { 736 txHeight, err := strconv.ParseInt(expire[2:], 10, 64) 737 if err != nil { 738 return 0, err 739 } 740 if txHeight <= 0 { 741 //fmt.Printf("txHeight should be grate to 0") 742 return 0, ErrHeightLessZero 743 } 744 if txHeight+TxHeightFlag < txHeight { 745 return 0, ErrHeightOverflow 746 } 747 748 return txHeight + TxHeightFlag, nil 749 } 750 751 blockHeight, err := strconv.ParseInt(expire, 10, 64) 752 if err == nil { 753 return blockHeight, nil 754 } 755 756 expireTime, err := time.ParseDuration(expire) 757 if err == nil { 758 return int64(expireTime), nil 759 } 760 761 return 0, err 762 } 763 764 //CalcTxShortHash 取txhash的前指定字节,目前默认5 765 func CalcTxShortHash(hash []byte) string { 766 if len(hash) >= 5 { 767 return hex.EncodeToString(hash[0:5]) 768 } 769 return "" 770 } 771 772 //TransactionSort 对主链以及平行链交易分类 773 //构造一个map用于临时存储各个子链的交易, 按照title分类,主链交易的title设置成main 774 //并对map按照title进行排序,不然每次遍历map顺序会不一致 775 func TransactionSort(rawtxs []*Transaction) []*Transaction { 776 txMap := make(map[string]*Transactions) 777 778 for _, tx := range rawtxs { 779 title, isPara := GetParaExecTitleName(string(tx.Execer)) 780 if !isPara { 781 title = MainChainName 782 } 783 if txMap[title] != nil { 784 txMap[title].Txs = append(txMap[title].Txs, tx) 785 } else { 786 var temptxs Transactions 787 temptxs.Txs = append(temptxs.Txs, tx) 788 txMap[title] = &temptxs 789 } 790 } 791 792 //需要按照title排序,不然每次遍历的map的顺序会不一致 793 var newMp = make([]string, 0) 794 for k := range txMap { 795 newMp = append(newMp, k) 796 } 797 sort.Strings(newMp) 798 799 var txs Transactions 800 for _, v := range newMp { 801 txs.Txs = append(txs.Txs, txMap[v].GetTxs()...) 802 } 803 return txs.GetTxs() 804 } 805 806 //Hash 交易的hash不包含header的值,引入tx group的概念后,做了修改 807 func (tx *Transaction) Hash() []byte { 808 copytx := cloneTx(tx) 809 copytx.Signature = nil 810 copytx.Header = nil 811 data := Encode(copytx) 812 return common.Sha256(data) 813 } 814 815 //FullHash 交易的fullhash包含交易的签名信息 816 func (tx *Transaction) FullHash() []byte { 817 copytx := tx.Clone() 818 data := Encode(copytx) 819 return common.Sha256(data) 820 } 821 822 //TxGroup 交易组的接口,Transactions 和 Transaction 都符合这个接口 823 type TxGroup interface { 824 Tx() *Transaction 825 GetTxGroup() (*Transactions, error) 826 CheckSign() bool 827 } 828 829 //这里要避免用 tmp := *tx 这样就会读 可能被 proto 其他线程修改的 size 字段 830 //proto buffer 字段发生更改之后,一定要修改这里,否则可能引起严重的bug 831 func cloneTx(tx *Transaction) *Transaction { 832 copytx := &Transaction{} 833 copytx.Execer = tx.Execer 834 copytx.Payload = tx.Payload 835 copytx.Signature = tx.Signature 836 copytx.Fee = tx.Fee 837 copytx.Expire = tx.Expire 838 copytx.Nonce = tx.Nonce 839 copytx.To = tx.To 840 copytx.GroupCount = tx.GroupCount 841 copytx.Header = tx.Header 842 copytx.Next = tx.Next 843 copytx.ChainID = tx.ChainID 844 return copytx 845 } 846 847 //Clone copytx := proto.Clone(tx).(*Transaction) too slow 848 func (tx *Transaction) Clone() *Transaction { 849 if tx == nil { 850 return nil 851 } 852 tmp := cloneTx(tx) 853 tmp.Signature = tx.Signature.Clone() 854 return tmp 855 } 856 857 //cloneTxs 拷贝 txs 858 func cloneTxs(b []*Transaction) []*Transaction { 859 if b == nil { 860 return nil 861 } 862 txs := make([]*Transaction, len(b)) 863 for i := 0; i < len(b); i++ { 864 txs[i] = b[i].Clone() 865 } 866 return txs 867 }