github.com/turingchain2020/turingchain@v1.1.21/util/exec.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 util
     6  
     7  import (
     8  	"errors"
     9  
    10  	clientApi "github.com/turingchain2020/turingchain/client"
    11  	"github.com/turingchain2020/turingchain/common"
    12  	log "github.com/turingchain2020/turingchain/common/log/log15"
    13  	"github.com/turingchain2020/turingchain/queue"
    14  	"github.com/turingchain2020/turingchain/types"
    15  )
    16  
    17  //CheckBlock : To check the block's validaty
    18  func CheckBlock(client queue.Client, block *types.BlockDetail) error {
    19  	req := block
    20  	msg := client.NewMessage("consensus", types.EventCheckBlock, req)
    21  	err := client.Send(msg, true)
    22  	if err != nil {
    23  		return err
    24  	}
    25  	resp, err := client.Wait(msg)
    26  	if err != nil {
    27  		return err
    28  	}
    29  	reply := resp.GetData().(*types.Reply)
    30  	if reply.IsOk {
    31  		return nil
    32  	}
    33  	return errors.New(string(reply.GetMsg()))
    34  }
    35  
    36  //ExecTx : To send lists of txs within a block to exector for execution
    37  func ExecTx(client queue.Client, prevStateRoot []byte, block *types.Block) (*types.Receipts, error) {
    38  	list := &types.ExecTxList{
    39  		StateHash:  prevStateRoot,
    40  		ParentHash: block.ParentHash,
    41  		MainHash:   block.MainHash,
    42  		MainHeight: block.MainHeight,
    43  		Txs:        block.Txs,
    44  		BlockTime:  block.BlockTime,
    45  		Height:     block.Height,
    46  		Difficulty: uint64(block.Difficulty),
    47  		IsMempool:  false,
    48  	}
    49  	msg := client.NewMessage("execs", types.EventExecTxList, list)
    50  	err := client.Send(msg, true)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	resp, err := client.Wait(msg)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	receipts := resp.GetData().(*types.Receipts)
    59  	return receipts, nil
    60  }
    61  
    62  //ExecKVMemSet : send kv values to memory store and set it in db
    63  func ExecKVMemSet(client queue.Client, prevStateRoot []byte, height int64, kvset []*types.KeyValue, sync bool, upgrade bool) ([]byte, error) {
    64  	set := &types.StoreSet{StateHash: prevStateRoot, KV: kvset, Height: height}
    65  	setwithsync := &types.StoreSetWithSync{Storeset: set, Sync: sync, Upgrade: upgrade}
    66  
    67  	msg := client.NewMessage("store", types.EventStoreMemSet, setwithsync)
    68  	err := client.Send(msg, true)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	resp, err := client.Wait(msg)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  	hash := resp.GetData().(*types.ReplyHash)
    77  	return hash.GetHash(), nil
    78  }
    79  
    80  //ExecKVSetCommit : commit the data set opetation to db
    81  func ExecKVSetCommit(client queue.Client, hash []byte, upgrade bool) error {
    82  	req := &types.ReqHash{Hash: hash, Upgrade: upgrade}
    83  	msg := client.NewMessage("store", types.EventStoreCommit, req)
    84  	err := client.Send(msg, true)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	msg, err = client.Wait(msg)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	hash = msg.GetData().(*types.ReplyHash).GetHash()
    93  	_ = hash
    94  	return nil
    95  }
    96  
    97  //ExecKVSetRollback : do the db's roll back operation
    98  func ExecKVSetRollback(client queue.Client, hash []byte) error {
    99  	req := &types.ReqHash{Hash: hash}
   100  	msg := client.NewMessage("store", types.EventStoreRollback, req)
   101  	err := client.Send(msg, true)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	msg, err = client.Wait(msg)
   106  	if err != nil {
   107  		return err
   108  	}
   109  	hash = msg.GetData().(*types.ReplyHash).GetHash()
   110  	_ = hash
   111  	return nil
   112  }
   113  
   114  //DelDupTx 删除重复的交易
   115  func DelDupTx(txs []*types.TransactionCache) (ret []*types.TransactionCache) {
   116  	dupindex := make(map[string]int)
   117  	hasdup := false
   118  	for i, tx := range txs {
   119  		if _, ok := dupindex[string(tx.Hash())]; ok {
   120  			hasdup = true
   121  		}
   122  		dupindex[string(tx.Hash())] = i
   123  	}
   124  	//没有重复的情况下,不需要重新处理
   125  	if !hasdup {
   126  		return txs
   127  	}
   128  	index := 0
   129  	for i, tx := range txs {
   130  		lastindex := dupindex[string(tx.Hash())]
   131  		if i == lastindex {
   132  			txs[index] = tx
   133  			index++
   134  		}
   135  	}
   136  	return txs[0:index]
   137  }
   138  
   139  //CheckDupTx : check use txs []*types.Transaction and not []*types.TransactionCache
   140  func CheckDupTx(client queue.Client, txs []*types.Transaction, height int64) (transactions []*types.Transaction, err error) {
   141  	txcache := make([]*types.TransactionCache, len(txs))
   142  	for i := 0; i < len(txcache); i++ {
   143  		txcache[i] = &types.TransactionCache{Transaction: txs[i]}
   144  	}
   145  	cache, err := CheckTxDup(client, txcache, height)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	for i := 0; i < len(cache); i++ {
   150  		transactions = append(transactions, cache[i].Transaction)
   151  	}
   152  	return transactions, nil
   153  }
   154  
   155  //CheckTxDup : check whether the tx is duplicated within the while chain
   156  func CheckTxDup(client queue.Client, txs []*types.TransactionCache, height int64) (transactions []*types.TransactionCache, err error) {
   157  	var checkHashList types.TxHashList
   158  	types.AssertConfig(client)
   159  	cfg := client.GetConfig()
   160  	if cfg.IsFork(height, "ForkCheckTxDup") {
   161  		txs = DelDupTx(txs)
   162  	}
   163  	for _, tx := range txs {
   164  		checkHashList.Hashes = append(checkHashList.Hashes, tx.Hash())
   165  		checkHashList.Expire = append(checkHashList.Expire, tx.GetExpire())
   166  	}
   167  	checkHashList.Count = height
   168  	hashList := client.NewMessage("blockchain", types.EventTxHashList, &checkHashList)
   169  	err = client.Send(hashList, true)
   170  	if err != nil {
   171  		log.Error("send", "to blockchain EventTxHashList msg err", err)
   172  		return nil, err
   173  	}
   174  	dupTxList, err := client.Wait(hashList)
   175  
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	dupTxs := dupTxList.GetData().(*types.TxHashList).Hashes
   180  	dupMap := make(map[string]bool)
   181  	for _, hash := range dupTxs {
   182  		dupMap[string(hash)] = true
   183  	}
   184  
   185  	for _, tx := range txs {
   186  		hash := tx.Hash()
   187  		if dupMap[string(hash)] {
   188  			continue
   189  		}
   190  		transactions = append(transactions, tx)
   191  	}
   192  	client.FreeMessage(hashList, dupTxList)
   193  	return transactions, nil
   194  }
   195  
   196  //ReportErrEventToFront 上报指定错误信息到指定模块,目前只支持从store,blockchain,wallet写数据库失败时上报错误信息到wallet模块,
   197  //然后由钱包模块前端定时调用显示给客户
   198  func ReportErrEventToFront(logger log.Logger, client queue.Client, frommodule string, tomodule string, err error) {
   199  	if client == nil || len(tomodule) == 0 || len(frommodule) == 0 || err == nil {
   200  		logger.Error("SendErrEventToFront  input para err .")
   201  		return
   202  	}
   203  
   204  	logger.Debug("SendErrEventToFront", "frommodule", frommodule, "tomodule", tomodule, "err", err)
   205  
   206  	var reportErrEvent types.ReportErrEvent
   207  	reportErrEvent.Frommodule = frommodule
   208  	reportErrEvent.Tomodule = tomodule
   209  	reportErrEvent.Error = err.Error()
   210  
   211  	api, err := clientApi.New(client, nil)
   212  	if err != nil {
   213  		log.Error("client", "new err", err)
   214  	}
   215  
   216  	_, err = api.ExecWalletFunc(tomodule, "ErrToFront", &reportErrEvent)
   217  	if err != nil {
   218  		log.Error("send", "ErrToFront msg err", err)
   219  	}
   220  }
   221  
   222  //DelDupKey 删除重复的key
   223  func DelDupKey(kvs []*types.KeyValue) []*types.KeyValue {
   224  	dupindex := make(map[string]int)
   225  	n := 0
   226  	for _, kv := range kvs {
   227  		skey := string(kv.Key)
   228  		if index, ok := dupindex[skey]; ok {
   229  			//重复的key 替换老的key
   230  			kvs[index] = kv
   231  		} else {
   232  			dupindex[skey] = n
   233  			kvs[n] = kv
   234  			n++
   235  		}
   236  	}
   237  	return kvs[0:n]
   238  }
   239  
   240  //CmpBestBlock : 选择最优区块,通知共识模块newblock是否是最优区块
   241  // height,time,parentHash一致时根据共识各自规则判断
   242  func CmpBestBlock(client queue.Client, newBlock *types.Block, cmpHash []byte) bool {
   243  	cfg := client.GetConfig()
   244  	req := types.CmpBlock{Block: newBlock, CmpHash: cmpHash}
   245  	msg := client.NewMessage("consensus", types.EventCmpBestBlock, &req)
   246  	err := client.Send(msg, true)
   247  	if err != nil {
   248  		log.Error("CmpBestBlock:Send", "cmpHash", common.ToHex(cmpHash), "newBlockHash", common.ToHex(newBlock.Hash(cfg)), "err", err)
   249  		return false
   250  	}
   251  	resp, err := client.Wait(msg)
   252  	if err != nil {
   253  		log.Error("CmpBestBlock:Wait", "cmpHash", common.ToHex(cmpHash), "newBlockHash", common.ToHex(newBlock.Hash(cfg)), "err", err)
   254  		return false
   255  	}
   256  	reply := resp.GetData().(*types.Reply)
   257  
   258  	log.Debug("CmpBestBlock", "newBlockHash", common.ToHex(newBlock.Hash(cfg)), "cmpHash", common.ToHex(cmpHash), "isBestBlock", reply.IsOk)
   259  	return reply.IsOk
   260  }