You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
8.9 KiB

  1. package api
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "testing"
  6. "time"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/db/historydb"
  9. "github.com/iden3/go-iden3-crypto/babyjub"
  10. "github.com/stretchr/testify/assert"
  11. )
  12. // testPoolTxReceive is a struct to be used to assert the response
  13. // of GET /transactions-pool/:id
  14. type testPoolTxReceive struct {
  15. TxID common.TxID `json:"id"`
  16. Type common.TxType `json:"type"`
  17. FromIdx string `json:"fromAccountIndex"`
  18. FromEthAddr *string `json:"fromHezEthereumAddress"`
  19. FromBJJ *string `json:"fromBJJ"`
  20. ToIdx *string `json:"toAccountIndex"`
  21. ToEthAddr *string `json:"toHezEthereumAddress"`
  22. ToBJJ *string `json:"toBjj"`
  23. Amount string `json:"amount"`
  24. Fee common.FeeSelector `json:"fee"`
  25. Nonce common.Nonce `json:"nonce"`
  26. State common.PoolL2TxState `json:"state"`
  27. Signature babyjub.SignatureComp `json:"signature"`
  28. RqFromIdx *string `json:"requestFromAccountIndex"`
  29. RqToIdx *string `json:"requestToAccountIndex"`
  30. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  31. RqToBJJ *string `json:"requestToBJJ"`
  32. RqTokenID *common.TokenID `json:"requestTokenId"`
  33. RqAmount *string `json:"requestAmount"`
  34. RqFee *common.FeeSelector `json:"requestFee"`
  35. RqNonce *common.Nonce `json:"requestNonce"`
  36. BatchNum *common.BatchNum `json:"batchNum"`
  37. Timestamp time.Time `json:"timestamp"`
  38. Token historydb.TokenWithUSD `json:"token"`
  39. }
  40. // testPoolTxSend is a struct to be used as a JSON body
  41. // when testing POST /transactions-pool
  42. type testPoolTxSend struct {
  43. TxID common.TxID `json:"id" binding:"required"`
  44. Type common.TxType `json:"type" binding:"required"`
  45. TokenID common.TokenID `json:"tokenId"`
  46. FromIdx string `json:"fromAccountIndex" binding:"required"`
  47. ToIdx *string `json:"toAccountIndex"`
  48. ToEthAddr *string `json:"toHezEthereumAddress"`
  49. ToBJJ *string `json:"toBjj"`
  50. Amount string `json:"amount" binding:"required"`
  51. Fee common.FeeSelector `json:"fee"`
  52. Nonce common.Nonce `json:"nonce"`
  53. Signature babyjub.SignatureComp `json:"signature" binding:"required"`
  54. RqFromIdx *string `json:"requestFromAccountIndex"`
  55. RqToIdx *string `json:"requestToAccountIndex"`
  56. RqToEthAddr *string `json:"requestToHezEthereumAddress"`
  57. RqToBJJ *string `json:"requestToBjj"`
  58. RqTokenID *common.TokenID `json:"requestTokenId"`
  59. RqAmount *string `json:"requestAmount"`
  60. RqFee *common.FeeSelector `json:"requestFee"`
  61. RqNonce *common.Nonce `json:"requestNonce"`
  62. }
  63. func genTestPoolTxs(
  64. poolTxs []common.PoolL2Tx,
  65. tokens []historydb.TokenWithUSD,
  66. accs []common.Account,
  67. ) (poolTxsToSend []testPoolTxSend, poolTxsToReceive []testPoolTxReceive) {
  68. poolTxsToSend = []testPoolTxSend{}
  69. poolTxsToReceive = []testPoolTxReceive{}
  70. for _, poolTx := range poolTxs {
  71. // common.PoolL2Tx ==> testPoolTxSend
  72. token := getTokenByID(poolTx.TokenID, tokens)
  73. genSendTx := testPoolTxSend{
  74. TxID: poolTx.TxID,
  75. Type: poolTx.Type,
  76. TokenID: poolTx.TokenID,
  77. FromIdx: idxToHez(poolTx.FromIdx, token.Symbol),
  78. Amount: poolTx.Amount.String(),
  79. Fee: poolTx.Fee,
  80. Nonce: poolTx.Nonce,
  81. Signature: poolTx.Signature,
  82. RqFee: &poolTx.RqFee,
  83. RqNonce: &poolTx.RqNonce,
  84. }
  85. // common.PoolL2Tx ==> testPoolTxReceive
  86. genReceiveTx := testPoolTxReceive{
  87. TxID: poolTx.TxID,
  88. Type: poolTx.Type,
  89. FromIdx: idxToHez(poolTx.FromIdx, token.Symbol),
  90. Amount: poolTx.Amount.String(),
  91. Fee: poolTx.Fee,
  92. Nonce: poolTx.Nonce,
  93. State: poolTx.State,
  94. Signature: poolTx.Signature,
  95. Timestamp: poolTx.Timestamp,
  96. // BatchNum: poolTx.BatchNum,
  97. RqFee: &poolTx.RqFee,
  98. RqNonce: &poolTx.RqNonce,
  99. Token: token,
  100. }
  101. fromAcc := getAccountByIdx(poolTx.FromIdx, accs)
  102. fromAddr := ethAddrToHez(fromAcc.EthAddr)
  103. genReceiveTx.FromEthAddr = &fromAddr
  104. fromBjj := bjjToString(fromAcc.BJJ)
  105. genReceiveTx.FromBJJ = &fromBjj
  106. if poolTx.ToIdx != 0 {
  107. toIdx := idxToHez(poolTx.ToIdx, token.Symbol)
  108. genSendTx.ToIdx = &toIdx
  109. genReceiveTx.ToIdx = &toIdx
  110. }
  111. if poolTx.ToEthAddr != common.EmptyAddr {
  112. toEth := ethAddrToHez(poolTx.ToEthAddr)
  113. genSendTx.ToEthAddr = &toEth
  114. genReceiveTx.ToEthAddr = &toEth
  115. } else if poolTx.ToIdx > 255 {
  116. acc := getAccountByIdx(poolTx.ToIdx, accs)
  117. addr := ethAddrToHez(acc.EthAddr)
  118. genReceiveTx.ToEthAddr = &addr
  119. }
  120. if poolTx.ToBJJ != common.EmptyBJJComp {
  121. toBJJ := bjjToString(poolTx.ToBJJ)
  122. genSendTx.ToBJJ = &toBJJ
  123. genReceiveTx.ToBJJ = &toBJJ
  124. } else if poolTx.ToIdx > 255 {
  125. acc := getAccountByIdx(poolTx.ToIdx, accs)
  126. bjj := bjjToString(acc.BJJ)
  127. genReceiveTx.ToBJJ = &bjj
  128. }
  129. if poolTx.RqFromIdx != 0 {
  130. rqFromIdx := idxToHez(poolTx.RqFromIdx, token.Symbol)
  131. genSendTx.RqFromIdx = &rqFromIdx
  132. genReceiveTx.RqFromIdx = &rqFromIdx
  133. genSendTx.RqTokenID = &token.TokenID
  134. genReceiveTx.RqTokenID = &token.TokenID
  135. rqAmount := poolTx.RqAmount.String()
  136. genSendTx.RqAmount = &rqAmount
  137. genReceiveTx.RqAmount = &rqAmount
  138. if poolTx.RqToIdx != 0 {
  139. rqToIdx := idxToHez(poolTx.RqToIdx, token.Symbol)
  140. genSendTx.RqToIdx = &rqToIdx
  141. genReceiveTx.RqToIdx = &rqToIdx
  142. }
  143. if poolTx.RqToEthAddr != common.EmptyAddr {
  144. rqToEth := ethAddrToHez(poolTx.RqToEthAddr)
  145. genSendTx.RqToEthAddr = &rqToEth
  146. genReceiveTx.RqToEthAddr = &rqToEth
  147. }
  148. if poolTx.RqToBJJ != common.EmptyBJJComp {
  149. rqToBJJ := bjjToString(poolTx.RqToBJJ)
  150. genSendTx.RqToBJJ = &rqToBJJ
  151. genReceiveTx.RqToBJJ = &rqToBJJ
  152. }
  153. }
  154. poolTxsToSend = append(poolTxsToSend, genSendTx)
  155. poolTxsToReceive = append(poolTxsToReceive, genReceiveTx)
  156. }
  157. return poolTxsToSend, poolTxsToReceive
  158. }
  159. func TestPoolTxs(t *testing.T) {
  160. // POST
  161. endpoint := apiURL + "transactions-pool"
  162. fetchedTxID := common.TxID{}
  163. for _, tx := range tc.poolTxsToSend {
  164. jsonTxBytes, err := json.Marshal(tx)
  165. assert.NoError(t, err)
  166. jsonTxReader := bytes.NewReader(jsonTxBytes)
  167. assert.NoError(
  168. t, doGoodReq(
  169. "POST",
  170. endpoint,
  171. jsonTxReader, &fetchedTxID,
  172. ),
  173. )
  174. assert.Equal(t, tx.TxID, fetchedTxID)
  175. }
  176. // 400
  177. // Wrong fee
  178. badTx := tc.poolTxsToSend[0]
  179. badTx.Amount = "99950000000000000"
  180. badTx.Fee = 255
  181. jsonTxBytes, err := json.Marshal(badTx)
  182. assert.NoError(t, err)
  183. jsonTxReader := bytes.NewReader(jsonTxBytes)
  184. err = doBadReq("POST", endpoint, jsonTxReader, 400)
  185. assert.NoError(t, err)
  186. // Wrong signature
  187. badTx = tc.poolTxsToSend[0]
  188. badTx.FromIdx = "hez:foo:1000"
  189. jsonTxBytes, err = json.Marshal(badTx)
  190. assert.NoError(t, err)
  191. jsonTxReader = bytes.NewReader(jsonTxBytes)
  192. err = doBadReq("POST", endpoint, jsonTxReader, 400)
  193. assert.NoError(t, err)
  194. // Wrong to
  195. badTx = tc.poolTxsToSend[0]
  196. ethAddr := "hez:0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
  197. badTx.ToEthAddr = &ethAddr
  198. badTx.ToIdx = nil
  199. jsonTxBytes, err = json.Marshal(badTx)
  200. assert.NoError(t, err)
  201. jsonTxReader = bytes.NewReader(jsonTxBytes)
  202. err = doBadReq("POST", endpoint, jsonTxReader, 400)
  203. assert.NoError(t, err)
  204. // Wrong rq
  205. badTx = tc.poolTxsToSend[0]
  206. rqFromIdx := "hez:foo:30"
  207. badTx.RqFromIdx = &rqFromIdx
  208. jsonTxBytes, err = json.Marshal(badTx)
  209. assert.NoError(t, err)
  210. jsonTxReader = bytes.NewReader(jsonTxBytes)
  211. err = doBadReq("POST", endpoint, jsonTxReader, 400)
  212. assert.NoError(t, err)
  213. // GET
  214. endpoint += "/"
  215. for _, tx := range tc.poolTxsToReceive {
  216. fetchedTx := testPoolTxReceive{}
  217. assert.NoError(
  218. t, doGoodReq(
  219. "GET",
  220. endpoint+tx.TxID.String(),
  221. nil, &fetchedTx,
  222. ),
  223. )
  224. assertPoolTx(t, tx, fetchedTx)
  225. }
  226. // 400, due invalid TxID
  227. err = doBadReq("GET", endpoint+"0xG2241b6f2b1dd772dba391f4a1a3407c7c21f598d86e2585a14e616fb4a255f823", nil, 400)
  228. assert.NoError(t, err)
  229. // 404, due inexistent TxID in DB
  230. err = doBadReq("GET", endpoint+"0x02241b6f2b1dd772dba391f4a1a3407c7c21f598d86e2585a14e616fb4a255f823", nil, 404)
  231. assert.NoError(t, err)
  232. }
  233. func assertPoolTx(t *testing.T, expected, actual testPoolTxReceive) {
  234. // state should be pending
  235. assert.Equal(t, common.PoolL2TxStatePending, actual.State)
  236. expected.State = actual.State
  237. actual.Token.ItemID = 0
  238. // timestamp should be very close to now
  239. assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
  240. expected.Timestamp = actual.Timestamp
  241. // token timestamp
  242. if expected.Token.USDUpdate == nil {
  243. assert.Equal(t, expected.Token.USDUpdate, actual.Token.USDUpdate)
  244. } else {
  245. assert.Equal(t, expected.Token.USDUpdate.Unix(), actual.Token.USDUpdate.Unix())
  246. expected.Token.USDUpdate = actual.Token.USDUpdate
  247. }
  248. assert.Equal(t, expected, actual)
  249. }