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