hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
1package historydb
2
3import (
4 "database/sql"
5 "fmt"
6 "math"
7 "math/big"
8 "os"
9 "testing"
10 "time"
11
12 ethCommon "github.com/ethereum/go-ethereum/common"
13 "github.com/hermeznetwork/hermez-node/common"
14 dbUtils "github.com/hermeznetwork/hermez-node/db"
15 "github.com/hermeznetwork/hermez-node/log"
16 "github.com/hermeznetwork/hermez-node/test"
17 "github.com/hermeznetwork/hermez-node/test/til"
18 "github.com/hermeznetwork/tracerr"
19 "github.com/stretchr/testify/assert"
20 "github.com/stretchr/testify/require"
21)
22
23var historyDB *HistoryDB
24
25// In order to run the test you need to run a Posgres DB with
26// a database named "history" that is accessible by
27// user: "hermez"
28// pass: set it using the env var POSTGRES_PASS
29// This can be achieved by running: POSTGRES_PASS=your_strong_pass && sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD=$POSTGRES_PASS -d postgres && sleep 2s && sudo docker exec -it hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
30// After running the test you can stop the container by running: sudo docker kill hermez-db-test
31// If you already did that for the L2DB you don't have to do it again
32
33func TestMain(m *testing.M) {
34 // init DB
35 pass := os.Getenv("POSTGRES_PASS")
36 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
37 if err != nil {
38 panic(err)
39 }
40 historyDB = NewHistoryDB(db)
41 if err != nil {
42 panic(err)
43 }
44 // Run tests
45 result := m.Run()
46 // Close DB
47 if err := db.Close(); err != nil {
48 log.Error("Error closing the history DB:", err)
49 }
50 os.Exit(result)
51}
52
53func TestBlocks(t *testing.T) {
54 var fromBlock, toBlock int64
55 fromBlock = 0
56 toBlock = 7
57 // Reset DB
58 test.WipeDB(historyDB.DB())
59 // Generate blocks using til
60 set1 := `
61 Type: Blockchain
62 // block 0 is stored as default in the DB
63 // block 1 does not exist
64 > block // blockNum=2
65 > block // blockNum=3
66 > block // blockNum=4
67 > block // blockNum=5
68 > block // blockNum=6
69 `
70 tc := til.NewContext(uint16(0), 1)
71 blocks, err := tc.GenerateBlocks(set1)
72 require.NoError(t, err)
73 // Save timestamp of a block with UTC and change it without UTC
74 timestamp := time.Now().Add(time.Second * 13)
75 blocks[fromBlock].Block.Timestamp = timestamp
76 // Insert blocks into DB
77 for i := 0; i < len(blocks); i++ {
78 err := historyDB.AddBlock(&blocks[i].Block)
79 assert.NoError(t, err)
80 }
81 // Add block 0 to the generated blocks
82 blocks = append(
83 []common.BlockData{{Block: test.Block0}}, //nolint:gofmt
84 blocks...,
85 )
86 // Get all blocks from DB
87 fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
88 assert.Equal(t, len(blocks), len(fetchedBlocks))
89 // Compare generated vs getted blocks
90 assert.NoError(t, err)
91 for i := range fetchedBlocks {
92 assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
93 }
94 // Compare saved timestamp vs getted
95 nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
96 zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
97 assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
98 assert.Equal(t, offsetUTC, offsetFetchedBlock)
99 // Get blocks from the DB one by one
100 for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
101 fetchedBlock, err := historyDB.GetBlock(i)
102 assert.NoError(t, err)
103 assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
104 }
105 // Get last block
106 lastBlock, err := historyDB.GetLastBlock()
107 assert.NoError(t, err)
108 assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
109}
110
111func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
112 assert.Equal(t, expected.Num, actual.Num)
113 assert.Equal(t, expected.Hash, actual.Hash)
114 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
115}
116
117func TestBatches(t *testing.T) {
118 // Reset DB
119 test.WipeDB(historyDB.DB())
120 // Generate batches using til (and blocks for foreign key)
121 set := `
122 Type: Blockchain
123
124 AddToken(1) // Will have value in USD
125 AddToken(2) // Will NOT have value in USD
126 CreateAccountDeposit(1) A: 2000
127 CreateAccountDeposit(2) A: 2000
128 CreateAccountDeposit(1) B: 1000
129 CreateAccountDeposit(2) B: 1000
130 > batchL1
131 > batchL1
132 Transfer(1) A-B: 100 (5)
133 Transfer(2) B-A: 100 (199)
134 > batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
135 > block
136 Transfer(1) A-B: 100 (5)
137 > batch // batchNum=3, L2 only batch, forges transfer (with USD value)
138 Transfer(2) B-A: 100 (199)
139 > batch // batchNum=4, L2 only batch, forges transfer (without USD value)
140 > block
141 `
142 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
143 tilCfgExtra := til.ConfigExtra{
144 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
145 CoordUser: "A",
146 }
147 blocks, err := tc.GenerateBlocks(set)
148 require.NoError(t, err)
149 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
150 require.NoError(t, err)
151 // Insert to DB
152 batches := []common.Batch{}
153 tokensValue := make(map[common.TokenID]float64)
154 lastL1TxsNum := new(int64)
155 lastL1BatchBlockNum := int64(0)
156 for _, block := range blocks {
157 // Insert block
158 assert.NoError(t, historyDB.AddBlock(&block.Block))
159 // Insert tokens
160 for i, token := range block.Rollup.AddedTokens {
161 assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
162 if i%2 != 0 {
163 // Set value to the token
164 value := (float64(i) + 5) * 5.389329
165 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
166 tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
167 }
168 }
169 // Combine all generated batches into single array
170 for _, batch := range block.Rollup.Batches {
171 batches = append(batches, batch.Batch)
172 forgeTxsNum := batch.Batch.ForgeL1TxsNum
173 if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
174 *lastL1TxsNum = *forgeTxsNum
175 lastL1BatchBlockNum = batch.Batch.EthBlockNum
176 }
177 }
178 }
179 // Insert batches
180 assert.NoError(t, historyDB.AddBatches(batches))
181 // Set expected total fee
182 for _, batch := range batches {
183 total := .0
184 for tokenID, amount := range batch.CollectedFees {
185 af := new(big.Float).SetInt(amount)
186 amountFloat, _ := af.Float64()
187 total += tokensValue[tokenID] * amountFloat
188 }
189 batch.TotalFeesUSD = &total
190 }
191 // Get batches from the DB
192 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
193 assert.NoError(t, err)
194 assert.Equal(t, len(batches), len(fetchedBatches))
195 for i, fetchedBatch := range fetchedBatches {
196 assert.Equal(t, batches[i], fetchedBatch)
197 }
198 // Test GetLastBatchNum
199 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
200 assert.NoError(t, err)
201 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
202 // Test GetLastL1TxsNum
203 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
204 assert.NoError(t, err)
205 assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
206 // Test GetLastL1BatchBlockNum
207 fetchedLastL1BatchBlockNum, err := historyDB.GetLastL1BatchBlockNum()
208 assert.NoError(t, err)
209 assert.Equal(t, lastL1BatchBlockNum, fetchedLastL1BatchBlockNum)
210}
211
212func TestBids(t *testing.T) {
213 const fromBlock int64 = 1
214 const toBlock int64 = 5
215 // Prepare blocks in the DB
216 blocks := setTestBlocks(fromBlock, toBlock)
217 // Generate fake coordinators
218 const nCoords = 5
219 coords := test.GenCoordinators(nCoords, blocks)
220 err := historyDB.AddCoordinators(coords)
221 assert.NoError(t, err)
222 // Generate fake bids
223 const nBids = 20
224 bids := test.GenBids(nBids, blocks, coords)
225 err = historyDB.AddBids(bids)
226 assert.NoError(t, err)
227 // Fetch bids
228 fetchedBids, err := historyDB.GetAllBids()
229 assert.NoError(t, err)
230 // Compare fetched bids vs generated bids
231 for i, bid := range fetchedBids {
232 assert.Equal(t, bids[i], bid)
233 }
234}
235
236func TestTokens(t *testing.T) {
237 const fromBlock int64 = 1
238 const toBlock int64 = 5
239 // Prepare blocks in the DB
240 blocks := setTestBlocks(fromBlock, toBlock)
241 // Generate fake tokens
242 const nTokens = 5
243 tokens, ethToken := test.GenTokens(nTokens, blocks)
244 err := historyDB.AddTokens(tokens)
245 assert.NoError(t, err)
246 tokens = append([]common.Token{ethToken}, tokens...)
247 limit := uint(10)
248 // Fetch tokens
249 fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
250 assert.NoError(t, err)
251 // Compare fetched tokens vs generated tokens
252 // All the tokens should have USDUpdate setted by the DB trigger
253 for i, token := range fetchedTokens {
254 assert.Equal(t, tokens[i].TokenID, token.TokenID)
255 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
256 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
257 assert.Equal(t, tokens[i].Name, token.Name)
258 assert.Equal(t, tokens[i].Symbol, token.Symbol)
259 assert.Nil(t, token.USD)
260 assert.Nil(t, token.USDUpdate)
261 }
262
263 // Update token value
264 for i, token := range tokens {
265 value := 1.01 * float64(i)
266 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
267 }
268 // Fetch tokens
269 fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
270 assert.NoError(t, err)
271 // Compare fetched tokens vs generated tokens
272 // All the tokens should have USDUpdate setted by the DB trigger
273 for i, token := range fetchedTokens {
274 value := 1.01 * float64(i)
275 assert.Equal(t, value, *token.USD)
276 nameZone, offset := token.USDUpdate.Zone()
277 assert.Equal(t, "UTC", nameZone)
278 assert.Equal(t, 0, offset)
279 }
280}
281
282func TestAccounts(t *testing.T) {
283 const fromBlock int64 = 1
284 const toBlock int64 = 5
285 // Prepare blocks in the DB
286 blocks := setTestBlocks(fromBlock, toBlock)
287 // Generate fake tokens
288 const nTokens = 5
289 tokens, ethToken := test.GenTokens(nTokens, blocks)
290 err := historyDB.AddTokens(tokens)
291 assert.NoError(t, err)
292 tokens = append([]common.Token{ethToken}, tokens...)
293 // Generate fake batches
294 const nBatches = 10
295 batches := test.GenBatches(nBatches, blocks)
296 err = historyDB.AddBatches(batches)
297 assert.NoError(t, err)
298 // Generate fake accounts
299 const nAccounts = 3
300 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
301 err = historyDB.AddAccounts(accs)
302 assert.NoError(t, err)
303 // Fetch accounts
304 fetchedAccs, err := historyDB.GetAllAccounts()
305 assert.NoError(t, err)
306 // Compare fetched accounts vs generated accounts
307 for i, acc := range fetchedAccs {
308 accs[i].Balance = nil
309 assert.Equal(t, accs[i], acc)
310 }
311}
312
313func TestTxs(t *testing.T) {
314 // Reset DB
315 test.WipeDB(historyDB.DB())
316
317 set := `
318 Type: Blockchain
319
320 AddToken(1)
321 AddToken(2)
322 CreateAccountDeposit(1) A: 10
323 CreateAccountDeposit(1) B: 10
324 > batchL1
325 > batchL1
326 > block
327
328 CreateAccountDepositTransfer(1) C-A: 20, 10
329 CreateAccountCoordinator(1) User0
330 > batchL1
331 > batchL1
332 > block
333
334 Deposit(1) B: 10
335 Deposit(1) C: 10
336 Transfer(1) C-A : 10 (1)
337 Transfer(1) B-C : 10 (1)
338 Transfer(1) A-B : 10 (1)
339 Exit(1) A: 10 (1)
340 > batch
341 > block
342
343 DepositTransfer(1) A-B: 10, 10
344 > batchL1
345 > block
346
347 ForceTransfer(1) A-B: 10
348 ForceExit(1) A: 5
349 > batchL1
350 > batchL1
351 > block
352
353 CreateAccountDeposit(2) D: 10
354 > batchL1
355 > block
356
357 CreateAccountDeposit(2) E: 10
358 > batchL1
359 > batchL1
360 > block
361
362 `
363 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
364 tilCfgExtra := til.ConfigExtra{
365 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
366 CoordUser: "A",
367 }
368 blocks, err := tc.GenerateBlocks(set)
369 require.NoError(t, err)
370 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
371 require.NoError(t, err)
372
373 // Sanity check
374 require.Equal(t, 7, len(blocks))
375 require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
376 require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
377 require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
378 require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
379 require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
380 require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
381 require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
382
383 var null *common.BatchNum = nil
384 var txID common.TxID
385
386 // Insert blocks into DB
387 for i := range blocks {
388 if i == len(blocks)-1 {
389 blocks[i].Block.Timestamp = time.Now()
390 dbL1Txs, err := historyDB.GetAllL1UserTxs()
391 assert.NoError(t, err)
392 // Check batch_num is nil before forging
393 assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
394 // Save this TxId
395 txID = dbL1Txs[len(dbL1Txs)-1].TxID
396 }
397 err = historyDB.AddBlockSCData(&blocks[i])
398 assert.NoError(t, err)
399 }
400
401 // Check blocks
402 dbBlocks, err := historyDB.GetAllBlocks()
403 assert.NoError(t, err)
404 assert.Equal(t, len(blocks)+1, len(dbBlocks))
405
406 // Check batches
407 batches, err := historyDB.GetAllBatches()
408 assert.NoError(t, err)
409 assert.Equal(t, 11, len(batches))
410
411 // Check L1 Transactions
412 dbL1Txs, err := historyDB.GetAllL1UserTxs()
413 assert.NoError(t, err)
414 assert.Equal(t, 10, len(dbL1Txs))
415
416 // Tx Type
417 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
418 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
419 assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
420 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
421 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
422 assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
423 assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
424 assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
425 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
426 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
427
428 // Tx ID
429 assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
430 assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
431 assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
432 assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
433 assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
434 assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
435 assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
436 assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
437 assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
438 assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
439
440 // Tx From IDx
441 assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
442 assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
443 assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
444 assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
445 assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
446 assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
447 assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
448 assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
449 assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
450 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
451 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
452 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
453 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
454
455 // Tx to IDx
456 assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
457 assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
458 assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
459
460 // Token ID
461 assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
462 assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
463 assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
464 assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
465 assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
466 assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
467 assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
468 assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
469 assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
470 assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
471
472 // Batch Number
473 var bn common.BatchNum = common.BatchNum(2)
474
475 assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
476 assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
477
478 bn = common.BatchNum(4)
479 assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
480
481 bn = common.BatchNum(7)
482 assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
483 assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
484 assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
485
486 bn = common.BatchNum(8)
487 assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
488 assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
489
490 bn = common.BatchNum(10)
491 assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
492
493 bn = common.BatchNum(11)
494 assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
495
496 // eth_block_num
497 assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
498 assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
499 assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
500 assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
501 assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
502 assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
503 assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
504 assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
505 assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
506 assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
507
508 // User Origin
509 assert.Equal(t, true, dbL1Txs[0].UserOrigin)
510 assert.Equal(t, true, dbL1Txs[1].UserOrigin)
511 assert.Equal(t, true, dbL1Txs[2].UserOrigin)
512 assert.Equal(t, true, dbL1Txs[3].UserOrigin)
513 assert.Equal(t, true, dbL1Txs[4].UserOrigin)
514 assert.Equal(t, true, dbL1Txs[5].UserOrigin)
515 assert.Equal(t, true, dbL1Txs[6].UserOrigin)
516 assert.Equal(t, true, dbL1Txs[7].UserOrigin)
517 assert.Equal(t, true, dbL1Txs[8].UserOrigin)
518 assert.Equal(t, true, dbL1Txs[9].UserOrigin)
519
520 // Deposit Amount
521 assert.Equal(t, big.NewInt(10), dbL1Txs[0].DepositAmount)
522 assert.Equal(t, big.NewInt(10), dbL1Txs[1].DepositAmount)
523 assert.Equal(t, big.NewInt(20), dbL1Txs[2].DepositAmount)
524 assert.Equal(t, big.NewInt(10), dbL1Txs[3].DepositAmount)
525 assert.Equal(t, big.NewInt(10), dbL1Txs[4].DepositAmount)
526 assert.Equal(t, big.NewInt(10), dbL1Txs[5].DepositAmount)
527 assert.Equal(t, big.NewInt(0), dbL1Txs[6].DepositAmount)
528 assert.Equal(t, big.NewInt(0), dbL1Txs[7].DepositAmount)
529 assert.Equal(t, big.NewInt(10), dbL1Txs[8].DepositAmount)
530 assert.Equal(t, big.NewInt(10), dbL1Txs[9].DepositAmount)
531
532 // Check saved txID's batch_num is not nil
533 assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
534 assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
535
536 // Check Coordinator TXs
537 coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
538 assert.NoError(t, err)
539 assert.Equal(t, 1, len(coordTxs))
540 assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
541 assert.Equal(t, false, coordTxs[0].UserOrigin)
542
543 // Check L2 TXs
544 dbL2Txs, err := historyDB.GetAllL2Txs()
545 assert.NoError(t, err)
546 assert.Equal(t, 4, len(dbL2Txs))
547
548 // Tx Type
549 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
550 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
551 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
552 assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
553
554 // Tx ID
555 assert.Equal(t, "0x020000000001030000000000", dbL2Txs[0].TxID.String())
556 assert.Equal(t, "0x020000000001010000000000", dbL2Txs[1].TxID.String())
557 assert.Equal(t, "0x020000000001000000000000", dbL2Txs[2].TxID.String())
558 assert.Equal(t, "0x020000000001000000000001", dbL2Txs[3].TxID.String())
559
560 // Tx From and To IDx
561 assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
562 assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
563 assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
564
565 // Batch Number
566 assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
567 assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
568 assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
569 assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
570
571 // eth_block_num
572 assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
573 assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
574 assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
575
576 // Amount
577 assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
578 assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
579 assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
580 assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
581}
582
583func TestExitTree(t *testing.T) {
584 nBatches := 17
585 blocks := setTestBlocks(1, 10)
586 batches := test.GenBatches(nBatches, blocks)
587 err := historyDB.AddBatches(batches)
588 assert.NoError(t, err)
589 const nTokens = 50
590 tokens, ethToken := test.GenTokens(nTokens, blocks)
591 err = historyDB.AddTokens(tokens)
592 assert.NoError(t, err)
593 tokens = append([]common.Token{ethToken}, tokens...)
594 const nAccounts = 3
595 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
596 assert.NoError(t, historyDB.AddAccounts(accs))
597 exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
598 err = historyDB.AddExitTree(exitTree)
599 assert.NoError(t, err)
600}
601
602func TestGetUnforgedL1UserTxs(t *testing.T) {
603 test.WipeDB(historyDB.DB())
604
605 set := `
606 Type: Blockchain
607 AddToken(1)
608 AddToken(2)
609 AddToken(3)
610
611 CreateAccountDeposit(1) A: 20
612 CreateAccountDeposit(2) A: 20
613 CreateAccountDeposit(1) B: 5
614 CreateAccountDeposit(1) C: 5
615 CreateAccountDeposit(1) D: 5
616
617 > block
618 `
619 tc := til.NewContext(uint16(0), 128)
620 blocks, err := tc.GenerateBlocks(set)
621 require.NoError(t, err)
622 // Sanity check
623 require.Equal(t, 1, len(blocks))
624 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
625
626 toForgeL1TxsNum := int64(1)
627
628 for i := range blocks {
629 err = historyDB.AddBlockSCData(&blocks[i])
630 require.NoError(t, err)
631 }
632
633 l1UserTxs, err := historyDB.GetUnforgedL1UserTxs(toForgeL1TxsNum)
634 require.NoError(t, err)
635 assert.Equal(t, 5, len(l1UserTxs))
636 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
637
638 // No l1UserTxs for this toForgeL1TxsNum
639 l1UserTxs, err = historyDB.GetUnforgedL1UserTxs(2)
640 require.NoError(t, err)
641 assert.Equal(t, 0, len(l1UserTxs))
642}
643
644func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
645 //nolint:govet
646 rollup := &common.RollupVariables{
647 0,
648 big.NewInt(10),
649 12,
650 13,
651 [5]common.BucketParams{},
652 false,
653 }
654 //nolint:govet
655 auction := &common.AuctionVariables{
656 0,
657 ethCommon.BigToAddress(big.NewInt(2)),
658 ethCommon.BigToAddress(big.NewInt(3)),
659 "https://boot.coord.com",
660 [6]*big.Int{
661 big.NewInt(1), big.NewInt(2), big.NewInt(3),
662 big.NewInt(4), big.NewInt(5), big.NewInt(6),
663 },
664 0,
665 2,
666 4320,
667 [3]uint16{10, 11, 12},
668 1000,
669 20,
670 }
671 //nolint:govet
672 wDelayer := &common.WDelayerVariables{
673 0,
674 ethCommon.BigToAddress(big.NewInt(2)),
675 ethCommon.BigToAddress(big.NewInt(3)),
676 13,
677 14,
678 false,
679 }
680 return rollup, auction, wDelayer
681}
682
683func TestSetInitialSCVars(t *testing.T) {
684 test.WipeDB(historyDB.DB())
685 _, _, _, err := historyDB.GetSCVars()
686 assert.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
687 rollup, auction, wDelayer := exampleInitSCVars()
688 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
689 require.NoError(t, err)
690 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
691 require.NoError(t, err)
692 require.Equal(t, rollup, dbRollup)
693 require.Equal(t, auction, dbAuction)
694 require.Equal(t, wDelayer, dbWDelayer)
695}
696
697func TestSetL1UserTxEffectiveAmounts(t *testing.T) {
698 test.WipeDB(historyDB.DB())
699
700 set := `
701 Type: Blockchain
702
703 AddToken(1)
704
705 CreateAccountDeposit(1) A: 2000
706 CreateAccountDeposit(1) B: 500
707 CreateAccountDeposit(1) C: 500
708
709 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{*}
710 > block // blockNum=2
711
712 > batchL1 // forge defined L1UserTxs{*}
713 > block // blockNum=3
714 `
715
716 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
717 tilCfgExtra := til.ConfigExtra{
718 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
719 CoordUser: "A",
720 }
721 blocks, err := tc.GenerateBlocks(set)
722 require.NoError(t, err)
723 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
724 require.NoError(t, err)
725 err = tc.FillBlocksForgedL1UserTxs(blocks)
726 require.NoError(t, err)
727
728 // Add only first block so that the L1UserTxs are not marked as forged
729 for i := range blocks[:1] {
730 err = historyDB.AddBlockSCData(&blocks[i])
731 require.NoError(t, err)
732 }
733 // Add second batch to trigger the update of the batch_num,
734 // while avoiding the implicit call of setL1UserTxEffectiveAmounts
735 err = historyDB.addBlock(historyDB.db, &blocks[1].Block)
736 assert.NoError(t, err)
737 err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch)
738 assert.NoError(t, err)
739 require.NoError(t, err)
740
741 // Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block
742 l1Txs := blocks[1].Rollup.Batches[0].L1UserTxs
743 require.Equal(t, 3, len(l1Txs))
744 // Change some values to test all cases
745 l1Txs[1].EffectiveAmount = big.NewInt(0)
746 l1Txs[2].EffectiveDepositAmount = big.NewInt(0)
747 l1Txs[2].EffectiveAmount = big.NewInt(0)
748 err = historyDB.setL1UserTxEffectiveAmounts(historyDB.db, l1Txs)
749 require.NoError(t, err)
750
751 dbL1Txs, err := historyDB.GetAllL1UserTxs()
752 require.NoError(t, err)
753 for i, tx := range dbL1Txs {
754 log.Infof("%d %v %v", i, tx.EffectiveAmount, tx.EffectiveDepositAmount)
755 assert.NotNil(t, tx.EffectiveAmount)
756 assert.NotNil(t, tx.EffectiveDepositAmount)
757 switch tx.TxID {
758 case l1Txs[0].TxID:
759 assert.Equal(t, l1Txs[0].DepositAmount, tx.EffectiveDepositAmount)
760 assert.Equal(t, l1Txs[0].Amount, tx.EffectiveAmount)
761 case l1Txs[1].TxID:
762 assert.Equal(t, l1Txs[1].DepositAmount, tx.EffectiveDepositAmount)
763 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
764 case l1Txs[2].TxID:
765 assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
766 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
767 }
768 }
769}
770
771func TestUpdateExitTree(t *testing.T) {
772 test.WipeDB(historyDB.DB())
773
774 set := `
775 Type: Blockchain
776
777 AddToken(1)
778
779 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
780 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
781
782 CreateAccountCoordinator(1) A // Idx=256+0=256
783 CreateAccountCoordinator(1) B // Idx=256+1=257
784
785 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
786 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
787 > block // blockNum=2
788
789 ForceExit(1) A: 100
790 ForceExit(1) B: 80
791
792 Exit(1) C: 50 (172)
793 Exit(1) D: 30 (172)
794
795 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
796 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
797 > block // blockNum=3
798
799 > block // blockNum=4 (empty block)
800 > block // blockNum=5 (empty block)
801 `
802
803 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
804 tilCfgExtra := til.ConfigExtra{
805 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
806 CoordUser: "A",
807 }
808 blocks, err := tc.GenerateBlocks(set)
809 require.NoError(t, err)
810 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
811 require.NoError(t, err)
812
813 // Add all blocks except for the last two
814 for i := range blocks[:len(blocks)-2] {
815 err = historyDB.AddBlockSCData(&blocks[i])
816 require.NoError(t, err)
817 }
818
819 // Add withdraws to the second-to-last block, and insert block into the DB
820 block := &blocks[len(blocks)-2]
821 require.Equal(t, int64(4), block.Block.Num)
822 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
823 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
824 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
825 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
826 // )
827 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
828 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
829 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
830 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
831 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
832 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
833 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
834 )
835 err = historyDB.addBlock(historyDB.db, &block.Block)
836 require.NoError(t, err)
837
838 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
839 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
840 require.NoError(t, err)
841
842 // Check that exits in DB match with the expected values
843 dbExits, err := historyDB.GetAllExits()
844 require.NoError(t, err)
845 assert.Equal(t, 4, len(dbExits))
846 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
847 for _, dbExit := range dbExits {
848 dbExitsByIdx[dbExit.AccountIdx] = dbExit
849 }
850 for _, withdraw := range block.Rollup.Withdrawals {
851 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
852 if withdraw.InstantWithdraw {
853 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
854 } else {
855 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
856 }
857 }
858
859 // Add delayed withdraw to the last block, and insert block into the DB
860 block = &blocks[len(blocks)-1]
861 require.Equal(t, int64(5), block.Block.Num)
862 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
863 common.WDelayerTransfer{
864 Owner: tc.UsersByIdx[257].Addr,
865 Token: tokenAddr,
866 Amount: big.NewInt(80),
867 })
868 err = historyDB.addBlock(historyDB.db, &block.Block)
869 require.NoError(t, err)
870
871 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
872 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
873 require.NoError(t, err)
874
875 // Check that delayed withdrawn has been set
876 dbExits, err = historyDB.GetAllExits()
877 require.NoError(t, err)
878 for _, dbExit := range dbExits {
879 dbExitsByIdx[dbExit.AccountIdx] = dbExit
880 }
881 require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
882}
883
884func TestGetBestBidCoordinator(t *testing.T) {
885 test.WipeDB(historyDB.DB())
886
887 rollup, auction, wDelayer := exampleInitSCVars()
888 err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
889 require.NoError(t, err)
890
891 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
892 blocks, err := tc.GenerateBlocks(`
893 Type: Blockchain
894 > block // blockNum=2
895 `)
896 require.NoError(t, err)
897 err = historyDB.AddBlockSCData(&blocks[0])
898 require.NoError(t, err)
899
900 coords := []common.Coordinator{
901 {
902 Bidder: ethCommon.BigToAddress(big.NewInt(1)),
903 Forger: ethCommon.BigToAddress(big.NewInt(2)),
904 EthBlockNum: 2,
905 URL: "foo",
906 },
907 {
908 Bidder: ethCommon.BigToAddress(big.NewInt(3)),
909 Forger: ethCommon.BigToAddress(big.NewInt(4)),
910 EthBlockNum: 2,
911 URL: "bar",
912 },
913 }
914 err = historyDB.addCoordinators(historyDB.db, coords)
915 require.NoError(t, err)
916
917 bids := []common.Bid{
918 {
919 SlotNum: 10,
920 BidValue: big.NewInt(10),
921 EthBlockNum: 2,
922 Bidder: coords[0].Bidder,
923 },
924 {
925 SlotNum: 10,
926 BidValue: big.NewInt(20),
927 EthBlockNum: 2,
928 Bidder: coords[1].Bidder,
929 },
930 }
931
932 err = historyDB.addBids(historyDB.db, bids)
933 require.NoError(t, err)
934
935 forger10, err := historyDB.GetBestBidCoordinator(10)
936 require.NoError(t, err)
937 require.Equal(t, coords[1].Forger, forger10.Forger)
938 require.Equal(t, coords[1].Bidder, forger10.Bidder)
939 require.Equal(t, coords[1].URL, forger10.URL)
940 require.Equal(t, bids[1].SlotNum, forger10.SlotNum)
941 require.Equal(t, bids[1].BidValue, forger10.BidValue)
942 for i := range forger10.DefaultSlotSetBid {
943 require.Equal(t, auction.DefaultSlotSetBid[i], forger10.DefaultSlotSetBid[i])
944 }
945
946 _, err = historyDB.GetBestBidCoordinator(11)
947 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
948}
949
950func TestAddBucketUpdates(t *testing.T) {
951 test.WipeDB(historyDB.DB())
952 const fromBlock int64 = 1
953 const toBlock int64 = 5 + 1
954 setTestBlocks(fromBlock, toBlock)
955
956 bucketUpdates := []common.BucketUpdate{
957 {
958 EthBlockNum: 4,
959 NumBucket: 0,
960 BlockStamp: 4,
961 Withdrawals: big.NewInt(123),
962 },
963 {
964 EthBlockNum: 5,
965 NumBucket: 2,
966 BlockStamp: 5,
967 Withdrawals: big.NewInt(42),
968 },
969 }
970 err := historyDB.addBucketUpdates(historyDB.db, bucketUpdates)
971 require.NoError(t, err)
972 dbBucketUpdates, err := historyDB.GetAllBucketUpdates()
973 require.NoError(t, err)
974 assert.Equal(t, bucketUpdates, dbBucketUpdates)
975}
976
977func TestAddTokenExchanges(t *testing.T) {
978 test.WipeDB(historyDB.DB())
979 const fromBlock int64 = 1
980 const toBlock int64 = 5 + 1
981 setTestBlocks(fromBlock, toBlock)
982
983 tokenExchanges := []common.TokenExchange{
984 {
985 EthBlockNum: 4,
986 Address: ethCommon.BigToAddress(big.NewInt(111)),
987 ValueUSD: 12345,
988 },
989 {
990 EthBlockNum: 5,
991 Address: ethCommon.BigToAddress(big.NewInt(222)),
992 ValueUSD: 67890,
993 },
994 }
995 err := historyDB.addTokenExchanges(historyDB.db, tokenExchanges)
996 require.NoError(t, err)
997 dbTokenExchanges, err := historyDB.GetAllTokenExchanges()
998 require.NoError(t, err)
999 assert.Equal(t, tokenExchanges, dbTokenExchanges)
1000}
1001
1002func TestAddEscapeHatchWithdrawals(t *testing.T) {
1003 test.WipeDB(historyDB.DB())
1004 const fromBlock int64 = 1
1005 const toBlock int64 = 5 + 1
1006 setTestBlocks(fromBlock, toBlock)
1007
1008 escapeHatchWithdrawals := []common.WDelayerEscapeHatchWithdrawal{
1009 {
1010 EthBlockNum: 4,
1011 Who: ethCommon.BigToAddress(big.NewInt(111)),
1012 To: ethCommon.BigToAddress(big.NewInt(222)),
1013 TokenAddr: ethCommon.BigToAddress(big.NewInt(333)),
1014 Amount: big.NewInt(10002),
1015 },
1016 {
1017 EthBlockNum: 5,
1018 Who: ethCommon.BigToAddress(big.NewInt(444)),
1019 To: ethCommon.BigToAddress(big.NewInt(555)),
1020 TokenAddr: ethCommon.BigToAddress(big.NewInt(666)),
1021 Amount: big.NewInt(20003),
1022 },
1023 }
1024 err := historyDB.addEscapeHatchWithdrawals(historyDB.db, escapeHatchWithdrawals)
1025 require.NoError(t, err)
1026 dbEscapeHatchWithdrawals, err := historyDB.GetAllEscapeHatchWithdrawals()
1027 require.NoError(t, err)
1028 assert.Equal(t, escapeHatchWithdrawals, dbEscapeHatchWithdrawals)
1029}
1030
1031func TestGetMetrics(t *testing.T) {
1032 test.WipeDB(historyDB.DB())
1033
1034 set := `
1035 Type: Blockchain
1036
1037 AddToken(1)
1038
1039 CreateAccountDeposit(1) A: 1000 // numTx=1
1040 CreateAccountDeposit(1) B: 2000 // numTx=2
1041 CreateAccountDeposit(1) C: 3000 //numTx=3
1042
1043 // block 0 is stored as default in the DB
1044 // block 1 does not exist
1045 > batchL1 // numBatches=1
1046 > batchL1 // numBatches=2
1047 > block // blockNum=2
1048
1049 Transfer(1) C-A : 10 (1) // numTx=4
1050 > batch // numBatches=3
1051 > block // blockNum=3
1052 Transfer(1) B-C : 10 (1) // numTx=5
1053 > batch // numBatches=5
1054 > block // blockNum=4
1055 Transfer(1) A-B : 10 (1) // numTx=6
1056 > batch // numBatches=5
1057 > block // blockNum=5
1058 Transfer(1) A-B : 10 (1) // numTx=7
1059 > batch // numBatches=6
1060 > block // blockNum=6
1061 `
1062
1063 const numBatches int = 6
1064 const numTx int = 7
1065 const blockNum = 6 - 1
1066
1067 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
1068 tilCfgExtra := til.ConfigExtra{
1069 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
1070 CoordUser: "A",
1071 }
1072 blocks, err := tc.GenerateBlocks(set)
1073 require.NoError(t, err)
1074 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1075 require.NoError(t, err)
1076
1077 // Sanity check
1078 require.Equal(t, blockNum, len(blocks))
1079
1080 // Adding one batch per block
1081 // batch frequency can be chosen
1082 const frequency int = 15
1083
1084 for i := range blocks {
1085 blocks[i].Block.Timestamp = time.Now().Add(-time.Second * time.Duration(frequency*(len(blocks)-i)))
1086 err = historyDB.AddBlockSCData(&blocks[i])
1087 assert.NoError(t, err)
1088 }
1089
1090 res, err := historyDB.GetMetrics(common.BatchNum(numBatches))
1091 assert.NoError(t, err)
1092
1093 assert.Equal(t, float64(numTx)/float64(numBatches-1), res.TransactionsPerBatch)
1094
1095 // Frequency is not exactly the desired one, some decimals may appear
1096 assert.GreaterOrEqual(t, res.BatchFrequency, float64(frequency))
1097 assert.Less(t, res.BatchFrequency, float64(frequency+1))
1098 // Truncate frecuency into an int to do an exact check
1099 assert.Equal(t, frequency, int(res.BatchFrequency))
1100 // This may also be different in some decimals
1101 // Truncate it to the third decimal to compare
1102 assert.Equal(t, math.Trunc((float64(numTx)/float64(frequency*blockNum-frequency))/0.001)*0.001, math.Trunc(res.TransactionsPerSecond/0.001)*0.001)
1103 assert.Equal(t, int64(3), res.TotalAccounts)
1104 assert.Equal(t, int64(3), res.TotalBJJs)
1105 // Til does not set fees
1106 assert.Equal(t, float64(0), res.AvgTransactionFee)
1107}
1108
1109func TestGetMetricsMoreThan24Hours(t *testing.T) {
1110 test.WipeDB(historyDB.DB())
1111
1112 testUsersLen := 3
1113 var set []til.Instruction
1114 for user := 0; user < testUsersLen; user++ {
1115 set = append(set, til.Instruction{
1116 Typ: common.TxTypeCreateAccountDeposit,
1117 TokenID: common.TokenID(0),
1118 DepositAmount: big.NewInt(1000000),
1119 Amount: big.NewInt(0),
1120 From: fmt.Sprintf("User%02d", user),
1121 })
1122 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1123 }
1124 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1125 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1126 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1127
1128 // Transfers
1129 for x := 0; x < 6000; x++ {
1130 set = append(set, til.Instruction{
1131 Typ: common.TxTypeTransfer,
1132 TokenID: common.TokenID(0),
1133 DepositAmount: big.NewInt(1),
1134 Amount: big.NewInt(0),
1135 From: "User00",
1136 To: "User01",
1137 })
1138 set = append(set, til.Instruction{Typ: til.TypeNewBatch})
1139 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1140 }
1141
1142 var chainID uint16 = 0
1143 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1144 blocks, err := tc.GenerateBlocksFromInstructions(set)
1145 assert.NoError(t, err)
1146
1147 tilCfgExtra := til.ConfigExtra{
1148 CoordUser: "A",
1149 }
1150 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1151 require.NoError(t, err)
1152
1153 const numBatches int = 6002
1154 const numTx int = 6003
1155 const blockNum = 6005 - 1
1156
1157 // Sanity check
1158 require.Equal(t, blockNum, len(blocks))
1159
1160 // Adding one batch per block
1161 // batch frequency can be chosen
1162 const frequency int = 15
1163
1164 for i := range blocks {
1165 blocks[i].Block.Timestamp = time.Now().Add(-time.Second * time.Duration(frequency*(len(blocks)-i)))
1166 err = historyDB.AddBlockSCData(&blocks[i])
1167 assert.NoError(t, err)
1168 }
1169
1170 res, err := historyDB.GetMetrics(common.BatchNum(numBatches))
1171 assert.NoError(t, err)
1172
1173 assert.Equal(t, math.Trunc((float64(numTx)/float64(numBatches-1))/0.001)*0.001, math.Trunc(res.TransactionsPerBatch/0.001)*0.001)
1174
1175 // Frequency is not exactly the desired one, some decimals may appear
1176 assert.GreaterOrEqual(t, res.BatchFrequency, float64(frequency))
1177 assert.Less(t, res.BatchFrequency, float64(frequency+1))
1178 // Truncate frecuency into an int to do an exact check
1179 assert.Equal(t, frequency, int(res.BatchFrequency))
1180 // This may also be different in some decimals
1181 // Truncate it to the third decimal to compare
1182 assert.Equal(t, math.Trunc((float64(numTx)/float64(frequency*blockNum-frequency))/0.001)*0.001, math.Trunc(res.TransactionsPerSecond/0.001)*0.001)
1183 assert.Equal(t, int64(3), res.TotalAccounts)
1184 assert.Equal(t, int64(3), res.TotalBJJs)
1185 // Til does not set fees
1186 assert.Equal(t, float64(0), res.AvgTransactionFee)
1187}
1188
1189func TestGetMetricsEmpty(t *testing.T) {
1190 test.WipeDB(historyDB.DB())
1191 _, err := historyDB.GetMetrics(0)
1192 assert.NoError(t, err)
1193}
1194
1195func TestGetAvgTxFeeEmpty(t *testing.T) {
1196 test.WipeDB(historyDB.DB())
1197 _, err := historyDB.GetAvgTxFee()
1198 assert.NoError(t, err)
1199}
1200
1201func TestGetLastL1TxsNum(t *testing.T) {
1202 test.WipeDB(historyDB.DB())
1203 _, err := historyDB.GetLastL1TxsNum()
1204 assert.NoError(t, err)
1205}
1206
1207func TestGetLastTxsPosition(t *testing.T) {
1208 test.WipeDB(historyDB.DB())
1209 _, err := historyDB.GetLastTxsPosition(0)
1210 assert.Equal(t, sql.ErrNoRows.Error(), err.Error())
1211}
1212
1213func TestGetFirstBatchBlockNumBySlot(t *testing.T) {
1214 test.WipeDB(historyDB.DB())
1215
1216 set := `
1217 Type: Blockchain
1218
1219 // Slot = 0
1220
1221 > block // 2
1222 > block // 3
1223 > block // 4
1224 > block // 5
1225
1226 // Slot = 1
1227
1228 > block // 6
1229 > block // 7
1230 > batch
1231 > block // 8
1232 > block // 9
1233
1234 // Slot = 2
1235
1236 > batch
1237 > block // 10
1238 > block // 11
1239 > block // 12
1240 > block // 13
1241
1242 `
1243 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
1244 blocks, err := tc.GenerateBlocks(set)
1245 assert.NoError(t, err)
1246
1247 tilCfgExtra := til.ConfigExtra{
1248 CoordUser: "A",
1249 }
1250 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1251 require.NoError(t, err)
1252
1253 for i := range blocks {
1254 for j := range blocks[i].Rollup.Batches {
1255 blocks[i].Rollup.Batches[j].Batch.SlotNum = int64(i) / 4
1256 }
1257 }
1258
1259 // Add all blocks
1260 for i := range blocks {
1261 err = historyDB.AddBlockSCData(&blocks[i])
1262 require.NoError(t, err)
1263 }
1264
1265 _, err = historyDB.GetFirstBatchBlockNumBySlot(0)
1266 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
1267
1268 bn1, err := historyDB.GetFirstBatchBlockNumBySlot(1)
1269 require.NoError(t, err)
1270 assert.Equal(t, int64(8), bn1)
1271
1272 bn2, err := historyDB.GetFirstBatchBlockNumBySlot(2)
1273 require.NoError(t, err)
1274 assert.Equal(t, int64(10), bn2)
1275}
1276
1277func TestTxItemID(t *testing.T) {
1278 test.WipeDB(historyDB.DB())
1279 testUsersLen := 10
1280 var set []til.Instruction
1281 for user := 0; user < testUsersLen; user++ {
1282 set = append(set, til.Instruction{
1283 Typ: common.TxTypeCreateAccountDeposit,
1284 TokenID: common.TokenID(0),
1285 DepositAmount: big.NewInt(1000000),
1286 Amount: big.NewInt(0),
1287 From: fmt.Sprintf("User%02d", user),
1288 })
1289 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1290 }
1291 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1292 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1293 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1294 for user := 0; user < testUsersLen; user++ {
1295 set = append(set, til.Instruction{
1296 Typ: common.TxTypeDeposit,
1297 TokenID: common.TokenID(0),
1298 DepositAmount: big.NewInt(100000),
1299 Amount: big.NewInt(0),
1300 From: fmt.Sprintf("User%02d", user),
1301 })
1302 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1303 }
1304 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1305 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1306 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1307 for user := 0; user < testUsersLen; user++ {
1308 set = append(set, til.Instruction{
1309 Typ: common.TxTypeDepositTransfer,
1310 TokenID: common.TokenID(0),
1311 DepositAmount: big.NewInt(10000 * int64(user+1)),
1312 Amount: big.NewInt(1000 * int64(user+1)),
1313 From: fmt.Sprintf("User%02d", user),
1314 To: fmt.Sprintf("User%02d", (user+1)%testUsersLen),
1315 })
1316 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1317 }
1318 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1319 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1320 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1321 for user := 0; user < testUsersLen; user++ {
1322 set = append(set, til.Instruction{
1323 Typ: common.TxTypeForceTransfer,
1324 TokenID: common.TokenID(0),
1325 Amount: big.NewInt(100 * int64(user+1)),
1326 DepositAmount: big.NewInt(0),
1327 From: fmt.Sprintf("User%02d", user),
1328 To: fmt.Sprintf("User%02d", (user+1)%testUsersLen),
1329 })
1330 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1331 }
1332 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1333 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1334 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1335 for user := 0; user < testUsersLen; user++ {
1336 set = append(set, til.Instruction{
1337 Typ: common.TxTypeForceExit,
1338 TokenID: common.TokenID(0),
1339 Amount: big.NewInt(10 * int64(user+1)),
1340 DepositAmount: big.NewInt(0),
1341 From: fmt.Sprintf("User%02d", user),
1342 })
1343 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1344 }
1345 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1346 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1347 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1348 var chainID uint16 = 0
1349 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1350 blocks, err := tc.GenerateBlocksFromInstructions(set)
1351 assert.NoError(t, err)
1352
1353 tilCfgExtra := til.ConfigExtra{
1354 CoordUser: "A",
1355 }
1356 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1357 require.NoError(t, err)
1358
1359 // Add all blocks
1360 for i := range blocks {
1361 err = historyDB.AddBlockSCData(&blocks[i])
1362 require.NoError(t, err)
1363 }
1364
1365 txs, err := historyDB.GetAllL1UserTxs()
1366 require.NoError(t, err)
1367 position := 0
1368 for _, tx := range txs {
1369 if tx.Position == 0 {
1370 position = 0
1371 }
1372 assert.Equal(t, position, tx.Position)
1373 position++
1374 }
1375}
1376
1377// setTestBlocks WARNING: this will delete the blocks and recreate them
1378func setTestBlocks(from, to int64) []common.Block {
1379 test.WipeDB(historyDB.DB())
1380 blocks := test.GenBlocks(from, to)
1381 if err := historyDB.AddBlocks(blocks); err != nil {
1382 panic(err)
1383 }
1384 return blocks
1385}