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