arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/api/batch_test.go
api/batch_test.goRaw
  1package api
  2
  3import (
  4	"fmt"
  5	"strconv"
  6	"testing"
  7	"time"
  8
  9	ethCommon "github.com/ethereum/go-ethereum/common"
 10	"github.com/hermeznetwork/hermez-node/common"
 11	"github.com/hermeznetwork/hermez-node/db/historydb"
 12	"github.com/mitchellh/copystructure"
 13	"github.com/stretchr/testify/assert"
 14)
 15
 16type testBatch struct {
 17	ItemID        uint64                    `json:"itemId"`
 18	BatchNum      common.BatchNum           `json:"batchNum"`
 19	EthBlockNum   int64                     `json:"ethereumBlockNum"`
 20	EthBlockHash  ethCommon.Hash            `json:"ethereumBlockHash"`
 21	Timestamp     time.Time                 `json:"timestamp"`
 22	ForgerAddr    ethCommon.Address         `json:"forgerAddr"`
 23	CollectedFees map[common.TokenID]string `json:"collectedFees"`
 24	TotalFeesUSD  *float64                  `json:"historicTotalCollectedFeesUSD"`
 25	StateRoot     string                    `json:"stateRoot"`
 26	NumAccounts   int                       `json:"numAccounts"`
 27	ExitRoot      string                    `json:"exitRoot"`
 28	ForgeL1TxsNum *int64                    `json:"forgeL1TransactionsNum"`
 29	SlotNum       int64                     `json:"slotNum"`
 30	ForgedTxs     int                       `json:"forgedTransactions"`
 31}
 32type testBatchesResponse struct {
 33	Batches      []testBatch `json:"batches"`
 34	PendingItems uint64      `json:"pendingItems"`
 35}
 36
 37func (t testBatchesResponse) GetPending() (pendingItems, lastItemID uint64) {
 38	pendingItems = t.PendingItems
 39	lastItemID = t.Batches[len(t.Batches)-1].ItemID
 40	return pendingItems, lastItemID
 41}
 42
 43func (t testBatchesResponse) Len() int {
 44	return len(t.Batches)
 45}
 46
 47func (t testBatchesResponse) New() Pendinger { return &testBatchesResponse{} }
 48
 49type testFullBatch struct {
 50	Batch testBatch `json:"batch"`
 51	Txs   []testTx  `json:"transactions"`
 52}
 53
 54func genTestBatches(
 55	blocks []common.Block,
 56	cBatches []common.Batch,
 57	txs []testTx,
 58) ([]testBatch, []testFullBatch) {
 59	tBatches := []testBatch{}
 60	for i := 0; i < len(cBatches); i++ {
 61		block := common.Block{}
 62		found := false
 63		for _, b := range blocks {
 64			if b.Num == cBatches[i].EthBlockNum {
 65				block = b
 66				found = true
 67				break
 68			}
 69		}
 70		if !found {
 71			panic("block not found")
 72		}
 73		collectedFees := make(map[common.TokenID]string)
 74		for k, v := range cBatches[i].CollectedFees {
 75			collectedFees[k] = v.String()
 76		}
 77		forgedTxs := 0
 78		for _, tx := range txs {
 79			if tx.BatchNum != nil && *tx.BatchNum == cBatches[i].BatchNum {
 80				forgedTxs++
 81			}
 82		}
 83		tBatch := testBatch{
 84			BatchNum:      cBatches[i].BatchNum,
 85			EthBlockNum:   cBatches[i].EthBlockNum,
 86			EthBlockHash:  block.Hash,
 87			Timestamp:     block.Timestamp,
 88			ForgerAddr:    cBatches[i].ForgerAddr,
 89			CollectedFees: collectedFees,
 90			TotalFeesUSD:  cBatches[i].TotalFeesUSD,
 91			StateRoot:     cBatches[i].StateRoot.String(),
 92			NumAccounts:   cBatches[i].NumAccounts,
 93			ExitRoot:      cBatches[i].ExitRoot.String(),
 94			ForgeL1TxsNum: cBatches[i].ForgeL1TxsNum,
 95			SlotNum:       cBatches[i].SlotNum,
 96			ForgedTxs:     forgedTxs,
 97		}
 98		tBatches = append(tBatches, tBatch)
 99	}
100	fullBatches := []testFullBatch{}
101	for i := 0; i < len(tBatches); i++ {
102		forgedTxs := []testTx{}
103		for j := 0; j < len(txs); j++ {
104			if txs[j].BatchNum != nil && *txs[j].BatchNum == tBatches[i].BatchNum {
105				forgedTxs = append(forgedTxs, txs[j])
106			}
107		}
108		fullBatches = append(fullBatches, testFullBatch{
109			Batch: tBatches[i],
110			Txs:   forgedTxs,
111		})
112	}
113	return tBatches, fullBatches
114}
115
116func TestGetBatches(t *testing.T) {
117	endpoint := apiURL + "batches"
118	fetchedBatches := []testBatch{}
119	appendIter := func(intr interface{}) {
120		for i := 0; i < len(intr.(*testBatchesResponse).Batches); i++ {
121			tmp, err := copystructure.Copy(intr.(*testBatchesResponse).Batches[i])
122			if err != nil {
123				panic(err)
124			}
125			fetchedBatches = append(fetchedBatches, tmp.(testBatch))
126		}
127	}
128	// Get all (no filters)
129	limit := 3
130	path := fmt.Sprintf("%s?limit=%d", endpoint, limit)
131	err := doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
132	assert.NoError(t, err)
133	assertBatches(t, tc.batches, fetchedBatches)
134
135	// minBatchNum
136	fetchedBatches = []testBatch{}
137	limit = 2
138	minBatchNum := tc.batches[len(tc.batches)/2].BatchNum
139	path = fmt.Sprintf("%s?minBatchNum=%d&limit=%d", endpoint, minBatchNum, limit)
140	err = doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
141	assert.NoError(t, err)
142	minBatchNumBatches := []testBatch{}
143	for i := 0; i < len(tc.batches); i++ {
144		if tc.batches[i].BatchNum > minBatchNum {
145			minBatchNumBatches = append(minBatchNumBatches, tc.batches[i])
146		}
147	}
148	assertBatches(t, minBatchNumBatches, fetchedBatches)
149
150	// maxBatchNum
151	fetchedBatches = []testBatch{}
152	limit = 1
153	maxBatchNum := tc.batches[len(tc.batches)/2].BatchNum
154	path = fmt.Sprintf("%s?maxBatchNum=%d&limit=%d", endpoint, maxBatchNum, limit)
155	err = doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
156	assert.NoError(t, err)
157	maxBatchNumBatches := []testBatch{}
158	for i := 0; i < len(tc.batches); i++ {
159		if tc.batches[i].BatchNum < maxBatchNum {
160			maxBatchNumBatches = append(maxBatchNumBatches, tc.batches[i])
161		}
162	}
163	assertBatches(t, maxBatchNumBatches, fetchedBatches)
164
165	// slotNum
166	fetchedBatches = []testBatch{}
167	limit = 5
168	slotNum := tc.batches[len(tc.batches)/2].SlotNum
169	path = fmt.Sprintf("%s?slotNum=%d&limit=%d", endpoint, slotNum, limit)
170	err = doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
171	assert.NoError(t, err)
172	slotNumBatches := []testBatch{}
173	for i := 0; i < len(tc.batches); i++ {
174		if tc.batches[i].SlotNum == slotNum {
175			slotNumBatches = append(slotNumBatches, tc.batches[i])
176		}
177	}
178	assertBatches(t, slotNumBatches, fetchedBatches)
179
180	// forgerAddr
181	fetchedBatches = []testBatch{}
182	limit = 10
183	forgerAddr := tc.batches[len(tc.batches)/2].ForgerAddr
184	path = fmt.Sprintf("%s?forgerAddr=%s&limit=%d", endpoint, forgerAddr.String(), limit)
185	err = doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
186	assert.NoError(t, err)
187	forgerAddrBatches := []testBatch{}
188	for i := 0; i < len(tc.batches); i++ {
189		if tc.batches[i].ForgerAddr == forgerAddr {
190			forgerAddrBatches = append(forgerAddrBatches, tc.batches[i])
191		}
192	}
193	assertBatches(t, forgerAddrBatches, fetchedBatches)
194
195	// All, in reverse order
196	fetchedBatches = []testBatch{}
197	limit = 6
198	path = fmt.Sprintf("%s?limit=%d", endpoint, limit)
199	err = doGoodReqPaginated(path, historydb.OrderDesc, &testBatchesResponse{}, appendIter)
200	assert.NoError(t, err)
201	flippedBatches := []testBatch{}
202	for i := len(tc.batches) - 1; i >= 0; i-- {
203		flippedBatches = append(flippedBatches, tc.batches[i])
204	}
205	assertBatches(t, flippedBatches, fetchedBatches)
206
207	// Mixed filters
208	fetchedBatches = []testBatch{}
209	limit = 1
210	maxBatchNum = tc.batches[len(tc.batches)-len(tc.batches)/4].BatchNum
211	minBatchNum = tc.batches[len(tc.batches)/4].BatchNum
212	path = fmt.Sprintf("%s?minBatchNum=%d&maxBatchNum=%d&limit=%d", endpoint, minBatchNum, maxBatchNum, limit)
213	err = doGoodReqPaginated(path, historydb.OrderAsc, &testBatchesResponse{}, appendIter)
214	assert.NoError(t, err)
215	minMaxBatchNumBatches := []testBatch{}
216	for i := 0; i < len(tc.batches); i++ {
217		if tc.batches[i].BatchNum < maxBatchNum && tc.batches[i].BatchNum > minBatchNum {
218			minMaxBatchNumBatches = append(minMaxBatchNumBatches, tc.batches[i])
219		}
220	}
221	assertBatches(t, minMaxBatchNumBatches, fetchedBatches)
222
223	// 400
224	// Invalid minBatchNum
225	path = fmt.Sprintf("%s?minBatchNum=%d", endpoint, -2)
226	err = doBadReq("GET", path, nil, 400)
227	assert.NoError(t, err)
228	// Invalid forgerAddr
229	path = fmt.Sprintf("%s?forgerAddr=%s", endpoint, "0xG0000001")
230	err = doBadReq("GET", path, nil, 400)
231	assert.NoError(t, err)
232	// 404
233	path = fmt.Sprintf("%s?slotNum=%d&minBatchNum=%d", endpoint, 1, 25)
234	err = doBadReq("GET", path, nil, 404)
235	assert.NoError(t, err)
236}
237
238func TestGetBatch(t *testing.T) {
239	endpoint := apiURL + "batches/"
240	for _, batch := range tc.batches {
241		fetchedBatch := testBatch{}
242		assert.NoError(
243			t, doGoodReq(
244				"GET",
245				endpoint+strconv.Itoa(int(batch.BatchNum)),
246				nil, &fetchedBatch,
247			),
248		)
249		assertBatch(t, batch, fetchedBatch)
250	}
251	// 400
252	assert.NoError(t, doBadReq("GET", endpoint+"foo", nil, 400))
253	// 404
254	assert.NoError(t, doBadReq("GET", endpoint+"99999", nil, 404))
255}
256
257func TestGetFullBatch(t *testing.T) {
258	endpoint := apiURL + "full-batches/"
259	for _, fullBatch := range tc.fullBatches {
260		fetchedFullBatch := testFullBatch{}
261		assert.NoError(
262			t, doGoodReq(
263				"GET",
264				endpoint+strconv.Itoa(int(fullBatch.Batch.BatchNum)),
265				nil, &fetchedFullBatch,
266			),
267		)
268		assertBatch(t, fullBatch.Batch, fetchedFullBatch.Batch)
269		assertTxs(t, fullBatch.Txs, fetchedFullBatch.Txs)
270	}
271	// 400
272	assert.NoError(t, doBadReq("GET", endpoint+"foo", nil, 400))
273	// 404
274	assert.NoError(t, doBadReq("GET", endpoint+"99999", nil, 404))
275}
276
277func assertBatches(t *testing.T, expected, actual []testBatch) {
278	assert.Equal(t, len(expected), len(actual))
279	for i := 0; i < len(expected); i++ {
280		assertBatch(t, expected[i], actual[i])
281	}
282}
283
284func assertBatch(t *testing.T, expected, actual testBatch) {
285	assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
286	expected.Timestamp = actual.Timestamp
287	actual.ItemID = expected.ItemID
288	assert.Equal(t, expected, actual)
289}