github.com/turingchain2020/turingchain@v1.1.21/blockchain/query_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 blockchain
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  
    11  	"github.com/turingchain2020/turingchain/common"
    12  	"github.com/turingchain2020/turingchain/common/merkle"
    13  	"github.com/turingchain2020/turingchain/types"
    14  )
    15  
    16  //ProcGetTransactionByAddr 获取地址对应的所有交易信息
    17  //存储格式key:addr:flag:height ,value:txhash
    18  //key=addr :获取本地参与的所有交易
    19  //key=addr:1 :获取本地作为from方的所有交易
    20  //key=addr:2 :获取本地作为to方的所有交易
    21  func (chain *BlockChain) ProcGetTransactionByAddr(addr *types.ReqAddr) (*types.ReplyTxInfos, error) {
    22  	if addr == nil || len(addr.Addr) == 0 {
    23  		return nil, types.ErrInvalidParam
    24  	}
    25  	//默认取10笔交易数据
    26  	if addr.Count == 0 {
    27  		addr.Count = 10
    28  	}
    29  
    30  	if int64(addr.Count) > types.MaxBlockCountPerTime {
    31  		return nil, types.ErrMaxCountPerTime
    32  	}
    33  	//入参数校验
    34  	curheigt := chain.GetBlockHeight()
    35  	if addr.GetHeight() > curheigt || addr.GetHeight() < -1 {
    36  		chainlog.Error("ProcGetTransactionByAddr Height err")
    37  		return nil, types.ErrInvalidParam
    38  	}
    39  	if addr.GetDirection() != 0 && addr.GetDirection() != 1 {
    40  		chainlog.Error("ProcGetTransactionByAddr Direction err")
    41  		return nil, types.ErrInvalidParam
    42  	}
    43  	if addr.GetIndex() < 0 || addr.GetIndex() > types.MaxTxsPerBlock {
    44  		chainlog.Error("ProcGetTransactionByAddr Index err")
    45  		return nil, types.ErrInvalidParam
    46  	}
    47  	//查询的drivers--> main 驱动的名称
    48  	//查询的方法:  --> GetTxsByAddr
    49  	//查询的参数:  --> interface{} 类型
    50  	cfg := chain.client.GetConfig()
    51  	txinfos, err := chain.query.Query(cfg.ExecName("coins"), "GetTxsByAddr", addr)
    52  	if err != nil {
    53  		chainlog.Info("ProcGetTransactionByAddr does not exist tx!", "addr", addr, "err", err)
    54  		return nil, err
    55  	}
    56  	return txinfos.(*types.ReplyTxInfos), nil
    57  }
    58  
    59  //ProcGetTransactionByHashes 返回类型
    60  //type TransactionDetails struct {
    61  //	Txs []*Transaction
    62  //}
    63  //通过hashs获取交易详情
    64  func (chain *BlockChain) ProcGetTransactionByHashes(hashs [][]byte) (TxDetails *types.TransactionDetails, err error) {
    65  	if int64(len(hashs)) > types.MaxBlockCountPerTime {
    66  		return nil, types.ErrMaxCountPerTime
    67  	}
    68  	var txDetails types.TransactionDetails
    69  	for _, txhash := range hashs {
    70  		txresult, err := chain.GetTxResultFromDb(txhash)
    71  		var txDetail types.TransactionDetail
    72  		if err == nil && txresult != nil {
    73  			setTxDetailFromTxResult(&txDetail, txresult)
    74  
    75  			//chainlog.Debug("ProcGetTransactionByHashes", "txDetail", txDetail.String())
    76  			txDetails.Txs = append(txDetails.Txs, &txDetail)
    77  		} else {
    78  			txDetails.Txs = append(txDetails.Txs, &txDetail) //
    79  			chainlog.Debug("ProcGetTransactionByHashes hash no exit", "txhash", common.ToHex(txhash))
    80  		}
    81  	}
    82  	return &txDetails, nil
    83  }
    84  
    85  //getTxHashProofs 获取指定txindex在txs中的proof ,注释:index从0开始
    86  func getTxHashProofs(Txs []*types.Transaction, index int32) [][]byte {
    87  	txlen := len(Txs)
    88  	leaves := make([][]byte, txlen)
    89  
    90  	for index, tx := range Txs {
    91  		leaves[index] = tx.Hash()
    92  	}
    93  
    94  	proofs := merkle.GetMerkleBranch(leaves, uint32(index))
    95  	chainlog.Debug("getTransactionDetail", "index", index, "proofs", proofs)
    96  
    97  	return proofs
    98  }
    99  
   100  //GetTxResultFromDb 通过txhash 从txindex db中获取tx信息
   101  //type TxResult struct {
   102  //	Height int64
   103  //	Index  int32
   104  //	Tx     *types.Transaction
   105  //  Receiptdate *ReceiptData
   106  //}
   107  func (chain *BlockChain) GetTxResultFromDb(txhash []byte) (tx *types.TxResult, err error) {
   108  	txinfo, err := chain.blockStore.GetTx(txhash)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	return txinfo, nil
   113  }
   114  
   115  //HasTx 是否包含该交易
   116  func (chain *BlockChain) HasTx(txhash []byte, txHeight int64) (has bool, err error) {
   117  
   118  	if txHeight > 0 {
   119  		return chain.txHeightCache.Contains(txhash, txHeight), nil
   120  	}
   121  	return chain.blockStore.HasTx(txhash)
   122  }
   123  
   124  //GetDuplicateTxHashList 获取重复的交易
   125  func (chain *BlockChain) GetDuplicateTxHashList(txhashlist *types.TxHashList) (duptxhashlist *types.TxHashList, err error) {
   126  	var dupTxHashList types.TxHashList
   127  	//onlyquerycache := false
   128  	//FIXME:这里Count实际传的是区块高度的值,代码中没找到-1的传参,不清楚具体含义
   129  	//对于非txHeight类交易,直接查询数据库,不会有影响,暂时先注释
   130  	//if txhashlist.Count == -1 {
   131  	//	onlyquerycache = true
   132  	//}
   133  	if txhashlist.Expire != nil && len(txhashlist.Expire) != len(txhashlist.Hashes) {
   134  		return nil, types.ErrInvalidParam
   135  	}
   136  	cfg := chain.client.GetConfig()
   137  	for i, txhash := range txhashlist.Hashes {
   138  		expire := int64(0)
   139  		if txhashlist.Expire != nil {
   140  			expire = txhashlist.Expire[i]
   141  		}
   142  		txHeight := types.GetTxHeight(cfg, expire, txhashlist.Count)
   143  		has, err := chain.HasTx(txhash, txHeight)
   144  		if err == nil && has {
   145  			dupTxHashList.Hashes = append(dupTxHashList.Hashes, txhash)
   146  		}
   147  	}
   148  	return &dupTxHashList, nil
   149  }
   150  
   151  /*ProcQueryTxMsg 函数功能:
   152  EventQueryTx(types.ReqHash) : rpc模块会向 blockchain 模块 发送 EventQueryTx(types.ReqHash) 消息 ,
   153  查询交易的默克尔树,回复消息 EventTransactionDetail(types.TransactionDetail)
   154  结构体:
   155  type ReqHash struct {Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`}
   156  type TransactionDetail struct {Hashs [][]byte `protobuf:"bytes,1,rep,name=hashs,proto3" json:"hashs,omitempty"}
   157  */
   158  func (chain *BlockChain) ProcQueryTxMsg(txhash []byte) (proof *types.TransactionDetail, err error) {
   159  	txresult, err := chain.GetTxResultFromDb(txhash)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	block, err := chain.GetBlock(txresult.Height)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	var txDetail types.TransactionDetail
   169  	cfg := chain.client.GetConfig()
   170  	height := block.Block.GetHeight()
   171  	if chain.isParaChain {
   172  		height = block.Block.GetMainHeight()
   173  	}
   174  	//获取指定tx在txlist中的proof,需要区分ForkRootHash前后proof证明数据
   175  	if !cfg.IsFork(height, "ForkRootHash") {
   176  		proofs := getTxHashProofs(block.Block.Txs, txresult.Index)
   177  		txDetail.Proofs = proofs
   178  	} else {
   179  		txproofs := chain.getMultiLayerProofs(txresult.Height, block.Block.Hash(cfg), block.Block.Txs, txresult.Index)
   180  		txDetail.TxProofs = txproofs
   181  		txDetail.FullHash = block.Block.Txs[txresult.Index].FullHash()
   182  	}
   183  
   184  	setTxDetailFromTxResult(&txDetail, txresult)
   185  	return &txDetail, nil
   186  }
   187  
   188  func setTxDetailFromTxResult(TransactionDetail *types.TransactionDetail, txresult *types.TxResult) {
   189  	TransactionDetail.Receipt = txresult.Receiptdate
   190  	TransactionDetail.Tx = txresult.GetTx()
   191  	TransactionDetail.Height = txresult.GetHeight()
   192  	TransactionDetail.Index = int64(txresult.GetIndex())
   193  	TransactionDetail.Blocktime = txresult.GetBlocktime()
   194  
   195  	//获取Amount
   196  	amount, err := txresult.GetTx().Amount()
   197  	if err != nil {
   198  		// return nil, err
   199  		amount = 0
   200  	}
   201  	TransactionDetail.Amount = amount
   202  	assets, err := txresult.GetTx().Assets()
   203  	if err != nil {
   204  		assets = nil
   205  	}
   206  	TransactionDetail.Assets = assets
   207  	TransactionDetail.ActionName = txresult.GetTx().ActionName()
   208  
   209  	//获取from地址
   210  	TransactionDetail.Fromaddr = txresult.GetTx().From()
   211  }
   212  
   213  //ProcGetAddrOverview 获取addrOverview
   214  //type  AddrOverview {
   215  //	int64 reciver = 1;
   216  //	int64 balance = 2;
   217  //	int64 txCount = 3;}
   218  func (chain *BlockChain) ProcGetAddrOverview(addr *types.ReqAddr) (*types.AddrOverview, error) {
   219  	cfg := chain.client.GetConfig()
   220  	if addr == nil || len(addr.Addr) == 0 {
   221  		chainlog.Error("ProcGetAddrOverview input err!")
   222  		return nil, types.ErrInvalidParam
   223  	}
   224  	chainlog.Debug("ProcGetAddrOverview", "Addr", addr.GetAddr())
   225  
   226  	var addrOverview types.AddrOverview
   227  
   228  	//获取地址的reciver
   229  	amount, err := chain.query.Query(cfg.ExecName("coins"), "GetAddrReciver", addr)
   230  	if err != nil {
   231  		chainlog.Error("ProcGetAddrOverview", "GetAddrReciver err", err)
   232  		addrOverview.Reciver = 0
   233  	} else {
   234  		addrOverview.Reciver = amount.(*types.Int64).GetData()
   235  	}
   236  	if err != nil && err != types.ErrEmpty {
   237  		return nil, err
   238  	}
   239  
   240  	var reqkey types.ReqKey
   241  
   242  	//新的代码不支持PrefixCount查询地址交易计数,executor/localdb.go PrefixCount
   243  	//现有的节点都已经升级了localdb,也就是都支持通过GetAddrTxsCount来获取地址交易计数
   244  	reqkey.Key = []byte(fmt.Sprintf("AddrTxsCount:%s", addr.Addr))
   245  	count, err := chain.query.Query(cfg.ExecName("coins"), "GetAddrTxsCount", &reqkey)
   246  	if err != nil {
   247  		chainlog.Error("ProcGetAddrOverview", "GetAddrTxsCount err", err)
   248  		addrOverview.TxCount = 0
   249  	} else {
   250  		addrOverview.TxCount = count.(*types.Int64).GetData()
   251  	}
   252  	chainlog.Debug("GetAddrTxsCount", "TxCount ", addrOverview.TxCount)
   253  
   254  	return &addrOverview, nil
   255  }
   256  
   257  //getTxFullHashProofs 获取指定txinde在txs中的proof, ForkRootHash之后使用fullhash来计算
   258  func getTxFullHashProofs(Txs []*types.Transaction, index int32) [][]byte {
   259  	txlen := len(Txs)
   260  	leaves := make([][]byte, txlen)
   261  
   262  	for index, tx := range Txs {
   263  		leaves[index] = tx.FullHash()
   264  	}
   265  
   266  	proofs := merkle.GetMerkleBranch(leaves, uint32(index))
   267  
   268  	return proofs
   269  }
   270  
   271  //获取指定交易在子链中的路径证明,使用fullhash
   272  func (chain *BlockChain) getMultiLayerProofs(height int64, blockHash []byte, Txs []*types.Transaction, index int32) []*types.TxProof {
   273  	var proofs []*types.TxProof
   274  
   275  	//平行链节点上的交易都是单层merkle树,使用FullHash直接计算即可
   276  	if chain.isParaChain {
   277  		txProofs := getTxFullHashProofs(Txs, index)
   278  		proof := types.TxProof{Proofs: txProofs, Index: uint32(index)}
   279  		proofs = append(proofs, &proof)
   280  		return proofs
   281  	}
   282  
   283  	//主链节点的处理
   284  	title, haveParaTx := types.GetParaExecTitleName(string(Txs[index].Execer))
   285  	if !haveParaTx {
   286  		title = types.MainChainName
   287  	}
   288  
   289  	replyparaTxs, err := chain.LoadParaTxByHeight(height, "", 0, 1)
   290  	if err != nil || 0 == len(replyparaTxs.Items) {
   291  		filterlog.Error("getMultiLayerProofs", "height", height, "blockHash", common.ToHex(blockHash), "err", err)
   292  		return nil
   293  	}
   294  
   295  	//获取本子链的第一笔交易的index值,以及最后一笔交易的index值
   296  	var startIndex int32
   297  	var childIndex uint32
   298  	var hashes [][]byte
   299  	var exist bool
   300  	var childHash []byte
   301  	var txCount int32
   302  
   303  	for _, paratx := range replyparaTxs.Items {
   304  		if title == paratx.Title && bytes.Equal(blockHash, paratx.GetHash()) {
   305  			startIndex = paratx.GetStartIndex()
   306  			childIndex = paratx.ChildHashIndex
   307  			childHash = paratx.ChildHash
   308  			txCount = paratx.GetTxCount()
   309  			exist = true
   310  		}
   311  		hashes = append(hashes, paratx.ChildHash)
   312  	}
   313  	//只有主链的交易,没有其他平行链的交易
   314  	if len(replyparaTxs.Items) == 1 && startIndex == 0 && childIndex == 0 {
   315  		txProofs := getTxFullHashProofs(Txs, index)
   316  		proof := types.TxProof{Proofs: txProofs, Index: uint32(index)}
   317  		proofs = append(proofs, &proof)
   318  		return proofs
   319  	}
   320  
   321  	endindex := startIndex + txCount
   322  	//不存在或者获取到的索引错误直接返回
   323  	if !exist || startIndex > index || endindex > int32(len(Txs)) || childIndex >= uint32(len(replyparaTxs.Items)) {
   324  		filterlog.Error("getMultiLayerProofs", "height", height, "blockHash", common.ToHex(blockHash), "exist", exist, "replyparaTxs", replyparaTxs)
   325  		filterlog.Error("getMultiLayerProofs", "startIndex", startIndex, "index", index, "childIndex", childIndex)
   326  		return nil
   327  	}
   328  
   329  	//主链和平行链交易都存在,获取本子链所有交易的hash值
   330  	var childHashes [][]byte
   331  	for i := startIndex; i < endindex; i++ {
   332  		childHashes = append(childHashes, Txs[i].FullHash())
   333  	}
   334  	txOnChildIndex := index - startIndex
   335  
   336  	//计算单笔交易在子链中的路径证明
   337  	txOnChildBranch := merkle.GetMerkleBranch(childHashes, uint32(txOnChildIndex))
   338  	txproof := types.TxProof{Proofs: txOnChildBranch, Index: uint32(txOnChildIndex), RootHash: childHash}
   339  	proofs = append(proofs, &txproof)
   340  
   341  	//子链在整个区块中的路径证明
   342  	childBranch := merkle.GetMerkleBranch(hashes, childIndex)
   343  	childproof := types.TxProof{Proofs: childBranch, Index: childIndex}
   344  	proofs = append(proofs, &childproof)
   345  	return proofs
   346  }