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