hermez-node/api/txspool.go
api/txspool.goRaw
1package api
2
3import (
4 "errors"
5 "math/big"
6 "net/http"
7
8 ethCommon "github.com/ethereum/go-ethereum/common"
9 "github.com/gin-gonic/gin"
10 "github.com/hermeznetwork/hermez-node/apitypes"
11 "github.com/hermeznetwork/hermez-node/common"
12 "github.com/hermeznetwork/hermez-node/db/l2db"
13 "github.com/iden3/go-iden3-crypto/babyjub"
14)
15
16func postPoolTx(c *gin.Context) {
17 // Parse body
18 var receivedTx receivedPoolTx
19 if err := c.ShouldBindJSON(&receivedTx); err != nil {
20 retBadReq(err, c)
21 return
22 }
23 // Transform from received to insert format and validate
24 writeTx := receivedTx.toPoolL2TxWrite()
25 if err := verifyPoolL2TxWrite(writeTx); err != nil {
26 retBadReq(err, c)
27 return
28 }
29 // Insert to DB
30 if err := l2.AddTx(writeTx); err != nil {
31 retSQLErr(err, c)
32 return
33 }
34 // Return TxID
35 c.JSON(http.StatusOK, writeTx.TxID.String())
36}
37
38func getPoolTx(c *gin.Context) {
39 // Get TxID
40 txID, err := parseParamTxID(c)
41 if err != nil {
42 retBadReq(err, c)
43 return
44 }
45 // Fetch tx from l2DB
46 tx, err := l2.GetTxAPI(txID)
47 if err != nil {
48 retSQLErr(err, c)
49 return
50 }
51 // Build succesfull response
52 c.JSON(http.StatusOK, tx)
53}
54
55type receivedPoolTx struct {
56 TxID common.TxID `json:"id" binding:"required"`
57 Type common.TxType `json:"type" binding:"required"`
58 TokenID common.TokenID `json:"tokenId"`
59 FromIdx apitypes.StrHezIdx `json:"fromAccountIndex" binding:"required"`
60 ToIdx *apitypes.StrHezIdx `json:"toAccountIndex"`
61 ToEthAddr *apitypes.StrHezEthAddr `json:"toHezEthereumAddress"`
62 ToBJJ *apitypes.StrHezBJJ `json:"toBjj"`
63 Amount apitypes.StrBigInt `json:"amount" binding:"required"`
64 Fee common.FeeSelector `json:"fee"`
65 Nonce common.Nonce `json:"nonce"`
66 Signature babyjub.SignatureComp `json:"signature" binding:"required"`
67 RqFromIdx *apitypes.StrHezIdx `json:"requestFromAccountIndex"`
68 RqToIdx *apitypes.StrHezIdx `json:"requestToAccountIndex"`
69 RqToEthAddr *apitypes.StrHezEthAddr `json:"requestToHezEthereumAddress"`
70 RqToBJJ *apitypes.StrHezBJJ `json:"requestToBjj"`
71 RqTokenID *common.TokenID `json:"requestTokenId"`
72 RqAmount *apitypes.StrBigInt `json:"requestAmount"`
73 RqFee *common.FeeSelector `json:"requestFee"`
74 RqNonce *common.Nonce `json:"requestNonce"`
75}
76
77func (tx *receivedPoolTx) toPoolL2TxWrite() *l2db.PoolL2TxWrite {
78 f := new(big.Float).SetInt((*big.Int)(&tx.Amount))
79 amountF, _ := f.Float64()
80 return &l2db.PoolL2TxWrite{
81 TxID: tx.TxID,
82 FromIdx: common.Idx(tx.FromIdx),
83 ToIdx: (*common.Idx)(tx.ToIdx),
84 ToEthAddr: (*ethCommon.Address)(tx.ToEthAddr),
85 ToBJJ: (*babyjub.PublicKey)(tx.ToBJJ),
86 TokenID: tx.TokenID,
87 Amount: (*big.Int)(&tx.Amount),
88 AmountFloat: amountF,
89 Fee: tx.Fee,
90 Nonce: tx.Nonce,
91 State: common.PoolL2TxStatePending,
92 Signature: tx.Signature,
93 RqFromIdx: (*common.Idx)(tx.RqFromIdx),
94 RqToIdx: (*common.Idx)(tx.RqToIdx),
95 RqToEthAddr: (*ethCommon.Address)(tx.RqToEthAddr),
96 RqToBJJ: (*babyjub.PublicKey)(tx.RqToBJJ),
97 RqTokenID: tx.RqTokenID,
98 RqAmount: (*big.Int)(tx.RqAmount),
99 RqFee: tx.RqFee,
100 RqNonce: tx.RqNonce,
101 Type: tx.Type,
102 }
103}
104
105func verifyPoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
106 poolTx := common.PoolL2Tx{
107 TxID: txw.TxID,
108 FromIdx: txw.FromIdx,
109 ToBJJ: txw.ToBJJ,
110 TokenID: txw.TokenID,
111 Amount: txw.Amount,
112 Fee: txw.Fee,
113 Nonce: txw.Nonce,
114 // State: txw.State,
115 Signature: txw.Signature,
116 RqToBJJ: txw.RqToBJJ,
117 RqAmount: txw.RqAmount,
118 Type: txw.Type,
119 }
120 // ToIdx
121 if txw.ToIdx != nil {
122 poolTx.ToIdx = *txw.ToIdx
123 }
124 // ToEthAddr
125 if txw.ToEthAddr == nil {
126 poolTx.ToEthAddr = common.EmptyAddr
127 } else {
128 poolTx.ToEthAddr = *txw.ToEthAddr
129 }
130 // RqFromIdx
131 if txw.RqFromIdx != nil {
132 poolTx.RqFromIdx = *txw.RqFromIdx
133 }
134 // RqToIdx
135 if txw.RqToIdx != nil {
136 poolTx.RqToIdx = *txw.RqToIdx
137 }
138 // RqToEthAddr
139 if txw.RqToEthAddr == nil {
140 poolTx.RqToEthAddr = common.EmptyAddr
141 } else {
142 poolTx.RqToEthAddr = *txw.RqToEthAddr
143 }
144 // RqTokenID
145 if txw.RqTokenID != nil {
146 poolTx.RqTokenID = *txw.RqTokenID
147 }
148 // RqFee
149 if txw.RqFee != nil {
150 poolTx.RqFee = *txw.RqFee
151 }
152 // RqNonce
153 if txw.RqNonce != nil {
154 poolTx.RqNonce = *txw.RqNonce
155 }
156 // Check type and id
157 _, err := common.NewPoolL2Tx(&poolTx)
158 if err != nil {
159 return err
160 }
161 // Get public key
162 account, err := s.GetAccount(poolTx.FromIdx)
163 if err != nil {
164 return err
165 }
166 // Validate feeAmount
167 _, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
168 if err != nil {
169 return err
170 }
171 // Check signature
172 if !poolTx.VerifySignature(account.PublicKey) {
173 return errors.New("wrong signature")
174 }
175 return nil
176}