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
309 set := `
310 Type: Blockchain
311
312 AddToken(1)
313 AddToken(2)
314 CreateAccountDeposit(1) A: 10
315 CreateAccountDeposit(1) B: 10
316 > batchL1
317 > batchL1
318 > block
319
320 CreateAccountDepositTransfer(1) C-A: 20, 10
321 CreateAccountCoordinator(1) User0
322 > batchL1
323 > batchL1
324 > block
325
326 Deposit(1) B: 10
327 Deposit(1) C: 10
328 Transfer(1) C-A : 10 (1)
329 Transfer(1) B-C : 10 (1)
330 Transfer(1) A-B : 10 (1)
331 Exit(1) A: 10 (1)
332 > batch
333 > block
334
335 DepositTransfer(1) A-B: 10, 10
336 > batchL1
337 > block
338
339 ForceTransfer(1) A-B: 10
340 ForceExit(1) A: 5
341 > batchL1
342 > batchL1
343 > block
344
345 CreateAccountDeposit(2) D: 10
346 > batchL1
347 > block
348
349 CreateAccountDeposit(2) E: 10
350 > batchL1
351 > batchL1
352 > block
353
354 `
355 tc := til.NewContext(common.RollupConstMaxL1UserTx)
356 tilCfgExtra := til.ConfigExtra{
357 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
358 CoordUser: "A",
359 }
360 blocks, err := tc.GenerateBlocks(set)
361 require.Nil(t, err)
362 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
363 assert.Nil(t, err)
364
365 // Sanity check
366 require.Equal(t, 7, len(blocks))
367 require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
368 require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
369 require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
370 require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
371 require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
372 require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
373 require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
374
375 var null *common.BatchNum = nil
376 var txID common.TxID
377
378 // Insert blocks into DB
379 for i := range blocks {
380 if i == len(blocks)-1 {
381 blocks[i].Block.Timestamp = time.Now()
382 dbL1Txs, err := historyDB.GetAllL1UserTxs()
383 assert.NoError(t, err)
384 // Check batch_num is nil before forging
385 assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
386 // Save this TxId
387 txID = dbL1Txs[len(dbL1Txs)-1].TxID
388 }
389 err = historyDB.AddBlockSCData(&blocks[i])
390 assert.NoError(t, err)
391 }
392
393 // Check blocks
394 dbBlocks, err := historyDB.GetAllBlocks()
395 assert.NoError(t, err)
396 assert.Equal(t, len(blocks)+1, len(dbBlocks))
397
398 // Check batches
399 batches, err := historyDB.GetAllBatches()
400 assert.NoError(t, err)
401 assert.Equal(t, 11, len(batches))
402
403 // Check L1 Transactions
404 dbL1Txs, err := historyDB.GetAllL1UserTxs()
405 assert.NoError(t, err)
406 assert.Equal(t, 10, len(dbL1Txs))
407
408 // Tx Type
409 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
410 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
411 assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
412 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
413 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
414 assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
415 assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
416 assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
417 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
418 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
419
420 // Tx ID
421 assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
422 assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
423 assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
424 assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
425 assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
426 assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
427 assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
428 assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
429 assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
430 assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
431
432 // Tx From IDx
433 assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
434 assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
435 assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
436 assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
437 assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
438 assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
439 assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
440 assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
441 assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
442 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
443 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
444 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
445 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
446
447 // Tx to IDx
448 assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
449 assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
450 assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
451
452 // Token ID
453 assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
454 assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
455 assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
456 assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
457 assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
458 assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
459 assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
460 assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
461 assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
462 assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
463
464 // Batch Number
465 var bn common.BatchNum = common.BatchNum(2)
466
467 assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
468 assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
469
470 bn = common.BatchNum(4)
471 assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
472
473 bn = common.BatchNum(7)
474 assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
475 assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
476 assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
477
478 bn = common.BatchNum(8)
479 assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
480 assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
481
482 bn = common.BatchNum(10)
483 assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
484
485 bn = common.BatchNum(11)
486 assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
487
488 // eth_block_num
489 assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
490 assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
491 assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
492 assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
493 assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
494 assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
495 assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
496 assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
497 assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
498 assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
499
500 // User Origin
501 assert.Equal(t, true, dbL1Txs[0].UserOrigin)
502 assert.Equal(t, true, dbL1Txs[1].UserOrigin)
503 assert.Equal(t, true, dbL1Txs[2].UserOrigin)
504 assert.Equal(t, true, dbL1Txs[3].UserOrigin)
505 assert.Equal(t, true, dbL1Txs[4].UserOrigin)
506 assert.Equal(t, true, dbL1Txs[5].UserOrigin)
507 assert.Equal(t, true, dbL1Txs[6].UserOrigin)
508 assert.Equal(t, true, dbL1Txs[7].UserOrigin)
509 assert.Equal(t, true, dbL1Txs[8].UserOrigin)
510 assert.Equal(t, true, dbL1Txs[9].UserOrigin)
511
512 // Load Amount
513 assert.Equal(t, big.NewInt(10), dbL1Txs[0].LoadAmount)
514 assert.Equal(t, big.NewInt(10), dbL1Txs[1].LoadAmount)
515 assert.Equal(t, big.NewInt(20), dbL1Txs[2].LoadAmount)
516 assert.Equal(t, big.NewInt(10), dbL1Txs[3].LoadAmount)
517 assert.Equal(t, big.NewInt(10), dbL1Txs[4].LoadAmount)
518 assert.Equal(t, big.NewInt(10), dbL1Txs[5].LoadAmount)
519 assert.Equal(t, big.NewInt(0), dbL1Txs[6].LoadAmount)
520 assert.Equal(t, big.NewInt(0), dbL1Txs[7].LoadAmount)
521 assert.Equal(t, big.NewInt(10), dbL1Txs[8].LoadAmount)
522 assert.Equal(t, big.NewInt(10), dbL1Txs[9].LoadAmount)
523
524 // Check saved txID's batch_num is not nil
525 assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
526 assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
527
528 // Check Coordinator TXs
529 coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
530 assert.NoError(t, err)
531 assert.Equal(t, 1, len(coordTxs))
532 assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
533 assert.Equal(t, false, coordTxs[0].UserOrigin)
534
535 // Check L2 TXs
536 dbL2Txs, err := historyDB.GetAllL2Txs()
537 assert.NoError(t, err)
538 assert.Equal(t, 4, len(dbL2Txs))
539
540 // Tx Type
541 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
542 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
543 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
544 assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
545
546 // Tx ID
547 assert.Equal(t, "0x020000000001030000000001", dbL2Txs[0].TxID.String())
548 assert.Equal(t, "0x020000000001010000000001", dbL2Txs[1].TxID.String())
549 assert.Equal(t, "0x020000000001000000000001", dbL2Txs[2].TxID.String())
550 assert.Equal(t, "0x020000000001000000000002", dbL2Txs[3].TxID.String())
551
552 // Tx From and To IDx
553 assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
554 assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
555 assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
556
557 // Batch Number
558 assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
559 assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
560 assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
561 assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
562
563 // eth_block_num
564 assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
565 assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
566 assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
567
568 // Amount
569 assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
570 assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
571 assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
572 assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
573}
574
575func TestExitTree(t *testing.T) {
576 nBatches := 17
577 blocks := setTestBlocks(1, 10)
578 batches := test.GenBatches(nBatches, blocks)
579 err := historyDB.AddBatches(batches)
580 assert.NoError(t, err)
581 const nTokens = 50
582 tokens, ethToken := test.GenTokens(nTokens, blocks)
583 err = historyDB.AddTokens(tokens)
584 assert.NoError(t, err)
585 tokens = append([]common.Token{ethToken}, tokens...)
586 const nAccounts = 3
587 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
588 assert.NoError(t, historyDB.AddAccounts(accs))
589 exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
590 err = historyDB.AddExitTree(exitTree)
591 assert.NoError(t, err)
592}
593
594func TestGetL1UserTxs(t *testing.T) {
595 test.WipeDB(historyDB.DB())
596
597 set := `
598 Type: Blockchain
599 AddToken(1)
600 AddToken(2)
601 AddToken(3)
602
603 CreateAccountDeposit(1) A: 20
604 CreateAccountDeposit(2) A: 20
605 CreateAccountDeposit(1) B: 5
606 CreateAccountDeposit(1) C: 5
607 CreateAccountDeposit(1) D: 5
608
609 > block
610 `
611 tc := til.NewContext(128)
612 blocks, err := tc.GenerateBlocks(set)
613 require.Nil(t, err)
614 // Sanity check
615 require.Equal(t, 1, len(blocks))
616 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
617
618 toForgeL1TxsNum := int64(1)
619
620 for i := range blocks {
621 err = historyDB.AddBlockSCData(&blocks[i])
622 require.Nil(t, err)
623 }
624
625 l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
626 require.Nil(t, err)
627 assert.Equal(t, 5, len(l1UserTxs))
628 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
629
630 // No l1UserTxs for this toForgeL1TxsNum
631 l1UserTxs, err = historyDB.GetL1UserTxs(2)
632 require.Nil(t, err)
633 assert.Equal(t, 0, len(l1UserTxs))
634}
635
636func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
637 //nolint:govet
638 rollup := &common.RollupVariables{
639 0,
640 big.NewInt(10),
641 12,
642 13,
643 [5]common.Bucket{},
644 }
645 //nolint:govet
646 auction := &common.AuctionVariables{
647 0,
648 ethCommon.BigToAddress(big.NewInt(2)),
649 ethCommon.BigToAddress(big.NewInt(3)),
650 [6]*big.Int{
651 big.NewInt(1), big.NewInt(2), big.NewInt(3),
652 big.NewInt(4), big.NewInt(5), big.NewInt(6),
653 },
654 0,
655 2,
656 4320,
657 [3]uint16{10, 11, 12},
658 1000,
659 20,
660 }
661 //nolint:govet
662 wDelayer := &common.WDelayerVariables{
663 0,
664 ethCommon.BigToAddress(big.NewInt(2)),
665 ethCommon.BigToAddress(big.NewInt(3)),
666 ethCommon.BigToAddress(big.NewInt(4)),
667 13,
668 14,
669 false,
670 }
671 return rollup, auction, wDelayer
672}
673
674func TestSetInitialSCVars(t *testing.T) {
675 test.WipeDB(historyDB.DB())
676 _, _, _, err := historyDB.GetSCVars()
677 assert.Equal(t, sql.ErrNoRows, err)
678 rollup, auction, wDelayer := exampleInitSCVars()
679 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
680 require.Nil(t, err)
681 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
682 assert.Nil(t, err)
683 require.Equal(t, rollup, dbRollup)
684 require.Equal(t, auction, dbAuction)
685 require.Equal(t, wDelayer, dbWDelayer)
686}
687
688func TestUpdateExitTree(t *testing.T) {
689 test.WipeDB(historyDB.DB())
690
691 set := `
692 Type: Blockchain
693
694 AddToken(1)
695
696 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
697 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
698
699 CreateAccountCoordinator(1) A // Idx=256+0=256
700 CreateAccountCoordinator(1) B // Idx=256+1=257
701
702 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
703 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
704 > block // blockNum=2
705
706 ForceExit(1) A: 100
707 ForceExit(1) B: 80
708
709 Exit(1) C: 50 (172)
710 Exit(1) D: 30 (172)
711
712 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
713 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
714 > block // blockNum=3
715
716 > block // blockNum=4 (empty block)
717 > block // blockNum=5 (empty block)
718 `
719
720 tc := til.NewContext(common.RollupConstMaxL1UserTx)
721 tilCfgExtra := til.ConfigExtra{
722 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
723 CoordUser: "A",
724 }
725 blocks, err := tc.GenerateBlocks(set)
726 require.Nil(t, err)
727 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
728 assert.Nil(t, err)
729
730 // Add all blocks except for the last two
731 for i := range blocks[:len(blocks)-2] {
732 err = historyDB.AddBlockSCData(&blocks[i])
733 require.Nil(t, err)
734 }
735
736 // Add withdraws to the second-to-last block, and insert block into the DB
737 block := &blocks[len(blocks)-2]
738 require.Equal(t, int64(4), block.Block.EthBlockNum)
739 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
740 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
741 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
742 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
743 // )
744 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
745 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
746 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
747 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
748 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
749 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
750 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
751 )
752 err = historyDB.addBlock(historyDB.db, &block.Block)
753 require.Nil(t, err)
754
755 err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
756 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
757 require.Nil(t, err)
758
759 // Check that exits in DB match with the expected values
760 dbExits, err := historyDB.GetAllExits()
761 require.Nil(t, err)
762 assert.Equal(t, 4, len(dbExits))
763 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
764 for _, dbExit := range dbExits {
765 dbExitsByIdx[dbExit.AccountIdx] = dbExit
766 }
767 for _, withdraw := range block.Rollup.Withdrawals {
768 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
769 if withdraw.InstantWithdraw {
770 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
771 } else {
772 assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
773 }
774 }
775
776 // Add delayed withdraw to the last block, and insert block into the DB
777 block = &blocks[len(blocks)-1]
778 require.Equal(t, int64(5), block.Block.EthBlockNum)
779 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
780 common.WDelayerTransfer{
781 Owner: tc.UsersByIdx[257].Addr,
782 Token: tokenAddr,
783 Amount: big.NewInt(80),
784 })
785 err = historyDB.addBlock(historyDB.db, &block.Block)
786 require.Nil(t, err)
787
788 err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
789 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
790 require.Nil(t, err)
791
792 // Check that delayed withdrawn has been set
793 dbExits, err = historyDB.GetAllExits()
794 require.Nil(t, err)
795 for _, dbExit := range dbExits {
796 dbExitsByIdx[dbExit.AccountIdx] = dbExit
797 }
798 require.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[257].DelayedWithdrawn)
799}
800
801func TestGetBestBidCoordinator(t *testing.T) {
802 test.WipeDB(historyDB.DB())
803
804 rollup, auction, wDelayer := exampleInitSCVars()
805 err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
806 require.Nil(t, err)
807
808 tc := til.NewContext(common.RollupConstMaxL1UserTx)
809 blocks, err := tc.GenerateBlocks(`
810 Type: Blockchain
811 > block // blockNum=2
812 `)
813 require.Nil(t, err)
814 err = historyDB.AddBlockSCData(&blocks[0])
815 require.Nil(t, err)
816
817 coords := []common.Coordinator{
818 {
819 Bidder: ethCommon.BigToAddress(big.NewInt(1)),
820 Forger: ethCommon.BigToAddress(big.NewInt(2)),
821 EthBlockNum: 2,
822 URL: "foo",
823 },
824 {
825 Bidder: ethCommon.BigToAddress(big.NewInt(3)),
826 Forger: ethCommon.BigToAddress(big.NewInt(4)),
827 EthBlockNum: 2,
828 URL: "bar",
829 },
830 }
831 err = historyDB.addCoordinators(historyDB.db, coords)
832 require.Nil(t, err)
833 err = historyDB.addBids(historyDB.db, []common.Bid{
834 {
835 SlotNum: 10,
836 BidValue: big.NewInt(10),
837 EthBlockNum: 2,
838 Bidder: coords[0].Bidder,
839 },
840 {
841 SlotNum: 10,
842 BidValue: big.NewInt(20),
843 EthBlockNum: 2,
844 Bidder: coords[1].Bidder,
845 },
846 })
847 require.Nil(t, err)
848
849 forger10, err := historyDB.GetBestBidCoordinator(10)
850 require.Nil(t, err)
851 require.Equal(t, coords[1].Forger, forger10.Forger)
852 require.Equal(t, coords[1].Bidder, forger10.Bidder)
853 require.Equal(t, coords[1].URL, forger10.URL)
854
855 _, err = historyDB.GetBestBidCoordinator(11)
856 require.Equal(t, sql.ErrNoRows, err)
857}
858
859// setTestBlocks WARNING: this will delete the blocks and recreate them
860func setTestBlocks(from, to int64) []common.Block {
861 test.WipeDB(historyDB.DB())
862 blocks := test.GenBlocks(from, to)
863 if err := historyDB.AddBlocks(blocks); err != nil {
864 panic(err)
865 }
866 return blocks
867}