/
query_tx.go
351 lines (310 loc) · 11.6 KB
/
query_tx.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
// 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 blockchain
import (
"bytes"
"fmt"
"github.com/assetcloud/chain/common"
"github.com/assetcloud/chain/common/merkle"
"github.com/assetcloud/chain/types"
)
// ProcGetTransactionByAddr 获取地址对应的所有交易信息
// 存储格式key:addr:flag:height ,value:txhash
// key=addr :获取本地参与的所有交易
// key=addr:1 :获取本地作为from方的所有交易
// key=addr:2 :获取本地作为to方的所有交易
func (chain *BlockChain) ProcGetTransactionByAddr(addr *types.ReqAddr) (*types.ReplyTxInfos, error) {
if addr == nil || len(addr.Addr) == 0 {
return nil, types.ErrInvalidParam
}
//默认取10笔交易数据
if addr.Count == 0 {
addr.Count = 10
}
if int64(addr.Count) > types.MaxBlockCountPerTime {
return nil, types.ErrMaxCountPerTime
}
//入参数校验
curheigt := chain.GetBlockHeight()
if addr.GetHeight() > curheigt || addr.GetHeight() < -1 {
chainlog.Error("ProcGetTransactionByAddr Height err")
return nil, types.ErrInvalidParam
}
if addr.GetDirection() != 0 && addr.GetDirection() != 1 {
chainlog.Error("ProcGetTransactionByAddr Direction err")
return nil, types.ErrInvalidParam
}
if addr.GetIndex() < 0 || addr.GetIndex() > types.MaxTxsPerBlock {
chainlog.Error("ProcGetTransactionByAddr Index err")
return nil, types.ErrInvalidParam
}
//查询的drivers--> main 驱动的名称
//查询的方法: --> GetTxsByAddr
//查询的参数: --> interface{} 类型
cfg := chain.client.GetConfig()
txinfos, err := chain.query.Query(cfg.ExecName(cfg.GetCoinExec()), "GetTxsByAddr", addr)
if err != nil {
chainlog.Info("ProcGetTransactionByAddr does not exist tx!", "addr", addr, "err", err)
return nil, err
}
return txinfos.(*types.ReplyTxInfos), nil
}
// ProcGetTransactionByHashes 返回类型
//
// type TransactionDetails struct {
// Txs []*Transaction
// }
//
// 通过hashs获取交易详情
func (chain *BlockChain) ProcGetTransactionByHashes(hashs [][]byte) (TxDetails *types.TransactionDetails, err error) {
if int64(len(hashs)) > types.MaxBlockCountPerTime {
return nil, types.ErrMaxCountPerTime
}
var txDetails types.TransactionDetails
for _, txhash := range hashs {
txresult, err := chain.GetTxResultFromDb(txhash)
var txDetail types.TransactionDetail
if err == nil && txresult != nil {
setTxDetailFromTxResult(&txDetail, txresult)
//chainlog.Debug("ProcGetTransactionByHashes", "txDetail", txDetail.String())
txDetails.Txs = append(txDetails.Txs, &txDetail)
} else {
txDetails.Txs = append(txDetails.Txs, &txDetail) //
chainlog.Debug("ProcGetTransactionByHashes hash no exit", "txhash", common.ToHex(txhash))
}
}
return &txDetails, nil
}
// getTxHashProofs 获取指定txindex在txs中的proof ,注释:index从0开始
func getTxHashProofs(Txs []*types.Transaction, index int32) [][]byte {
txlen := len(Txs)
leaves := make([][]byte, txlen)
for index, tx := range Txs {
leaves[index] = tx.Hash()
}
proofs := merkle.GetMerkleBranch(leaves, uint32(index))
chainlog.Debug("getTransactionDetail", "index", index, "proofs", proofs)
return proofs
}
// GetTxResultFromDb 通过txhash 从txindex db中获取tx信息
//
// type TxResult struct {
// Height int64
// Index int32
// Tx *types.Transaction
// Receiptdate *ReceiptData
// }
func (chain *BlockChain) GetTxResultFromDb(txhash []byte) (tx *types.TxResult, err error) {
txinfo, err := chain.blockStore.GetTx(txhash)
if err != nil {
return nil, err
}
return txinfo, nil
}
// HasTx 是否包含该交易
func (chain *BlockChain) HasTx(txhash []byte, txHeight int64) (has bool, err error) {
if txHeight > 0 {
return chain.txHeightCache.Contains(txhash, txHeight), nil
}
return chain.blockStore.HasTx(txhash)
}
// GetDuplicateTxHashList 获取重复的交易
func (chain *BlockChain) GetDuplicateTxHashList(txhashlist *types.TxHashList) (duptxhashlist *types.TxHashList, err error) {
var dupTxHashList types.TxHashList
//onlyquerycache := false
//FIXME:这里Count实际传的是区块高度的值,代码中没找到-1的传参,不清楚具体含义
//对于非txHeight类交易,直接查询数据库,不会有影响,暂时先注释
//if txhashlist.Count == -1 {
// onlyquerycache = true
//}
if txhashlist.Expire != nil && len(txhashlist.Expire) != len(txhashlist.Hashes) {
return nil, types.ErrInvalidParam
}
cfg := chain.client.GetConfig()
for i, txhash := range txhashlist.Hashes {
expire := int64(0)
if txhashlist.Expire != nil {
expire = txhashlist.Expire[i]
}
txHeight := types.GetTxHeight(cfg, expire, txhashlist.Count)
has, err := chain.HasTx(txhash, txHeight)
if err == nil && has {
dupTxHashList.Hashes = append(dupTxHashList.Hashes, txhash)
}
}
return &dupTxHashList, nil
}
/*
ProcQueryTxMsg 函数功能:
EventQueryTx(types.ReqHash) : rpc模块会向 blockchain 模块 发送 EventQueryTx(types.ReqHash) 消息 ,
查询交易的默克尔树,回复消息 EventTransactionDetail(types.TransactionDetail)
结构体:
type ReqHash struct {Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`}
type TransactionDetail struct {Hashs [][]byte `protobuf:"bytes,1,rep,name=hashs,proto3" json:"hashs,omitempty"}
*/
func (chain *BlockChain) ProcQueryTxMsg(txhash []byte) (proof *types.TransactionDetail, err error) {
txresult, err := chain.GetTxResultFromDb(txhash)
if err != nil {
return nil, err
}
block, err := chain.GetBlock(txresult.Height)
if err != nil {
return nil, err
}
var txDetail types.TransactionDetail
cfg := chain.client.GetConfig()
height := block.Block.GetHeight()
if chain.isParaChain {
height = block.Block.GetMainHeight()
}
//获取指定tx在txlist中的proof,需要区分ForkRootHash前后proof证明数据
if !cfg.IsFork(height, "ForkRootHash") {
proofs := getTxHashProofs(block.Block.Txs, txresult.Index)
txDetail.Proofs = proofs
} else {
txproofs := chain.getMultiLayerProofs(txresult.Height, block.Block.Hash(cfg), block.Block.Txs, txresult.Index)
txDetail.TxProofs = txproofs
txDetail.FullHash = block.Block.Txs[txresult.Index].FullHash()
}
setTxDetailFromTxResult(&txDetail, txresult)
return &txDetail, nil
}
func setTxDetailFromTxResult(TransactionDetail *types.TransactionDetail, txresult *types.TxResult) {
TransactionDetail.Receipt = txresult.Receiptdate
TransactionDetail.Tx = txresult.GetTx()
TransactionDetail.Height = txresult.GetHeight()
TransactionDetail.Index = int64(txresult.GetIndex())
TransactionDetail.Blocktime = txresult.GetBlocktime()
//获取Amount
amount, err := txresult.GetTx().Amount()
if err != nil {
// return nil, err
amount = 0
}
TransactionDetail.Amount = amount
assets, err := txresult.GetTx().Assets()
if err != nil {
assets = nil
}
TransactionDetail.Assets = assets
TransactionDetail.ActionName = txresult.GetTx().ActionName()
//获取from地址
TransactionDetail.Fromaddr = txresult.GetTx().From()
}
// ProcGetAddrOverview 获取addrOverview
//
// type AddrOverview {
// int64 reciver = 1;
// int64 balance = 2;
// int64 txCount = 3;}
func (chain *BlockChain) ProcGetAddrOverview(addr *types.ReqAddr) (*types.AddrOverview, error) {
cfg := chain.client.GetConfig()
if addr == nil || len(addr.Addr) == 0 {
chainlog.Error("ProcGetAddrOverview input err!")
return nil, types.ErrInvalidParam
}
chainlog.Debug("ProcGetAddrOverview", "Addr", addr.GetAddr())
var addrOverview types.AddrOverview
//获取地址的reciver
amount, err := chain.query.Query(cfg.ExecName(cfg.GetCoinExec()), "GetAddrReciver", addr)
if err != nil {
chainlog.Error("ProcGetAddrOverview", "GetAddrReciver err", err)
addrOverview.Reciver = 0
} else {
addrOverview.Reciver = amount.(*types.Int64).GetData()
}
if err != nil && err != types.ErrEmpty {
return nil, err
}
var reqkey types.ReqKey
//新的代码不支持PrefixCount查询地址交易计数,executor/localdb.go PrefixCount
//现有的节点都已经升级了localdb,也就是都支持通过GetAddrTxsCount来获取地址交易计数
reqkey.Key = []byte(fmt.Sprintf("AddrTxsCount:%s", addr.Addr))
count, err := chain.query.Query(cfg.ExecName(cfg.GetCoinExec()), "GetAddrTxsCount", &reqkey)
if err != nil {
chainlog.Error("ProcGetAddrOverview", "GetAddrTxsCount err", err)
addrOverview.TxCount = 0
} else {
addrOverview.TxCount = count.(*types.Int64).GetData()
}
chainlog.Debug("GetAddrTxsCount", "TxCount ", addrOverview.TxCount)
return &addrOverview, nil
}
// getTxFullHashProofs 获取指定txinde在txs中的proof, ForkRootHash之后使用fullhash来计算
func getTxFullHashProofs(Txs []*types.Transaction, index int32) [][]byte {
txlen := len(Txs)
leaves := make([][]byte, txlen)
for index, tx := range Txs {
leaves[index] = tx.FullHash()
}
proofs := merkle.GetMerkleBranch(leaves, uint32(index))
return proofs
}
// 获取指定交易在子链中的路径证明,使用fullhash
func (chain *BlockChain) getMultiLayerProofs(height int64, blockHash []byte, Txs []*types.Transaction, index int32) []*types.TxProof {
var proofs []*types.TxProof
//平行链节点上的交易都是单层merkle树,使用FullHash直接计算即可
if chain.isParaChain {
txProofs := getTxFullHashProofs(Txs, index)
proof := types.TxProof{Proofs: txProofs, Index: uint32(index)}
proofs = append(proofs, &proof)
return proofs
}
//主链节点的处理
title, haveParaTx := types.GetParaExecTitleName(string(Txs[index].Execer))
if !haveParaTx {
title = types.MainChainName
}
replyparaTxs, err := chain.LoadParaTxByHeight(height, "", 0, 1)
if err != nil || 0 == len(replyparaTxs.Items) {
filterlog.Error("getMultiLayerProofs", "height", height, "blockHash", common.ToHex(blockHash), "err", err)
return nil
}
//获取本子链的第一笔交易的index值,以及最后一笔交易的index值
var startIndex int32
var childIndex uint32
var hashes [][]byte
var exist bool
var childHash []byte
var txCount int32
for _, paratx := range replyparaTxs.Items {
if title == paratx.Title && bytes.Equal(blockHash, paratx.GetHash()) {
startIndex = paratx.GetStartIndex()
childIndex = paratx.ChildHashIndex
childHash = paratx.ChildHash
txCount = paratx.GetTxCount()
exist = true
}
hashes = append(hashes, paratx.ChildHash)
}
//只有主链的交易,没有其他平行链的交易
if len(replyparaTxs.Items) == 1 && startIndex == 0 && childIndex == 0 {
txProofs := getTxFullHashProofs(Txs, index)
proof := types.TxProof{Proofs: txProofs, Index: uint32(index)}
proofs = append(proofs, &proof)
return proofs
}
endindex := startIndex + txCount
//不存在或者获取到的索引错误直接返回
if !exist || startIndex > index || endindex > int32(len(Txs)) || childIndex >= uint32(len(replyparaTxs.Items)) {
filterlog.Error("getMultiLayerProofs", "height", height, "blockHash", common.ToHex(blockHash), "exist", exist, "replyparaTxs", replyparaTxs)
filterlog.Error("getMultiLayerProofs", "startIndex", startIndex, "index", index, "childIndex", childIndex)
return nil
}
//主链和平行链交易都存在,获取本子链所有交易的hash值
var childHashes [][]byte
for i := startIndex; i < endindex; i++ {
childHashes = append(childHashes, Txs[i].FullHash())
}
txOnChildIndex := index - startIndex
//计算单笔交易在子链中的路径证明
txOnChildBranch := merkle.GetMerkleBranch(childHashes, uint32(txOnChildIndex))
txproof := types.TxProof{Proofs: txOnChildBranch, Index: uint32(txOnChildIndex), RootHash: childHash}
proofs = append(proofs, &txproof)
//子链在整个区块中的路径证明
childBranch := merkle.GetMerkleBranch(hashes, childIndex)
childproof := types.TxProof{Proofs: childBranch, Index: childIndex}
proofs = append(proofs, &childproof)
return proofs
}