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.Num, actual.Num)
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 lastL1BatchBlockNum := int64(0)
154 for _, block := range blocks {
155 // Insert block
156 assert.NoError(t, historyDB.AddBlock(&block.Block))
157 // Insert tokens
158 for i, token := range block.Rollup.AddedTokens {
159 assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
160 if i%2 != 0 {
161 // Set value to the token
162 value := (float64(i) + 5) * 5.389329
163 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
164 tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
165 }
166 }
167 // Combine all generated batches into single array
168 for _, batch := range block.Rollup.Batches {
169 batches = append(batches, batch.Batch)
170 forgeTxsNum := batch.Batch.ForgeL1TxsNum
171 if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
172 *lastL1TxsNum = *forgeTxsNum
173 lastL1BatchBlockNum = batch.Batch.EthBlockNum
174 }
175 }
176 }
177 // Insert batches
178 assert.NoError(t, historyDB.AddBatches(batches))
179 // Set expected total fee
180 for _, batch := range batches {
181 total := .0
182 for tokenID, amount := range batch.CollectedFees {
183 af := new(big.Float).SetInt(amount)
184 amountFloat, _ := af.Float64()
185 total += tokensValue[tokenID] * amountFloat
186 }
187 batch.TotalFeesUSD = &total
188 }
189 // Get batches from the DB
190 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
191 assert.NoError(t, err)
192 assert.Equal(t, len(batches), len(fetchedBatches))
193 for i, fetchedBatch := range fetchedBatches {
194 assert.Equal(t, batches[i], fetchedBatch)
195 }
196 // Test GetLastBatchNum
197 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
198 assert.NoError(t, err)
199 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
200 // Test GetLastL1TxsNum
201 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
202 assert.NoError(t, err)
203 assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
204 // Test GetLastL1BatchBlockNum
205 fetchedLastL1BatchBlockNum, err := historyDB.GetLastL1BatchBlockNum()
206 assert.NoError(t, err)
207 assert.Equal(t, lastL1BatchBlockNum, fetchedLastL1BatchBlockNum)
208}
209
210func TestBids(t *testing.T) {
211 const fromBlock int64 = 1
212 const toBlock int64 = 5
213 // Prepare blocks in the DB
214 blocks := setTestBlocks(fromBlock, toBlock)
215 // Generate fake coordinators
216 const nCoords = 5
217 coords := test.GenCoordinators(nCoords, blocks)
218 err := historyDB.AddCoordinators(coords)
219 assert.NoError(t, err)
220 // Generate fake bids
221 const nBids = 20
222 bids := test.GenBids(nBids, blocks, coords)
223 err = historyDB.AddBids(bids)
224 assert.NoError(t, err)
225 // Fetch bids
226 fetchedBids, err := historyDB.GetAllBids()
227 assert.NoError(t, err)
228 // Compare fetched bids vs generated bids
229 for i, bid := range fetchedBids {
230 assert.Equal(t, bids[i], bid)
231 }
232}
233
234func TestTokens(t *testing.T) {
235 const fromBlock int64 = 1
236 const toBlock int64 = 5
237 // Prepare blocks in the DB
238 blocks := setTestBlocks(fromBlock, toBlock)
239 // Generate fake tokens
240 const nTokens = 5
241 tokens, ethToken := test.GenTokens(nTokens, blocks)
242 err := historyDB.AddTokens(tokens)
243 assert.NoError(t, err)
244 tokens = append([]common.Token{ethToken}, tokens...)
245 limit := uint(10)
246 // Fetch tokens
247 fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
248 assert.NoError(t, err)
249 // Compare fetched tokens vs generated tokens
250 // All the tokens should have USDUpdate setted by the DB trigger
251 for i, token := range fetchedTokens {
252 assert.Equal(t, tokens[i].TokenID, token.TokenID)
253 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
254 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
255 assert.Equal(t, tokens[i].Name, token.Name)
256 assert.Equal(t, tokens[i].Symbol, token.Symbol)
257 assert.Nil(t, token.USD)
258 assert.Nil(t, token.USDUpdate)
259 }
260
261 // Update token value
262 for i, token := range tokens {
263 value := 1.01 * float64(i)
264 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
265 }
266 // Fetch tokens
267 fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
268 assert.NoError(t, err)
269 // Compare fetched tokens vs generated tokens
270 // All the tokens should have USDUpdate setted by the DB trigger
271 for i, token := range fetchedTokens {
272 value := 1.01 * float64(i)
273 assert.Equal(t, value, *token.USD)
274 nameZone, offset := token.USDUpdate.Zone()
275 assert.Equal(t, "UTC", nameZone)
276 assert.Equal(t, 0, offset)
277 }
278}
279
280func TestAccounts(t *testing.T) {
281 const fromBlock int64 = 1
282 const toBlock int64 = 5
283 // Prepare blocks in the DB
284 blocks := setTestBlocks(fromBlock, toBlock)
285 // Generate fake tokens
286 const nTokens = 5
287 tokens, ethToken := test.GenTokens(nTokens, blocks)
288 err := historyDB.AddTokens(tokens)
289 assert.NoError(t, err)
290 tokens = append([]common.Token{ethToken}, tokens...)
291 // Generate fake batches
292 const nBatches = 10
293 batches := test.GenBatches(nBatches, blocks)
294 err = historyDB.AddBatches(batches)
295 assert.NoError(t, err)
296 // Generate fake accounts
297 const nAccounts = 3
298 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
299 err = historyDB.AddAccounts(accs)
300 assert.NoError(t, err)
301 // Fetch accounts
302 fetchedAccs, err := historyDB.GetAllAccounts()
303 assert.NoError(t, err)
304 // Compare fetched accounts vs generated accounts
305 for i, acc := range fetchedAccs {
306 accs[i].Balance = nil
307 assert.Equal(t, accs[i], acc)
308 }
309}
310
311func TestTxs(t *testing.T) {
312 // Reset DB
313 test.WipeDB(historyDB.DB())
314
315 set := `
316 Type: Blockchain
317
318 AddToken(1)
319 AddToken(2)
320 CreateAccountDeposit(1) A: 10
321 CreateAccountDeposit(1) B: 10
322 > batchL1
323 > batchL1
324 > block
325
326 CreateAccountDepositTransfer(1) C-A: 20, 10
327 CreateAccountCoordinator(1) User0
328 > batchL1
329 > batchL1
330 > block
331
332 Deposit(1) B: 10
333 Deposit(1) C: 10
334 Transfer(1) C-A : 10 (1)
335 Transfer(1) B-C : 10 (1)
336 Transfer(1) A-B : 10 (1)
337 Exit(1) A: 10 (1)
338 > batch
339 > block
340
341 DepositTransfer(1) A-B: 10, 10
342 > batchL1
343 > block
344
345 ForceTransfer(1) A-B: 10
346 ForceExit(1) A: 5
347 > batchL1
348 > batchL1
349 > block
350
351 CreateAccountDeposit(2) D: 10
352 > batchL1
353 > block
354
355 CreateAccountDeposit(2) E: 10
356 > batchL1
357 > batchL1
358 > block
359
360 `
361 tc := til.NewContext(common.RollupConstMaxL1UserTx)
362 tilCfgExtra := til.ConfigExtra{
363 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
364 CoordUser: "A",
365 }
366 blocks, err := tc.GenerateBlocks(set)
367 require.Nil(t, err)
368 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
369 assert.Nil(t, err)
370
371 // Sanity check
372 require.Equal(t, 7, len(blocks))
373 require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
374 require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
375 require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
376 require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
377 require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
378 require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
379 require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
380
381 var null *common.BatchNum = nil
382 var txID common.TxID
383
384 // Insert blocks into DB
385 for i := range blocks {
386 if i == len(blocks)-1 {
387 blocks[i].Block.Timestamp = time.Now()
388 dbL1Txs, err := historyDB.GetAllL1UserTxs()
389 assert.NoError(t, err)
390 // Check batch_num is nil before forging
391 assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
392 // Save this TxId
393 txID = dbL1Txs[len(dbL1Txs)-1].TxID
394 }
395 err = historyDB.AddBlockSCData(&blocks[i])
396 assert.NoError(t, err)
397 }
398
399 // Check blocks
400 dbBlocks, err := historyDB.GetAllBlocks()
401 assert.NoError(t, err)
402 assert.Equal(t, len(blocks)+1, len(dbBlocks))
403
404 // Check batches
405 batches, err := historyDB.GetAllBatches()
406 assert.NoError(t, err)
407 assert.Equal(t, 11, len(batches))
408
409 // Check L1 Transactions
410 dbL1Txs, err := historyDB.GetAllL1UserTxs()
411 assert.NoError(t, err)
412 assert.Equal(t, 10, len(dbL1Txs))
413
414 // Tx Type
415 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
416 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
417 assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
418 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
419 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
420 assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
421 assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
422 assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
423 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
424 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
425
426 // Tx ID
427 assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
428 assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
429 assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
430 assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
431 assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
432 assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
433 assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
434 assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
435 assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
436 assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
437
438 // Tx From IDx
439 assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
440 assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
441 assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
442 assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
443 assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
444 assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
445 assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
446 assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
447 assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
448 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
449 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
450 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
451 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
452
453 // Tx to IDx
454 assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
455 assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
456 assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
457
458 // Token ID
459 assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
460 assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
461 assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
462 assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
463 assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
464 assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
465 assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
466 assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
467 assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
468 assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
469
470 // Batch Number
471 var bn common.BatchNum = common.BatchNum(2)
472
473 assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
474 assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
475
476 bn = common.BatchNum(4)
477 assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
478
479 bn = common.BatchNum(7)
480 assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
481 assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
482 assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
483
484 bn = common.BatchNum(8)
485 assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
486 assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
487
488 bn = common.BatchNum(10)
489 assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
490
491 bn = common.BatchNum(11)
492 assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
493
494 // eth_block_num
495 assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
496 assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
497 assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
498 assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
499 assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
500 assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
501 assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
502 assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
503 assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
504 assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
505
506 // User Origin
507 assert.Equal(t, true, dbL1Txs[0].UserOrigin)
508 assert.Equal(t, true, dbL1Txs[1].UserOrigin)
509 assert.Equal(t, true, dbL1Txs[2].UserOrigin)
510 assert.Equal(t, true, dbL1Txs[3].UserOrigin)
511 assert.Equal(t, true, dbL1Txs[4].UserOrigin)
512 assert.Equal(t, true, dbL1Txs[5].UserOrigin)
513 assert.Equal(t, true, dbL1Txs[6].UserOrigin)
514 assert.Equal(t, true, dbL1Txs[7].UserOrigin)
515 assert.Equal(t, true, dbL1Txs[8].UserOrigin)
516 assert.Equal(t, true, dbL1Txs[9].UserOrigin)
517
518 // Load Amount
519 assert.Equal(t, big.NewInt(10), dbL1Txs[0].LoadAmount)
520 assert.Equal(t, big.NewInt(10), dbL1Txs[1].LoadAmount)
521 assert.Equal(t, big.NewInt(20), dbL1Txs[2].LoadAmount)
522 assert.Equal(t, big.NewInt(10), dbL1Txs[3].LoadAmount)
523 assert.Equal(t, big.NewInt(10), dbL1Txs[4].LoadAmount)
524 assert.Equal(t, big.NewInt(10), dbL1Txs[5].LoadAmount)
525 assert.Equal(t, big.NewInt(0), dbL1Txs[6].LoadAmount)
526 assert.Equal(t, big.NewInt(0), dbL1Txs[7].LoadAmount)
527 assert.Equal(t, big.NewInt(10), dbL1Txs[8].LoadAmount)
528 assert.Equal(t, big.NewInt(10), dbL1Txs[9].LoadAmount)
529
530 // Check saved txID's batch_num is not nil
531 assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
532 assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
533
534 // Check Coordinator TXs
535 coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
536 assert.NoError(t, err)
537 assert.Equal(t, 1, len(coordTxs))
538 assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
539 assert.Equal(t, false, coordTxs[0].UserOrigin)
540
541 // Check L2 TXs
542 dbL2Txs, err := historyDB.GetAllL2Txs()
543 assert.NoError(t, err)
544 assert.Equal(t, 4, len(dbL2Txs))
545
546 // Tx Type
547 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
548 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
549 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
550 assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
551
552 // Tx ID
553 assert.Equal(t, "0x020000000001030000000001", dbL2Txs[0].TxID.String())
554 assert.Equal(t, "0x020000000001010000000001", dbL2Txs[1].TxID.String())
555 assert.Equal(t, "0x020000000001000000000001", dbL2Txs[2].TxID.String())
556 assert.Equal(t, "0x020000000001000000000002", dbL2Txs[3].TxID.String())
557
558 // Tx From and To IDx
559 assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
560 assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
561 assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
562
563 // Batch Number
564 assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
565 assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
566 assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
567 assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
568
569 // eth_block_num
570 assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
571 assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
572 assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
573
574 // Amount
575 assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
576 assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
577 assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
578 assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
579}
580
581func TestExitTree(t *testing.T) {
582 nBatches := 17
583 blocks := setTestBlocks(1, 10)
584 batches := test.GenBatches(nBatches, blocks)
585 err := historyDB.AddBatches(batches)
586 assert.NoError(t, err)
587 const nTokens = 50
588 tokens, ethToken := test.GenTokens(nTokens, blocks)
589 err = historyDB.AddTokens(tokens)
590 assert.NoError(t, err)
591 tokens = append([]common.Token{ethToken}, tokens...)
592 const nAccounts = 3
593 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
594 assert.NoError(t, historyDB.AddAccounts(accs))
595 exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
596 err = historyDB.AddExitTree(exitTree)
597 assert.NoError(t, err)
598}
599
600func TestGetL1UserTxs(t *testing.T) {
601 test.WipeDB(historyDB.DB())
602
603 set := `
604 Type: Blockchain
605 AddToken(1)
606 AddToken(2)
607 AddToken(3)
608
609 CreateAccountDeposit(1) A: 20
610 CreateAccountDeposit(2) A: 20
611 CreateAccountDeposit(1) B: 5
612 CreateAccountDeposit(1) C: 5
613 CreateAccountDeposit(1) D: 5
614
615 > block
616 `
617 tc := til.NewContext(128)
618 blocks, err := tc.GenerateBlocks(set)
619 require.Nil(t, err)
620 // Sanity check
621 require.Equal(t, 1, len(blocks))
622 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
623
624 toForgeL1TxsNum := int64(1)
625
626 for i := range blocks {
627 err = historyDB.AddBlockSCData(&blocks[i])
628 require.Nil(t, err)
629 }
630
631 l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
632 require.Nil(t, err)
633 assert.Equal(t, 5, len(l1UserTxs))
634 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
635
636 // No l1UserTxs for this toForgeL1TxsNum
637 l1UserTxs, err = historyDB.GetL1UserTxs(2)
638 require.Nil(t, err)
639 assert.Equal(t, 0, len(l1UserTxs))
640}
641
642func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
643 //nolint:govet
644 rollup := &common.RollupVariables{
645 0,
646 big.NewInt(10),
647 12,
648 13,
649 [5]common.Bucket{},
650 }
651 //nolint:govet
652 auction := &common.AuctionVariables{
653 0,
654 ethCommon.BigToAddress(big.NewInt(2)),
655 ethCommon.BigToAddress(big.NewInt(3)),
656 [6]*big.Int{
657 big.NewInt(1), big.NewInt(2), big.NewInt(3),
658 big.NewInt(4), big.NewInt(5), big.NewInt(6),
659 },
660 0,
661 2,
662 4320,
663 [3]uint16{10, 11, 12},
664 1000,
665 20,
666 }
667 //nolint:govet
668 wDelayer := &common.WDelayerVariables{
669 0,
670 ethCommon.BigToAddress(big.NewInt(2)),
671 ethCommon.BigToAddress(big.NewInt(3)),
672 ethCommon.BigToAddress(big.NewInt(4)),
673 13,
674 14,
675 false,
676 }
677 return rollup, auction, wDelayer
678}
679
680func TestSetInitialSCVars(t *testing.T) {
681 test.WipeDB(historyDB.DB())
682 _, _, _, err := historyDB.GetSCVars()
683 assert.Equal(t, sql.ErrNoRows, err)
684 rollup, auction, wDelayer := exampleInitSCVars()
685 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
686 require.Nil(t, err)
687 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
688 assert.Nil(t, err)
689 require.Equal(t, rollup, dbRollup)
690 require.Equal(t, auction, dbAuction)
691 require.Equal(t, wDelayer, dbWDelayer)
692}
693
694func TestUpdateExitTree(t *testing.T) {
695 test.WipeDB(historyDB.DB())
696
697 set := `
698 Type: Blockchain
699
700 AddToken(1)
701
702 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
703 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
704
705 CreateAccountCoordinator(1) A // Idx=256+0=256
706 CreateAccountCoordinator(1) B // Idx=256+1=257
707
708 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
709 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
710 > block // blockNum=2
711
712 ForceExit(1) A: 100
713 ForceExit(1) B: 80
714
715 Exit(1) C: 50 (172)
716 Exit(1) D: 30 (172)
717
718 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
719 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
720 > block // blockNum=3
721
722 > block // blockNum=4 (empty block)
723 > block // blockNum=5 (empty block)
724 `
725
726 tc := til.NewContext(common.RollupConstMaxL1UserTx)
727 tilCfgExtra := til.ConfigExtra{
728 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
729 CoordUser: "A",
730 }
731 blocks, err := tc.GenerateBlocks(set)
732 require.Nil(t, err)
733 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
734 assert.Nil(t, err)
735
736 // Add all blocks except for the last two
737 for i := range blocks[:len(blocks)-2] {
738 err = historyDB.AddBlockSCData(&blocks[i])
739 require.Nil(t, err)
740 }
741
742 // Add withdraws to the second-to-last block, and insert block into the DB
743 block := &blocks[len(blocks)-2]
744 require.Equal(t, int64(4), block.Block.Num)
745 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
746 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
747 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
748 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
749 // )
750 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
751 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
752 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
753 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
754 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
755 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
756 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
757 )
758 err = historyDB.addBlock(historyDB.db, &block.Block)
759 require.Nil(t, err)
760
761 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
762 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
763 require.Nil(t, err)
764
765 // Check that exits in DB match with the expected values
766 dbExits, err := historyDB.GetAllExits()
767 require.Nil(t, err)
768 assert.Equal(t, 4, len(dbExits))
769 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
770 for _, dbExit := range dbExits {
771 dbExitsByIdx[dbExit.AccountIdx] = dbExit
772 }
773 for _, withdraw := range block.Rollup.Withdrawals {
774 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
775 if withdraw.InstantWithdraw {
776 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
777 } else {
778 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
779 }
780 }
781
782 // Add delayed withdraw to the last block, and insert block into the DB
783 block = &blocks[len(blocks)-1]
784 require.Equal(t, int64(5), block.Block.Num)
785 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
786 common.WDelayerTransfer{
787 Owner: tc.UsersByIdx[257].Addr,
788 Token: tokenAddr,
789 Amount: big.NewInt(80),
790 })
791 err = historyDB.addBlock(historyDB.db, &block.Block)
792 require.Nil(t, err)
793
794 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
795 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
796 require.Nil(t, err)
797
798 // Check that delayed withdrawn has been set
799 dbExits, err = historyDB.GetAllExits()
800 require.Nil(t, err)
801 for _, dbExit := range dbExits {
802 dbExitsByIdx[dbExit.AccountIdx] = dbExit
803 }
804 require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
805}
806
807func TestGetBestBidCoordinator(t *testing.T) {
808 test.WipeDB(historyDB.DB())
809
810 rollup, auction, wDelayer := exampleInitSCVars()
811 err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
812 require.Nil(t, err)
813
814 tc := til.NewContext(common.RollupConstMaxL1UserTx)
815 blocks, err := tc.GenerateBlocks(`
816 Type: Blockchain
817 > block // blockNum=2
818 `)
819 require.Nil(t, err)
820 err = historyDB.AddBlockSCData(&blocks[0])
821 require.Nil(t, err)
822
823 coords := []common.Coordinator{
824 {
825 Bidder: ethCommon.BigToAddress(big.NewInt(1)),
826 Forger: ethCommon.BigToAddress(big.NewInt(2)),
827 EthBlockNum: 2,
828 URL: "foo",
829 },
830 {
831 Bidder: ethCommon.BigToAddress(big.NewInt(3)),
832 Forger: ethCommon.BigToAddress(big.NewInt(4)),
833 EthBlockNum: 2,
834 URL: "bar",
835 },
836 }
837 err = historyDB.addCoordinators(historyDB.db, coords)
838 require.Nil(t, err)
839 err = historyDB.addBids(historyDB.db, []common.Bid{
840 {
841 SlotNum: 10,
842 BidValue: big.NewInt(10),
843 EthBlockNum: 2,
844 Bidder: coords[0].Bidder,
845 },
846 {
847 SlotNum: 10,
848 BidValue: big.NewInt(20),
849 EthBlockNum: 2,
850 Bidder: coords[1].Bidder,
851 },
852 })
853 require.Nil(t, err)
854
855 forger10, err := historyDB.GetBestBidCoordinator(10)
856 require.Nil(t, err)
857 require.Equal(t, coords[1].Forger, forger10.Forger)
858 require.Equal(t, coords[1].Bidder, forger10.Bidder)
859 require.Equal(t, coords[1].URL, forger10.URL)
860
861 _, err = historyDB.GetBestBidCoordinator(11)
862 require.Equal(t, sql.ErrNoRows, err)
863}
864
865// setTestBlocks WARNING: this will delete the blocks and recreate them
866func setTestBlocks(from, to int64) []common.Block {
867 test.WipeDB(historyDB.DB())
868 blocks := test.GenBlocks(from, to)
869 if err := historyDB.AddBlocks(blocks); err != nil {
870 panic(err)
871 }
872 return blocks
873}