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