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/hermeznetwork/tracerr"
18 "github.com/stretchr/testify/assert"
19 "github.com/stretchr/testify/require"
20)
21
22var historyDB *HistoryDB
23
24// In order to run the test you need to run a Posgres DB with
25// a database named "history" that is accessible by
26// user: "hermez"
27// pass: set it using the env var POSTGRES_PASS
28// 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;"
29// After running the test you can stop the container by running: sudo docker kill hermez-db-test
30// If you already did that for the L2DB you don't have to do it again
31
32func TestMain(m *testing.M) {
33 // init DB
34 pass := os.Getenv("POSTGRES_PASS")
35 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
36 if err != nil {
37 panic(err)
38 }
39 historyDB = NewHistoryDB(db)
40 if err != nil {
41 panic(err)
42 }
43 // Run tests
44 result := m.Run()
45 // Close DB
46 if err := db.Close(); err != nil {
47 log.Error("Error closing the history DB:", err)
48 }
49 os.Exit(result)
50}
51
52func TestBlocks(t *testing.T) {
53 var fromBlock, toBlock int64
54 fromBlock = 0
55 toBlock = 7
56 // Reset DB
57 test.WipeDB(historyDB.DB())
58 // Generate blocks using til
59 set1 := `
60 Type: Blockchain
61 // block 0 is stored as default in the DB
62 // block 1 does not exist
63 > block // blockNum=2
64 > block // blockNum=3
65 > block // blockNum=4
66 > block // blockNum=5
67 > block // blockNum=6
68 `
69 tc := til.NewContext(1)
70 blocks, err := tc.GenerateBlocks(set1)
71 require.NoError(t, err)
72 // Save timestamp of a block with UTC and change it without UTC
73 timestamp := time.Now().Add(time.Second * 13)
74 blocks[fromBlock].Block.Timestamp = timestamp
75 // Insert blocks into DB
76 for i := 0; i < len(blocks); i++ {
77 err := historyDB.AddBlock(&blocks[i].Block)
78 assert.NoError(t, err)
79 }
80 // Add block 0 to the generated blocks
81 blocks = append(
82 []common.BlockData{{Block: test.Block0}}, //nolint:gofmt
83 blocks...,
84 )
85 // Get all blocks from DB
86 fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
87 assert.Equal(t, len(blocks), len(fetchedBlocks))
88 // Compare generated vs getted blocks
89 assert.NoError(t, err)
90 for i := range fetchedBlocks {
91 assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
92 }
93 // Compare saved timestamp vs getted
94 nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
95 zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
96 assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
97 assert.Equal(t, offsetUTC, offsetFetchedBlock)
98 // Get blocks from the DB one by one
99 for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
100 fetchedBlock, err := historyDB.GetBlock(i)
101 assert.NoError(t, err)
102 assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
103 }
104 // Get last block
105 lastBlock, err := historyDB.GetLastBlock()
106 assert.NoError(t, err)
107 assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
108}
109
110func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
111 assert.Equal(t, expected.Num, actual.Num)
112 assert.Equal(t, expected.Hash, actual.Hash)
113 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
114}
115
116func TestBatches(t *testing.T) {
117 // Reset DB
118 test.WipeDB(historyDB.DB())
119 // Generate batches using til (and blocks for foreign key)
120 set := `
121 Type: Blockchain
122
123 AddToken(1) // Will have value in USD
124 AddToken(2) // Will NOT have value in USD
125 CreateAccountDeposit(1) A: 2000
126 CreateAccountDeposit(2) A: 2000
127 CreateAccountDeposit(1) B: 1000
128 CreateAccountDeposit(2) B: 1000
129 > batchL1
130 > batchL1
131 Transfer(1) A-B: 100 (5)
132 Transfer(2) B-A: 100 (199)
133 > batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
134 > block
135 Transfer(1) A-B: 100 (5)
136 > batch // batchNum=3, L2 only batch, forges transfer (with USD value)
137 Transfer(2) B-A: 100 (199)
138 > batch // batchNum=4, L2 only batch, forges transfer (without USD value)
139 > block
140 `
141 tc := til.NewContext(common.RollupConstMaxL1UserTx)
142 tilCfgExtra := til.ConfigExtra{
143 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
144 CoordUser: "A",
145 }
146 blocks, err := tc.GenerateBlocks(set)
147 require.Nil(t, err)
148 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
149 assert.Nil(t, err)
150 // Insert to DB
151 batches := []common.Batch{}
152 tokensValue := make(map[common.TokenID]float64)
153 lastL1TxsNum := new(int64)
154 lastL1BatchBlockNum := int64(0)
155 for _, block := range blocks {
156 // Insert block
157 assert.NoError(t, historyDB.AddBlock(&block.Block))
158 // Insert tokens
159 for i, token := range block.Rollup.AddedTokens {
160 assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
161 if i%2 != 0 {
162 // Set value to the token
163 value := (float64(i) + 5) * 5.389329
164 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
165 tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
166 }
167 }
168 // Combine all generated batches into single array
169 for _, batch := range block.Rollup.Batches {
170 batches = append(batches, batch.Batch)
171 forgeTxsNum := batch.Batch.ForgeL1TxsNum
172 if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
173 *lastL1TxsNum = *forgeTxsNum
174 lastL1BatchBlockNum = batch.Batch.EthBlockNum
175 }
176 }
177 }
178 // Insert batches
179 assert.NoError(t, historyDB.AddBatches(batches))
180 // Set expected total fee
181 for _, batch := range batches {
182 total := .0
183 for tokenID, amount := range batch.CollectedFees {
184 af := new(big.Float).SetInt(amount)
185 amountFloat, _ := af.Float64()
186 total += tokensValue[tokenID] * amountFloat
187 }
188 batch.TotalFeesUSD = &total
189 }
190 // Get batches from the DB
191 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
192 assert.NoError(t, err)
193 assert.Equal(t, len(batches), len(fetchedBatches))
194 for i, fetchedBatch := range fetchedBatches {
195 assert.Equal(t, batches[i], fetchedBatch)
196 }
197 // Test GetLastBatchNum
198 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
199 assert.NoError(t, err)
200 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
201 // Test GetLastL1TxsNum
202 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
203 assert.NoError(t, err)
204 assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
205 // Test GetLastL1BatchBlockNum
206 fetchedLastL1BatchBlockNum, err := historyDB.GetLastL1BatchBlockNum()
207 assert.NoError(t, err)
208 assert.Equal(t, lastL1BatchBlockNum, fetchedLastL1BatchBlockNum)
209}
210
211func TestBids(t *testing.T) {
212 const fromBlock int64 = 1
213 const toBlock int64 = 5
214 // Prepare blocks in the DB
215 blocks := setTestBlocks(fromBlock, toBlock)
216 // Generate fake coordinators
217 const nCoords = 5
218 coords := test.GenCoordinators(nCoords, blocks)
219 err := historyDB.AddCoordinators(coords)
220 assert.NoError(t, err)
221 // Generate fake bids
222 const nBids = 20
223 bids := test.GenBids(nBids, blocks, coords)
224 err = historyDB.AddBids(bids)
225 assert.NoError(t, err)
226 // Fetch bids
227 fetchedBids, err := historyDB.GetAllBids()
228 assert.NoError(t, err)
229 // Compare fetched bids vs generated bids
230 for i, bid := range fetchedBids {
231 assert.Equal(t, bids[i], bid)
232 }
233}
234
235func TestTokens(t *testing.T) {
236 const fromBlock int64 = 1
237 const toBlock int64 = 5
238 // Prepare blocks in the DB
239 blocks := setTestBlocks(fromBlock, toBlock)
240 // Generate fake tokens
241 const nTokens = 5
242 tokens, ethToken := test.GenTokens(nTokens, blocks)
243 err := historyDB.AddTokens(tokens)
244 assert.NoError(t, err)
245 tokens = append([]common.Token{ethToken}, tokens...)
246 limit := uint(10)
247 // Fetch tokens
248 fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
249 assert.NoError(t, err)
250 // Compare fetched tokens vs generated tokens
251 // All the tokens should have USDUpdate setted by the DB trigger
252 for i, token := range fetchedTokens {
253 assert.Equal(t, tokens[i].TokenID, token.TokenID)
254 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
255 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
256 assert.Equal(t, tokens[i].Name, token.Name)
257 assert.Equal(t, tokens[i].Symbol, token.Symbol)
258 assert.Nil(t, token.USD)
259 assert.Nil(t, token.USDUpdate)
260 }
261
262 // Update token value
263 for i, token := range tokens {
264 value := 1.01 * float64(i)
265 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
266 }
267 // Fetch tokens
268 fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
269 assert.NoError(t, err)
270 // Compare fetched tokens vs generated tokens
271 // All the tokens should have USDUpdate setted by the DB trigger
272 for i, token := range fetchedTokens {
273 value := 1.01 * float64(i)
274 assert.Equal(t, value, *token.USD)
275 nameZone, offset := token.USDUpdate.Zone()
276 assert.Equal(t, "UTC", nameZone)
277 assert.Equal(t, 0, offset)
278 }
279}
280
281func TestAccounts(t *testing.T) {
282 const fromBlock int64 = 1
283 const toBlock int64 = 5
284 // Prepare blocks in the DB
285 blocks := setTestBlocks(fromBlock, toBlock)
286 // Generate fake tokens
287 const nTokens = 5
288 tokens, ethToken := test.GenTokens(nTokens, blocks)
289 err := historyDB.AddTokens(tokens)
290 assert.NoError(t, err)
291 tokens = append([]common.Token{ethToken}, tokens...)
292 // Generate fake batches
293 const nBatches = 10
294 batches := test.GenBatches(nBatches, blocks)
295 err = historyDB.AddBatches(batches)
296 assert.NoError(t, err)
297 // Generate fake accounts
298 const nAccounts = 3
299 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
300 err = historyDB.AddAccounts(accs)
301 assert.NoError(t, err)
302 // Fetch accounts
303 fetchedAccs, err := historyDB.GetAllAccounts()
304 assert.NoError(t, err)
305 // Compare fetched accounts vs generated accounts
306 for i, acc := range fetchedAccs {
307 accs[i].Balance = nil
308 assert.Equal(t, accs[i], acc)
309 }
310}
311
312func TestTxs(t *testing.T) {
313 // Reset DB
314 test.WipeDB(historyDB.DB())
315
316 set := `
317 Type: Blockchain
318
319 AddToken(1)
320 AddToken(2)
321 CreateAccountDeposit(1) A: 10
322 CreateAccountDeposit(1) B: 10
323 > batchL1
324 > batchL1
325 > block
326
327 CreateAccountDepositTransfer(1) C-A: 20, 10
328 CreateAccountCoordinator(1) User0
329 > batchL1
330 > batchL1
331 > block
332
333 Deposit(1) B: 10
334 Deposit(1) C: 10
335 Transfer(1) C-A : 10 (1)
336 Transfer(1) B-C : 10 (1)
337 Transfer(1) A-B : 10 (1)
338 Exit(1) A: 10 (1)
339 > batch
340 > block
341
342 DepositTransfer(1) A-B: 10, 10
343 > batchL1
344 > block
345
346 ForceTransfer(1) A-B: 10
347 ForceExit(1) A: 5
348 > batchL1
349 > batchL1
350 > block
351
352 CreateAccountDeposit(2) D: 10
353 > batchL1
354 > block
355
356 CreateAccountDeposit(2) E: 10
357 > batchL1
358 > batchL1
359 > block
360
361 `
362 tc := til.NewContext(common.RollupConstMaxL1UserTx)
363 tilCfgExtra := til.ConfigExtra{
364 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
365 CoordUser: "A",
366 }
367 blocks, err := tc.GenerateBlocks(set)
368 require.Nil(t, err)
369 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
370 assert.Nil(t, err)
371
372 // Sanity check
373 require.Equal(t, 7, len(blocks))
374 require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
375 require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
376 require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
377 require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
378 require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
379 require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
380 require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
381
382 var null *common.BatchNum = nil
383 var txID common.TxID
384
385 // Insert blocks into DB
386 for i := range blocks {
387 if i == len(blocks)-1 {
388 blocks[i].Block.Timestamp = time.Now()
389 dbL1Txs, err := historyDB.GetAllL1UserTxs()
390 assert.NoError(t, err)
391 // Check batch_num is nil before forging
392 assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
393 // Save this TxId
394 txID = dbL1Txs[len(dbL1Txs)-1].TxID
395 }
396 err = historyDB.AddBlockSCData(&blocks[i])
397 assert.NoError(t, err)
398 }
399
400 // Check blocks
401 dbBlocks, err := historyDB.GetAllBlocks()
402 assert.NoError(t, err)
403 assert.Equal(t, len(blocks)+1, len(dbBlocks))
404
405 // Check batches
406 batches, err := historyDB.GetAllBatches()
407 assert.NoError(t, err)
408 assert.Equal(t, 11, len(batches))
409
410 // Check L1 Transactions
411 dbL1Txs, err := historyDB.GetAllL1UserTxs()
412 assert.NoError(t, err)
413 assert.Equal(t, 10, len(dbL1Txs))
414
415 // Tx Type
416 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
417 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
418 assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
419 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
420 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
421 assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
422 assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
423 assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
424 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
425 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
426
427 // Tx ID
428 assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
429 assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
430 assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
431 assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
432 assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
433 assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
434 assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
435 assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
436 assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
437 assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
438
439 // Tx From IDx
440 assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
441 assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
442 assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
443 assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
444 assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
445 assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
446 assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
447 assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
448 assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
449 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
450 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
451 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
452 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
453
454 // Tx to IDx
455 assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
456 assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
457 assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
458
459 // Token ID
460 assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
461 assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
462 assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
463 assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
464 assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
465 assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
466 assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
467 assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
468 assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
469 assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
470
471 // Batch Number
472 var bn common.BatchNum = common.BatchNum(2)
473
474 assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
475 assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
476
477 bn = common.BatchNum(4)
478 assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
479
480 bn = common.BatchNum(7)
481 assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
482 assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
483 assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
484
485 bn = common.BatchNum(8)
486 assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
487 assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
488
489 bn = common.BatchNum(10)
490 assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
491
492 bn = common.BatchNum(11)
493 assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
494
495 // eth_block_num
496 assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
497 assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
498 assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
499 assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
500 assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
501 assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
502 assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
503 assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
504 assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
505 assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
506
507 // User Origin
508 assert.Equal(t, true, dbL1Txs[0].UserOrigin)
509 assert.Equal(t, true, dbL1Txs[1].UserOrigin)
510 assert.Equal(t, true, dbL1Txs[2].UserOrigin)
511 assert.Equal(t, true, dbL1Txs[3].UserOrigin)
512 assert.Equal(t, true, dbL1Txs[4].UserOrigin)
513 assert.Equal(t, true, dbL1Txs[5].UserOrigin)
514 assert.Equal(t, true, dbL1Txs[6].UserOrigin)
515 assert.Equal(t, true, dbL1Txs[7].UserOrigin)
516 assert.Equal(t, true, dbL1Txs[8].UserOrigin)
517 assert.Equal(t, true, dbL1Txs[9].UserOrigin)
518
519 // Load Amount
520 assert.Equal(t, big.NewInt(10), dbL1Txs[0].LoadAmount)
521 assert.Equal(t, big.NewInt(10), dbL1Txs[1].LoadAmount)
522 assert.Equal(t, big.NewInt(20), dbL1Txs[2].LoadAmount)
523 assert.Equal(t, big.NewInt(10), dbL1Txs[3].LoadAmount)
524 assert.Equal(t, big.NewInt(10), dbL1Txs[4].LoadAmount)
525 assert.Equal(t, big.NewInt(10), dbL1Txs[5].LoadAmount)
526 assert.Equal(t, big.NewInt(0), dbL1Txs[6].LoadAmount)
527 assert.Equal(t, big.NewInt(0), dbL1Txs[7].LoadAmount)
528 assert.Equal(t, big.NewInt(10), dbL1Txs[8].LoadAmount)
529 assert.Equal(t, big.NewInt(10), dbL1Txs[9].LoadAmount)
530
531 // Check saved txID's batch_num is not nil
532 assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
533 assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
534
535 // Check Coordinator TXs
536 coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
537 assert.NoError(t, err)
538 assert.Equal(t, 1, len(coordTxs))
539 assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
540 assert.Equal(t, false, coordTxs[0].UserOrigin)
541
542 // Check L2 TXs
543 dbL2Txs, err := historyDB.GetAllL2Txs()
544 assert.NoError(t, err)
545 assert.Equal(t, 4, len(dbL2Txs))
546
547 // Tx Type
548 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
549 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
550 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
551 assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
552
553 // Tx ID
554 assert.Equal(t, "0x020000000001030000000001", dbL2Txs[0].TxID.String())
555 assert.Equal(t, "0x020000000001010000000001", dbL2Txs[1].TxID.String())
556 assert.Equal(t, "0x020000000001000000000001", dbL2Txs[2].TxID.String())
557 assert.Equal(t, "0x020000000001000000000002", dbL2Txs[3].TxID.String())
558
559 // Tx From and To IDx
560 assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
561 assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
562 assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
563
564 // Batch Number
565 assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
566 assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
567 assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
568 assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
569
570 // eth_block_num
571 assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
572 assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
573 assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
574
575 // Amount
576 assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
577 assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
578 assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
579 assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
580}
581
582func TestExitTree(t *testing.T) {
583 nBatches := 17
584 blocks := setTestBlocks(1, 10)
585 batches := test.GenBatches(nBatches, blocks)
586 err := historyDB.AddBatches(batches)
587 assert.NoError(t, err)
588 const nTokens = 50
589 tokens, ethToken := test.GenTokens(nTokens, blocks)
590 err = historyDB.AddTokens(tokens)
591 assert.NoError(t, err)
592 tokens = append([]common.Token{ethToken}, tokens...)
593 const nAccounts = 3
594 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
595 assert.NoError(t, historyDB.AddAccounts(accs))
596 exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
597 err = historyDB.AddExitTree(exitTree)
598 assert.NoError(t, err)
599}
600
601func TestGetL1UserTxs(t *testing.T) {
602 test.WipeDB(historyDB.DB())
603
604 set := `
605 Type: Blockchain
606 AddToken(1)
607 AddToken(2)
608 AddToken(3)
609
610 CreateAccountDeposit(1) A: 20
611 CreateAccountDeposit(2) A: 20
612 CreateAccountDeposit(1) B: 5
613 CreateAccountDeposit(1) C: 5
614 CreateAccountDeposit(1) D: 5
615
616 > block
617 `
618 tc := til.NewContext(128)
619 blocks, err := tc.GenerateBlocks(set)
620 require.Nil(t, err)
621 // Sanity check
622 require.Equal(t, 1, len(blocks))
623 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
624
625 toForgeL1TxsNum := int64(1)
626
627 for i := range blocks {
628 err = historyDB.AddBlockSCData(&blocks[i])
629 require.Nil(t, err)
630 }
631
632 l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
633 require.Nil(t, err)
634 assert.Equal(t, 5, len(l1UserTxs))
635 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
636
637 // No l1UserTxs for this toForgeL1TxsNum
638 l1UserTxs, err = historyDB.GetL1UserTxs(2)
639 require.Nil(t, err)
640 assert.Equal(t, 0, len(l1UserTxs))
641}
642
643func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
644 //nolint:govet
645 rollup := &common.RollupVariables{
646 0,
647 big.NewInt(10),
648 12,
649 13,
650 [5]common.Bucket{},
651 }
652 //nolint:govet
653 auction := &common.AuctionVariables{
654 0,
655 ethCommon.BigToAddress(big.NewInt(2)),
656 ethCommon.BigToAddress(big.NewInt(3)),
657 [6]*big.Int{
658 big.NewInt(1), big.NewInt(2), big.NewInt(3),
659 big.NewInt(4), big.NewInt(5), big.NewInt(6),
660 },
661 0,
662 2,
663 4320,
664 [3]uint16{10, 11, 12},
665 1000,
666 20,
667 }
668 //nolint:govet
669 wDelayer := &common.WDelayerVariables{
670 0,
671 ethCommon.BigToAddress(big.NewInt(2)),
672 ethCommon.BigToAddress(big.NewInt(3)),
673 ethCommon.BigToAddress(big.NewInt(4)),
674 13,
675 14,
676 false,
677 }
678 return rollup, auction, wDelayer
679}
680
681func TestSetInitialSCVars(t *testing.T) {
682 test.WipeDB(historyDB.DB())
683 _, _, _, err := historyDB.GetSCVars()
684 assert.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
685 rollup, auction, wDelayer := exampleInitSCVars()
686 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
687 require.Nil(t, err)
688 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
689 assert.Nil(t, err)
690 require.Equal(t, rollup, dbRollup)
691 require.Equal(t, auction, dbAuction)
692 require.Equal(t, wDelayer, dbWDelayer)
693}
694
695func TestSetL1UserTxEffectiveAmounts(t *testing.T) {
696 test.WipeDB(historyDB.DB())
697
698 set := `
699 Type: Blockchain
700
701 AddToken(1)
702
703 CreateAccountDeposit(1) A: 2000
704 CreateAccountDeposit(1) B: 500
705 CreateAccountDeposit(1) C: 500
706
707 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{*}
708 > block // blockNum=2
709
710 > batchL1 // forge defined L1UserTxs{*}
711 > block // blockNum=3
712 `
713
714 tc := til.NewContext(common.RollupConstMaxL1UserTx)
715 tilCfgExtra := til.ConfigExtra{
716 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
717 CoordUser: "A",
718 }
719 blocks, err := tc.GenerateBlocks(set)
720 require.Nil(t, err)
721 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
722 assert.Nil(t, err)
723 err = tc.FillBlocksForgedL1UserTxs(blocks)
724 require.Nil(t, err)
725
726 // Add only first block so that the L1UserTxs are not marked as forged
727 for i := range blocks[:1] {
728 err = historyDB.AddBlockSCData(&blocks[i])
729 require.Nil(t, err)
730 }
731
732 // Set the Effective{Amount,LoadAmount} of the L1UserTxs that are forged in the second block
733 l1Txs := blocks[1].Rollup.Batches[0].L1UserTxs
734 require.Equal(t, 3, len(l1Txs))
735 // Change some values to test all cases
736 l1Txs[1].EffectiveAmount = big.NewInt(0)
737 l1Txs[2].EffectiveLoadAmount = big.NewInt(0)
738 l1Txs[2].EffectiveAmount = big.NewInt(0)
739 err = historyDB.setL1UserTxEffectiveAmounts(historyDB.db, l1Txs)
740 require.NoError(t, err)
741
742 dbL1Txs, err := historyDB.GetAllL1UserTxs()
743 require.NoError(t, err)
744 for _, tx := range dbL1Txs {
745 assert.NotNil(t, tx.EffectiveAmount)
746 assert.NotNil(t, tx.EffectiveLoadAmount)
747 switch tx.TxID {
748 case l1Txs[0].TxID:
749 assert.Equal(t, l1Txs[0].LoadAmount, tx.EffectiveLoadAmount)
750 assert.Equal(t, l1Txs[0].Amount, tx.EffectiveAmount)
751 case l1Txs[1].TxID:
752 assert.Equal(t, l1Txs[1].LoadAmount, tx.EffectiveLoadAmount)
753 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
754 case l1Txs[2].TxID:
755 assert.Equal(t, big.NewInt(0), tx.EffectiveLoadAmount)
756 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
757 }
758 }
759}
760
761func TestUpdateExitTree(t *testing.T) {
762 test.WipeDB(historyDB.DB())
763
764 set := `
765 Type: Blockchain
766
767 AddToken(1)
768
769 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
770 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
771
772 CreateAccountCoordinator(1) A // Idx=256+0=256
773 CreateAccountCoordinator(1) B // Idx=256+1=257
774
775 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
776 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
777 > block // blockNum=2
778
779 ForceExit(1) A: 100
780 ForceExit(1) B: 80
781
782 Exit(1) C: 50 (172)
783 Exit(1) D: 30 (172)
784
785 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
786 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
787 > block // blockNum=3
788
789 > block // blockNum=4 (empty block)
790 > block // blockNum=5 (empty block)
791 `
792
793 tc := til.NewContext(common.RollupConstMaxL1UserTx)
794 tilCfgExtra := til.ConfigExtra{
795 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
796 CoordUser: "A",
797 }
798 blocks, err := tc.GenerateBlocks(set)
799 require.Nil(t, err)
800 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
801 assert.Nil(t, err)
802
803 // Add all blocks except for the last two
804 for i := range blocks[:len(blocks)-2] {
805 err = historyDB.AddBlockSCData(&blocks[i])
806 require.Nil(t, err)
807 }
808
809 // Add withdraws to the second-to-last block, and insert block into the DB
810 block := &blocks[len(blocks)-2]
811 require.Equal(t, int64(4), block.Block.Num)
812 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
813 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
814 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
815 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
816 // )
817 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
818 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
819 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
820 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
821 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
822 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
823 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
824 )
825 err = historyDB.addBlock(historyDB.db, &block.Block)
826 require.Nil(t, err)
827
828 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
829 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
830 require.Nil(t, err)
831
832 // Check that exits in DB match with the expected values
833 dbExits, err := historyDB.GetAllExits()
834 require.Nil(t, err)
835 assert.Equal(t, 4, len(dbExits))
836 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
837 for _, dbExit := range dbExits {
838 dbExitsByIdx[dbExit.AccountIdx] = dbExit
839 }
840 for _, withdraw := range block.Rollup.Withdrawals {
841 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
842 if withdraw.InstantWithdraw {
843 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
844 } else {
845 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
846 }
847 }
848
849 // Add delayed withdraw to the last block, and insert block into the DB
850 block = &blocks[len(blocks)-1]
851 require.Equal(t, int64(5), block.Block.Num)
852 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
853 common.WDelayerTransfer{
854 Owner: tc.UsersByIdx[257].Addr,
855 Token: tokenAddr,
856 Amount: big.NewInt(80),
857 })
858 err = historyDB.addBlock(historyDB.db, &block.Block)
859 require.Nil(t, err)
860
861 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
862 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
863 require.Nil(t, err)
864
865 // Check that delayed withdrawn has been set
866 dbExits, err = historyDB.GetAllExits()
867 require.Nil(t, err)
868 for _, dbExit := range dbExits {
869 dbExitsByIdx[dbExit.AccountIdx] = dbExit
870 }
871 require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
872}
873
874func TestGetBestBidCoordinator(t *testing.T) {
875 test.WipeDB(historyDB.DB())
876
877 rollup, auction, wDelayer := exampleInitSCVars()
878 err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
879 require.Nil(t, err)
880
881 tc := til.NewContext(common.RollupConstMaxL1UserTx)
882 blocks, err := tc.GenerateBlocks(`
883 Type: Blockchain
884 > block // blockNum=2
885 `)
886 require.Nil(t, err)
887 err = historyDB.AddBlockSCData(&blocks[0])
888 require.Nil(t, err)
889
890 coords := []common.Coordinator{
891 {
892 Bidder: ethCommon.BigToAddress(big.NewInt(1)),
893 Forger: ethCommon.BigToAddress(big.NewInt(2)),
894 EthBlockNum: 2,
895 URL: "foo",
896 },
897 {
898 Bidder: ethCommon.BigToAddress(big.NewInt(3)),
899 Forger: ethCommon.BigToAddress(big.NewInt(4)),
900 EthBlockNum: 2,
901 URL: "bar",
902 },
903 }
904 err = historyDB.addCoordinators(historyDB.db, coords)
905 require.Nil(t, err)
906 err = historyDB.addBids(historyDB.db, []common.Bid{
907 {
908 SlotNum: 10,
909 BidValue: big.NewInt(10),
910 EthBlockNum: 2,
911 Bidder: coords[0].Bidder,
912 },
913 {
914 SlotNum: 10,
915 BidValue: big.NewInt(20),
916 EthBlockNum: 2,
917 Bidder: coords[1].Bidder,
918 },
919 })
920 require.Nil(t, err)
921
922 forger10, err := historyDB.GetBestBidCoordinator(10)
923 require.Nil(t, err)
924 require.Equal(t, coords[1].Forger, forger10.Forger)
925 require.Equal(t, coords[1].Bidder, forger10.Bidder)
926 require.Equal(t, coords[1].URL, forger10.URL)
927
928 _, err = historyDB.GetBestBidCoordinator(11)
929 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
930}
931
932// setTestBlocks WARNING: this will delete the blocks and recreate them
933func setTestBlocks(from, to int64) []common.Block {
934 test.WipeDB(historyDB.DB())
935 blocks := test.GenBlocks(from, to)
936 if err := historyDB.AddBlocks(blocks); err != nil {
937 panic(err)
938 }
939 return blocks
940}