hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
1package historydb
2
3import (
4 "database/sql"
5 "math"
6 "math/big"
7 "os"
8 "testing"
9 "time"
10
11 ethCommon "github.com/ethereum/go-ethereum/common"
12 "github.com/hermeznetwork/hermez-node/common"
13 dbUtils "github.com/hermeznetwork/hermez-node/db"
14 "github.com/hermeznetwork/hermez-node/log"
15 "github.com/hermeznetwork/hermez-node/test"
16 "github.com/hermeznetwork/hermez-node/test/til"
17 "github.com/stretchr/testify/assert"
18 "github.com/stretchr/testify/require"
19)
20
21var historyDB *HistoryDB
22
23// In order to run the test you need to run a Posgres DB with
24// a database named "history" that is accessible by
25// user: "hermez"
26// pass: set it using the env var POSTGRES_PASS
27// 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;"
28// After running the test you can stop the container by running: sudo docker kill hermez-db-test
29// If you already did that for the L2DB you don't have to do it again
30
31func TestMain(m *testing.M) {
32 // init DB
33 pass := os.Getenv("POSTGRES_PASS")
34 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
35 if err != nil {
36 panic(err)
37 }
38 historyDB = NewHistoryDB(db)
39 if err != nil {
40 panic(err)
41 }
42 // Run tests
43 result := m.Run()
44 // Close DB
45 if err := db.Close(); err != nil {
46 log.Error("Error closing the history DB:", err)
47 }
48 os.Exit(result)
49}
50
51func TestBlocks(t *testing.T) {
52 var fromBlock, toBlock int64
53 fromBlock = 0
54 toBlock = 7
55 // Reset DB
56 test.WipeDB(historyDB.DB())
57 // Generate blocks using til
58 set1 := `
59 Type: Blockchain
60 // block 0 is stored as default in the DB
61 // block 1 does not exist
62 > block // blockNum=2
63 > block // blockNum=3
64 > block // blockNum=4
65 > block // blockNum=5
66 > block // blockNum=6
67 `
68 tc := til.NewContext(1)
69 blocks, err := tc.GenerateBlocks(set1)
70 require.NoError(t, err)
71 // Save timestamp of a block with UTC and change it without UTC
72 timestamp := time.Now().Add(time.Second * 13)
73 blocks[fromBlock].Block.Timestamp = timestamp
74 // Insert blocks into DB
75 for i := 0; i < len(blocks); i++ {
76 err := historyDB.AddBlock(&blocks[i].Block)
77 assert.NoError(t, err)
78 }
79 // Add block 0 to the generated blocks
80 blocks = append(
81 []common.BlockData{common.BlockData{Block: test.Block0}}, //nolint:gofmt
82 blocks...,
83 )
84 // Get all blocks from DB
85 fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
86 assert.Equal(t, len(blocks), len(fetchedBlocks))
87 // Compare generated vs getted blocks
88 assert.NoError(t, err)
89 for i := range fetchedBlocks {
90 assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
91 }
92 // Compare saved timestamp vs getted
93 nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
94 zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
95 assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
96 assert.Equal(t, offsetUTC, offsetFetchedBlock)
97 // Get blocks from the DB one by one
98 for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
99 fetchedBlock, err := historyDB.GetBlock(i)
100 assert.NoError(t, err)
101 assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
102 }
103 // Get last block
104 lastBlock, err := historyDB.GetLastBlock()
105 assert.NoError(t, err)
106 assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
107}
108
109func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
110 assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
111 assert.Equal(t, expected.Hash, actual.Hash)
112 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
113}
114
115func TestBatches(t *testing.T) {
116 // Reset DB
117 test.WipeDB(historyDB.DB())
118 // Generate batches using til (and blocks for foreign key)
119 set := `
120 Type: Blockchain
121
122 AddToken(1) // Will have value in USD
123 AddToken(2) // Will NOT have value in USD
124 CreateAccountDeposit(1) A: 2000
125 CreateAccountDeposit(2) A: 2000
126 CreateAccountDeposit(1) B: 1000
127 CreateAccountDeposit(2) B: 1000
128 > batchL1
129 > batchL1
130 Transfer(1) A-B: 100 (5)
131 Transfer(2) B-A: 100 (199)
132 > batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
133 > block
134 Transfer(1) A-B: 100 (5)
135 > batch // batchNum=3, L2 only batch, forges transfer (with USD value)
136 Transfer(2) B-A: 100 (199)
137 > batch // batchNum=4, L2 only batch, forges transfer (without USD value)
138 > block
139 `
140 tc := til.NewContext(common.RollupConstMaxL1UserTx)
141 tilCfgExtra := til.ConfigExtra{
142 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
143 CoordUser: "A",
144 }
145 blocks, err := tc.GenerateBlocks(set)
146 require.Nil(t, err)
147 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
148 assert.Nil(t, err)
149 // Insert to DB
150 batches := []common.Batch{}
151 tokensValue := make(map[common.TokenID]float64)
152 lastL1TxsNum := new(int64)
153 for _, block := range blocks {
154 // Insert block
155 assert.NoError(t, historyDB.AddBlock(&block.Block))
156 // Insert tokens
157 for i, token := range block.Rollup.AddedTokens {
158 assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
159 if i%2 != 0 {
160 // Set value to the token
161 value := (float64(i) + 5) * 5.389329
162 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
163 tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
164 }
165 }
166 // Combine all generated batches into single array
167 for _, batch := range block.Rollup.Batches {
168 batches = append(batches, batch.Batch)
169 forgeTxsNum := batch.Batch.ForgeL1TxsNum
170 if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
171 *lastL1TxsNum = *forgeTxsNum
172 }
173 }
174 }
175 // Insert batches
176 assert.NoError(t, historyDB.AddBatches(batches))
177 // Set expected total fee
178 for _, batch := range batches {
179 total := .0
180 for tokenID, amount := range batch.CollectedFees {
181 af := new(big.Float).SetInt(amount)
182 amountFloat, _ := af.Float64()
183 total += tokensValue[tokenID] * amountFloat
184 }
185 batch.TotalFeesUSD = &total
186 }
187 // Get batches from the DB
188 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
189 assert.NoError(t, err)
190 assert.Equal(t, len(batches), len(fetchedBatches))
191 for i, fetchedBatch := range fetchedBatches {
192 assert.Equal(t, batches[i], fetchedBatch)
193 }
194 // Test GetLastBatchNum
195 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
196 assert.NoError(t, err)
197 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
198 // Test GetLastL1TxsNum
199 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
200 assert.NoError(t, err)
201 assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
202}
203
204func TestBids(t *testing.T) {
205 const fromBlock int64 = 1
206 const toBlock int64 = 5
207 // Prepare blocks in the DB
208 blocks := setTestBlocks(fromBlock, toBlock)
209 // Generate fake coordinators
210 const nCoords = 5
211 coords := test.GenCoordinators(nCoords, blocks)
212 err := historyDB.AddCoordinators(coords)
213 assert.NoError(t, err)
214 // Generate fake bids
215 const nBids = 20
216 bids := test.GenBids(nBids, blocks, coords)
217 err = historyDB.AddBids(bids)
218 assert.NoError(t, err)
219 // Fetch bids
220 fetchedBids, err := historyDB.GetAllBids()
221 assert.NoError(t, err)
222 // Compare fetched bids vs generated bids
223 for i, bid := range fetchedBids {
224 assert.Equal(t, bids[i], bid)
225 }
226}
227
228func TestTokens(t *testing.T) {
229 const fromBlock int64 = 1
230 const toBlock int64 = 5
231 // Prepare blocks in the DB
232 blocks := setTestBlocks(fromBlock, toBlock)
233 // Generate fake tokens
234 const nTokens = 5
235 tokens, ethToken := test.GenTokens(nTokens, blocks)
236 err := historyDB.AddTokens(tokens)
237 assert.NoError(t, err)
238 tokens = append([]common.Token{ethToken}, tokens...)
239 limit := uint(10)
240 // Fetch tokens
241 fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
242 assert.NoError(t, err)
243 // Compare fetched tokens vs generated tokens
244 // All the tokens should have USDUpdate setted by the DB trigger
245 for i, token := range fetchedTokens {
246 assert.Equal(t, tokens[i].TokenID, token.TokenID)
247 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
248 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
249 assert.Equal(t, tokens[i].Name, token.Name)
250 assert.Equal(t, tokens[i].Symbol, token.Symbol)
251 assert.Nil(t, token.USD)
252 assert.Nil(t, token.USDUpdate)
253 }
254
255 // Update token value
256 for i, token := range tokens {
257 value := 1.01 * float64(i)
258 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
259 }
260 // Fetch tokens
261 fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
262 assert.NoError(t, err)
263 // Compare fetched tokens vs generated tokens
264 // All the tokens should have USDUpdate setted by the DB trigger
265 for i, token := range fetchedTokens {
266 value := 1.01 * float64(i)
267 assert.Equal(t, value, *token.USD)
268 nameZone, offset := token.USDUpdate.Zone()
269 assert.Equal(t, "UTC", nameZone)
270 assert.Equal(t, 0, offset)
271 }
272}
273
274func TestAccounts(t *testing.T) {
275 const fromBlock int64 = 1
276 const toBlock int64 = 5
277 // Prepare blocks in the DB
278 blocks := setTestBlocks(fromBlock, toBlock)
279 // Generate fake tokens
280 const nTokens = 5
281 tokens, ethToken := test.GenTokens(nTokens, blocks)
282 err := historyDB.AddTokens(tokens)
283 assert.NoError(t, err)
284 tokens = append([]common.Token{ethToken}, tokens...)
285 // Generate fake batches
286 const nBatches = 10
287 batches := test.GenBatches(nBatches, blocks)
288 err = historyDB.AddBatches(batches)
289 assert.NoError(t, err)
290 // Generate fake accounts
291 const nAccounts = 3
292 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
293 err = historyDB.AddAccounts(accs)
294 assert.NoError(t, err)
295 // Fetch accounts
296 fetchedAccs, err := historyDB.GetAccounts()
297 assert.NoError(t, err)
298 // Compare fetched accounts vs generated accounts
299 for i, acc := range fetchedAccs {
300 accs[i].Balance = nil
301 assert.Equal(t, accs[i], acc)
302 }
303}
304
305func TestTxs(t *testing.T) {
306 // Reset DB
307 test.WipeDB(historyDB.DB())
308 // TODO: Generate batches using til (and blocks for foreign key)
309 set := `
310 Type: Blockchain
311
312 // Things to test:
313 // One tx of each type
314 // batches that forge user L1s
315 // historic USD is not set if USDUpdate is too old (24h)
316 `
317 tc := til.NewContext(common.RollupConstMaxL1UserTx)
318 tilCfgExtra := til.ConfigExtra{
319 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
320 CoordUser: "A",
321 }
322 blocks, err := tc.GenerateBlocks(set)
323 require.Nil(t, err)
324 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
325 assert.Nil(t, err)
326
327 /*
328
329 OLD TEST
330
331
332 const fromBlock int64 = 1
333 const toBlock int64 = 5
334 // Prepare blocks in the DB
335 blocks := setTestBlocks(fromBlock, toBlock)
336 // Generate fake tokens
337 const nTokens = 500
338 tokens, ethToken := test.GenTokens(nTokens, blocks)
339 err := historyDB.AddTokens(tokens)
340 assert.NoError(t, err)
341 tokens = append([]common.Token{ethToken}, tokens...)
342 // Generate fake batches
343 const nBatches = 10
344 batches := test.GenBatches(nBatches, blocks)
345 err = historyDB.AddBatches(batches)
346 assert.NoError(t, err)
347 // Generate fake accounts
348 const nAccounts = 3
349 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
350 err = historyDB.AddAccounts(accs)
351 assert.NoError(t, err)
352
353 Uncomment once the transaction generation is fixed
354 !! test that batches that forge user L1s !!
355 !! Missing tests to check that !!
356
357 // Generate fake L1 txs
358 const nL1s = 64
359 _, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
360 err = historyDB.AddL1Txs(l1txs)
361 assert.NoError(t, err)
362 // Generate fake L2 txs
363 const nL2s = 2048 - nL1s
364 _, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
365 err = historyDB.AddL2Txs(l2txs)
366 assert.NoError(t, err)
367 // Compare fetched txs vs generated txs.
368 fetchAndAssertTxs(t, l1txs, l2txs)
369 // Test trigger: L1 integrity
370 // from_eth_addr can't be null
371 l1txs[0].FromEthAddr = ethCommon.Address{}
372 err = historyDB.AddL1Txs(l1txs)
373 assert.Error(t, err)
374 l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
375 // from_bjj can't be null
376 l1txs[0].FromBJJ = nil
377 err = historyDB.AddL1Txs(l1txs)
378 assert.Error(t, err)
379 privK := babyjub.NewRandPrivKey()
380 l1txs[0].FromBJJ = privK.Public()
381 // load_amount can't be null
382 l1txs[0].LoadAmount = nil
383 err = historyDB.AddL1Txs(l1txs)
384 assert.Error(t, err)
385 // Test trigger: L2 integrity
386 // batch_num can't be null
387 l2txs[0].BatchNum = 0
388 err = historyDB.AddL2Txs(l2txs)
389 assert.Error(t, err)
390 l2txs[0].BatchNum = 1
391 // nonce can't be null
392 l2txs[0].Nonce = 0
393 err = historyDB.AddL2Txs(l2txs)
394 assert.Error(t, err)
395 // Test trigger: forge L1 txs
396 // add next batch to DB
397 batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
398 batch := batches[0]
399 batch.BatchNum = batchNum
400 batch.ForgeL1TxsNum = toForgeL1TxsNum
401 assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
402 // Set batch num in txs that should have been marked as forged in the DB
403 for i := 0; i < len(l1txs); i++ {
404 fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
405 assert.NoError(t, err)
406 if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
407 assert.Equal(t, batchNum, *fetchedTx.BatchNum)
408 } else {
409 if fetchedTx.BatchNum != nil {
410 assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
411 }
412 }
413 }
414
415 // Test helper functions for Synchronizer
416 // GetLastTxsPosition
417 expectedPosition := -1
418 var choosenToForgeL1TxsNum int64 = -1
419 for _, tx := range l1txs {
420 if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
421 choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
422 expectedPosition = tx.Position
423 } else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
424 expectedPosition = tx.Position
425 }
426 }
427 position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
428 assert.NoError(t, err)
429 assert.Equal(t, expectedPosition, position)
430
431 // GetL1UserTxs: not needed? tests were broken
432 // txs, err := historyDB.GetL1UserTxs(2)
433 // assert.NoError(t, err)
434 // assert.NotZero(t, len(txs))
435 // assert.NoError(t, err)
436 // assert.Equal(t, 22, position)
437 // // Test Update L1 TX Batch_num
438 // assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
439 // txs[0].BatchNum = common.BatchNum(1)
440 // txs, err = historyDB.GetL1UserTxs(2)
441 // assert.NoError(t, err)
442 // assert.NotZero(t, len(txs))
443 // assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
444 */
445}
446
447/*
448func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
449 for i := 0; i < len(l1txs); i++ {
450 tx := l1txs[i].Tx()
451 fmt.Println("ASDF", i, tx.TxID)
452 fetchedTx, err := historyDB.GetTx(tx.TxID)
453 require.NoError(t, err)
454 test.AssertUSD(t, tx.USD, fetchedTx.USD)
455 test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
456 assert.Equal(t, tx, fetchedTx)
457 }
458 for i := 0; i < len(l2txs); i++ {
459 tx := l2txs[i].Tx()
460 fetchedTx, err := historyDB.GetTx(tx.TxID)
461 tx.TokenID = fetchedTx.TokenID
462 assert.NoError(t, err)
463 test.AssertUSD(t, fetchedTx.USD, tx.USD)
464 test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
465 assert.Equal(t, tx, fetchedTx)
466 }
467}
468*/
469
470func TestExitTree(t *testing.T) {
471 nBatches := 17
472 blocks := setTestBlocks(1, 10)
473 batches := test.GenBatches(nBatches, blocks)
474 err := historyDB.AddBatches(batches)
475 assert.NoError(t, err)
476 const nTokens = 50
477 tokens, ethToken := test.GenTokens(nTokens, blocks)
478 err = historyDB.AddTokens(tokens)
479 assert.NoError(t, err)
480 tokens = append([]common.Token{ethToken}, tokens...)
481 const nAccounts = 3
482 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
483 assert.NoError(t, historyDB.AddAccounts(accs))
484 exitTree := test.GenExitTree(nBatches, batches, accs)
485 err = historyDB.AddExitTree(exitTree)
486 assert.NoError(t, err)
487}
488
489func TestGetL1UserTxs(t *testing.T) {
490 test.WipeDB(historyDB.DB())
491
492 set := `
493 Type: Blockchain
494 AddToken(1)
495 AddToken(2)
496 AddToken(3)
497
498 CreateAccountDeposit(1) A: 20
499 CreateAccountDeposit(2) A: 20
500 CreateAccountDeposit(1) B: 5
501 CreateAccountDeposit(1) C: 5
502 CreateAccountDeposit(1) D: 5
503
504 > block
505 `
506 tc := til.NewContext(128)
507 blocks, err := tc.GenerateBlocks(set)
508 require.Nil(t, err)
509 // Sanity check
510 require.Equal(t, 1, len(blocks))
511 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
512 // fmt.Printf("DBG Blocks: %+v\n", blocks)
513
514 toForgeL1TxsNum := int64(1)
515
516 for i := range blocks {
517 err = historyDB.AddBlockSCData(&blocks[i])
518 require.Nil(t, err)
519 }
520
521 l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
522 require.Nil(t, err)
523 assert.Equal(t, 5, len(l1UserTxs))
524 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
525
526 // No l1UserTxs for this toForgeL1TxsNum
527 l1UserTxs, err = historyDB.GetL1UserTxs(2)
528 require.Nil(t, err)
529 assert.Equal(t, 0, len(l1UserTxs))
530}
531
532func TestSetInitialSCVars(t *testing.T) {
533 test.WipeDB(historyDB.DB())
534 _, _, _, err := historyDB.GetSCVars()
535 assert.Equal(t, sql.ErrNoRows, err)
536
537 //nolint:govet
538 rollup := &common.RollupVariables{
539 0,
540 big.NewInt(10),
541 12,
542 13,
543 }
544 //nolint:govet
545 auction := &common.AuctionVariables{
546 0,
547 ethCommon.BigToAddress(big.NewInt(2)),
548 ethCommon.BigToAddress(big.NewInt(3)),
549 [6]*big.Int{
550 big.NewInt(1), big.NewInt(2), big.NewInt(3),
551 big.NewInt(4), big.NewInt(5), big.NewInt(6),
552 },
553 2,
554 4320,
555 [3]uint16{10, 11, 12},
556 1000,
557 20,
558 }
559 //nolint:govet
560 wDelayer := &common.WDelayerVariables{
561 0,
562 ethCommon.BigToAddress(big.NewInt(2)),
563 ethCommon.BigToAddress(big.NewInt(3)),
564 ethCommon.BigToAddress(big.NewInt(4)),
565 13,
566 14,
567 false,
568 }
569 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
570 require.Nil(t, err)
571 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
572 assert.Nil(t, err)
573 require.Equal(t, rollup, dbRollup)
574 require.Equal(t, auction, dbAuction)
575 require.Equal(t, wDelayer, dbWDelayer)
576}
577
578func TestUpdateExitTree(t *testing.T) {
579 test.WipeDB(historyDB.DB())
580
581 set := `
582 Type: Blockchain
583
584 AddToken(1)
585
586 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
587 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
588
589 CreateAccountCoordinator(1) A // Idx=256+0=256
590 CreateAccountCoordinator(1) B // Idx=256+1=257
591
592 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
593 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
594 > block // blockNum=2
595
596 ForceExit(1) A: 100
597 ForceExit(1) B: 80
598
599 Exit(1) C: 50 (200)
600 Exit(1) D: 30 (200)
601
602 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
603 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
604 > block // blockNum=3
605
606 > block // blockNum=4 (empty block)
607 `
608
609 tc := til.NewContext(common.RollupConstMaxL1UserTx)
610 tilCfgExtra := til.ConfigExtra{
611 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
612 CoordUser: "A",
613 }
614 blocks, err := tc.GenerateBlocks(set)
615 require.Nil(t, err)
616 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
617 assert.Nil(t, err)
618
619 // Add all blocks except for the last one
620 for i := range blocks[:len(blocks)-1] {
621 err = historyDB.AddBlockSCData(&blocks[i])
622 require.Nil(t, err)
623 }
624
625 // Add withdraws to the last block, and insert block into the DB
626 block := &blocks[len(blocks)-1]
627 require.Equal(t, int64(4), block.Block.EthBlockNum)
628 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
629 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
630 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
631 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
632 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
633 )
634 err = historyDB.addBlock(historyDB.db, &block.Block)
635 require.Nil(t, err)
636
637 // update exit trees in DB
638 instantWithdrawn := []exitID{}
639 delayedWithdrawRequest := []exitID{}
640 for _, withdraw := range block.Rollup.Withdrawals {
641 exitID := exitID{
642 batchNum: int64(withdraw.NumExitRoot),
643 idx: int64(withdraw.Idx),
644 }
645 if withdraw.InstantWithdraw {
646 instantWithdrawn = append(instantWithdrawn, exitID)
647 } else {
648 delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
649 }
650 }
651 err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
652 require.Nil(t, err)
653
654 // Check that exits in DB match with the expected values
655 dbExits, err := historyDB.GetAllExits()
656 require.Nil(t, err)
657 assert.Equal(t, 4, len(dbExits))
658 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
659 for _, dbExit := range dbExits {
660 dbExitsByIdx[dbExit.AccountIdx] = dbExit
661 }
662 for _, withdraw := range block.Rollup.Withdrawals {
663 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
664 if withdraw.InstantWithdraw {
665 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
666 } else {
667 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
668 }
669 }
670}
671
672// setTestBlocks WARNING: this will delete the blocks and recreate them
673func setTestBlocks(from, to int64) []common.Block {
674 test.WipeDB(historyDB.DB())
675 blocks := test.GenBlocks(from, to)
676 if err := historyDB.AddBlocks(blocks); err != nil {
677 panic(err)
678 }
679 return blocks
680}