-
Notifications
You must be signed in to change notification settings - Fork 101
/
odr_tx.go
119 lines (94 loc) · 3.07 KB
/
odr_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
/**
* @file
* @copyright defined in go-seele/LICENSE
*/
package light
import (
"github.com/seeleteam/go-seele/api"
"github.com/seeleteam/go-seele/common"
"github.com/seeleteam/go-seele/common/errors"
"github.com/seeleteam/go-seele/core/store"
"github.com/seeleteam/go-seele/core/types"
)
// ODR object to send tx.
type odrAddTx struct {
OdrItem
Tx types.Transaction
}
func (odr *odrAddTx) code() uint16 {
return addTxRequestCode
}
func (odr *odrAddTx) handle(lp *LightProtocol) (uint16, odrResponse) {
if err := lp.txPool.AddTransaction(&odr.Tx); err != nil {
odr.Error = errors.NewStackedError(err, "failed to add tx").Error()
}
return addTxResponseCode, odr
}
func (odr *odrAddTx) validate(request odrRequest, bcStore store.BlockchainStore) error {
return nil
}
// ODR object to get transaction by hash.
type odrTxByHashRequest struct {
OdrItem
TxHash common.Hash
}
type odrTxByHashResponse struct {
OdrProvableResponse
Tx *types.Transaction `rlp:"nil"`
}
func (req *odrTxByHashRequest) code() uint16 {
return txByHashRequestCode
}
func (req *odrTxByHashRequest) handle(lp *LightProtocol) (uint16, odrResponse) {
var err error
var result odrTxByHashResponse
result.Tx, result.BlockIndex, err = api.GetTransaction(lp.txPool, lp.chain.GetStore(), req.TxHash)
result.ReqID = req.ReqID
if err != nil {
err = errors.NewStackedErrorf(err, "failed to get tx by hash %v", req.TxHash)
return newErrorResponse(txByHashResponseCode, req.ReqID, err)
}
if result.Tx != nil && result.BlockIndex != nil && !result.BlockIndex.BlockHash.IsEmpty() {
block, err := lp.chain.GetStore().GetBlock(result.BlockIndex.BlockHash)
if err != nil {
err = errors.NewStackedErrorf(err, "failed to get block by hash %v", result.BlockIndex.BlockHash)
return newErrorResponse(txByHashResponseCode, req.ReqID, err)
}
txTrie := types.GetTxTrie(block.Transactions)
proof, err := txTrie.GetProof(req.TxHash.Bytes())
if err != nil {
err = errors.NewStackedError(err, "failed to get tx trie proof")
return newErrorResponse(txByHashResponseCode, req.ReqID, err)
}
result.Proof = mapToArray(proof)
}
return txByHashResponseCode, &result
}
func (response *odrTxByHashResponse) validateUnpackedTx(txHash common.Hash) error {
if response.Tx == nil {
return nil
}
if !txHash.Equal(response.Tx.Hash) {
return types.ErrHashMismatch
}
if err := response.Tx.ValidateWithoutState(true, false); err != nil {
return errors.NewStackedError(err, "failed to validate tx without state")
}
return nil
}
func (response *odrTxByHashResponse) validate(request odrRequest, bcStore store.BlockchainStore) error {
header, err := response.proveHeader(bcStore)
if err != nil {
return errors.NewStackedError(err, "failed to prove block header")
}
txHash := request.(*odrTxByHashRequest).TxHash
// tx not packed yet.
if header == nil {
return response.validateUnpackedTx(txHash)
}
response.Tx = new(types.Transaction)
if err = response.proveMerkleTrie(header.TxHash, txHash.Bytes(), response.Tx); err != nil {
return errors.NewStackedError(err, "failed to prove merkle trie")
}
return nil
}