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