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