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.GetAllAccounts()
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, blocks)
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
513 toForgeL1TxsNum := int64(1)
514
515 for i := range blocks {
516 err = historyDB.AddBlockSCData(&blocks[i])
517 require.Nil(t, err)
518 }
519
520 l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
521 require.Nil(t, err)
522 assert.Equal(t, 5, len(l1UserTxs))
523 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
524
525 // No l1UserTxs for this toForgeL1TxsNum
526 l1UserTxs, err = historyDB.GetL1UserTxs(2)
527 require.Nil(t, err)
528 assert.Equal(t, 0, len(l1UserTxs))
529}
530
531func TestSetInitialSCVars(t *testing.T) {
532 test.WipeDB(historyDB.DB())
533 _, _, _, err := historyDB.GetSCVars()
534 assert.Equal(t, sql.ErrNoRows, err)
535
536 //nolint:govet
537 rollup := &common.RollupVariables{
538 0,
539 big.NewInt(10),
540 12,
541 13,
542 [5]common.Bucket{},
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 (172)
600 Exit(1) D: 30 (172)
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 > block // blockNum=5 (empty block)
608 `
609
610 tc := til.NewContext(common.RollupConstMaxL1UserTx)
611 tilCfgExtra := til.ConfigExtra{
612 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
613 CoordUser: "A",
614 }
615 blocks, err := tc.GenerateBlocks(set)
616 require.Nil(t, err)
617 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
618 assert.Nil(t, err)
619
620 // Add all blocks except for the last two
621 for i := range blocks[:len(blocks)-2] {
622 err = historyDB.AddBlockSCData(&blocks[i])
623 require.Nil(t, err)
624 }
625
626 // Add withdraws to the second-to-last block, and insert block into the DB
627 block := &blocks[len(blocks)-2]
628 require.Equal(t, int64(4), block.Block.EthBlockNum)
629 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
630 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
631 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
632 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
633 // )
634 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
635 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
636 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
637 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
638 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
639 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
640 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
641 )
642 err = historyDB.addBlock(historyDB.db, &block.Block)
643 require.Nil(t, err)
644
645 err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
646 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
647 require.Nil(t, err)
648
649 // Check that exits in DB match with the expected values
650 dbExits, err := historyDB.GetAllExits()
651 require.Nil(t, err)
652 assert.Equal(t, 4, len(dbExits))
653 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
654 for _, dbExit := range dbExits {
655 dbExitsByIdx[dbExit.AccountIdx] = dbExit
656 }
657 for _, withdraw := range block.Rollup.Withdrawals {
658 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
659 if withdraw.InstantWithdraw {
660 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
661 } else {
662 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
663 }
664 }
665
666 // Add delayed withdraw to the last block, and insert block into the DB
667 block = &blocks[len(blocks)-1]
668 require.Equal(t, int64(5), block.Block.EthBlockNum)
669 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
670 common.WDelayerTransfer{
671 Owner: tc.UsersByIdx[257].Addr,
672 Token: tokenAddr,
673 Amount: big.NewInt(80),
674 })
675 err = historyDB.addBlock(historyDB.db, &block.Block)
676 require.Nil(t, err)
677
678 err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
679 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
680 require.Nil(t, err)
681
682 // Check that delayed withdrawn has been set
683 dbExits, err = historyDB.GetAllExits()
684 require.Nil(t, err)
685 for _, dbExit := range dbExits {
686 dbExitsByIdx[dbExit.AccountIdx] = dbExit
687 }
688 require.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[257].DelayedWithdrawn)
689}
690
691// setTestBlocks WARNING: this will delete the blocks and recreate them
692func setTestBlocks(from, to int64) []common.Block {
693 test.WipeDB(historyDB.DB())
694 blocks := test.GenBlocks(from, to)
695 if err := historyDB.AddBlocks(blocks); err != nil {
696 panic(err)
697 }
698 return blocks
699}