hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
1package historydb
2
3import (
4 "database/sql"
5 "fmt"
6 "math"
7 "math/big"
8 "os"
9 "strings"
10 "testing"
11 "time"
12
13 ethCommon "github.com/ethereum/go-ethereum/common"
14 "github.com/hermeznetwork/hermez-node/common"
15 dbUtils "github.com/hermeznetwork/hermez-node/db"
16 "github.com/hermeznetwork/hermez-node/log"
17 "github.com/hermeznetwork/hermez-node/test"
18 "github.com/hermeznetwork/hermez-node/test/til"
19 "github.com/hermeznetwork/tracerr"
20 "github.com/stretchr/testify/assert"
21 "github.com/stretchr/testify/require"
22)
23
24var historyDB *HistoryDB
25var historyDBWithACC *HistoryDB
26
27// In order to run the test you need to run a Posgres DB with
28// a database named "history" that is accessible by
29// user: "hermez"
30// pass: set it using the env var POSTGRES_PASS
31// 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;"
32// After running the test you can stop the container by running: sudo docker kill hermez-db-test
33// If you already did that for the L2DB you don't have to do it again
34
35func TestMain(m *testing.M) {
36 // init DB
37 pass := os.Getenv("POSTGRES_PASS")
38 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
39 if err != nil {
40 panic(err)
41 }
42 historyDB = NewHistoryDB(db, nil)
43 if err != nil {
44 panic(err)
45 }
46 apiConnCon := dbUtils.NewAPICnnectionController(1, time.Second)
47 historyDBWithACC = NewHistoryDB(db, apiConnCon)
48 // Run tests
49 result := m.Run()
50 // Close DB
51 if err := db.Close(); err != nil {
52 log.Error("Error closing the history DB:", err)
53 }
54 os.Exit(result)
55}
56
57func TestBlocks(t *testing.T) {
58 var fromBlock, toBlock int64
59 fromBlock = 0
60 toBlock = 7
61 // Reset DB
62 test.WipeDB(historyDB.DB())
63 // Generate blocks using til
64 set1 := `
65 Type: Blockchain
66 // block 0 is stored as default in the DB
67 // block 1 does not exist
68 > block // blockNum=2
69 > block // blockNum=3
70 > block // blockNum=4
71 > block // blockNum=5
72 > block // blockNum=6
73 `
74 tc := til.NewContext(uint16(0), 1)
75 blocks, err := tc.GenerateBlocks(set1)
76 require.NoError(t, err)
77 // Save timestamp of a block with UTC and change it without UTC
78 timestamp := time.Now().Add(time.Second * 13)
79 blocks[fromBlock].Block.Timestamp = timestamp
80 // Insert blocks into DB
81 for i := 0; i < len(blocks); i++ {
82 err := historyDB.AddBlock(&blocks[i].Block)
83 assert.NoError(t, err)
84 }
85 // Add block 0 to the generated blocks
86 blocks = append(
87 []common.BlockData{{Block: test.Block0}}, //nolint:gofmt
88 blocks...,
89 )
90 // Get all blocks from DB
91 fetchedBlocks, err := historyDB.getBlocks(fromBlock, toBlock)
92 assert.Equal(t, len(blocks), len(fetchedBlocks))
93 // Compare generated vs getted blocks
94 assert.NoError(t, err)
95 for i := range fetchedBlocks {
96 assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
97 }
98 // Compare saved timestamp vs getted
99 nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
100 zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
101 assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
102 assert.Equal(t, offsetUTC, offsetFetchedBlock)
103 // Get blocks from the DB one by one
104 for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
105 fetchedBlock, err := historyDB.GetBlock(i)
106 assert.NoError(t, err)
107 assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
108 }
109 // Get last block
110 lastBlock, err := historyDB.GetLastBlock()
111 assert.NoError(t, err)
112 assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
113}
114
115func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
116 assert.Equal(t, expected.Num, actual.Num)
117 assert.Equal(t, expected.Hash, actual.Hash)
118 assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
119}
120
121func TestBatches(t *testing.T) {
122 // Reset DB
123 test.WipeDB(historyDB.DB())
124 // Generate batches using til (and blocks for foreign key)
125 set := `
126 Type: Blockchain
127
128 AddToken(1) // Will have value in USD
129 AddToken(2) // Will NOT have value in USD
130 CreateAccountDeposit(1) A: 2000
131 CreateAccountDeposit(2) A: 2000
132 CreateAccountDeposit(1) B: 1000
133 CreateAccountDeposit(2) B: 1000
134 > batchL1
135 > batchL1
136 Transfer(1) A-B: 100 (5)
137 Transfer(2) B-A: 100 (199)
138 > batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
139 > block
140 Transfer(1) A-B: 100 (5)
141 > batch // batchNum=3, L2 only batch, forges transfer (with USD value)
142 Transfer(2) B-A: 100 (199)
143 > batch // batchNum=4, L2 only batch, forges transfer (without USD value)
144 > block
145 `
146 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
147 tilCfgExtra := til.ConfigExtra{
148 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
149 CoordUser: "A",
150 }
151 blocks, err := tc.GenerateBlocks(set)
152 require.NoError(t, err)
153 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
154 require.NoError(t, err)
155 // Insert to DB
156 batches := []common.Batch{}
157 tokensValue := make(map[common.TokenID]float64)
158 lastL1TxsNum := new(int64)
159 lastL1BatchBlockNum := int64(0)
160 for _, block := range blocks {
161 // Insert block
162 assert.NoError(t, historyDB.AddBlock(&block.Block))
163 // Insert tokens
164 for i, token := range block.Rollup.AddedTokens {
165 assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
166 if i%2 != 0 {
167 // Set value to the token
168 value := (float64(i) + 5) * 5.389329
169 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
170 tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
171 }
172 }
173 // Combine all generated batches into single array
174 for _, batch := range block.Rollup.Batches {
175 batches = append(batches, batch.Batch)
176 forgeTxsNum := batch.Batch.ForgeL1TxsNum
177 if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
178 *lastL1TxsNum = *forgeTxsNum
179 lastL1BatchBlockNum = batch.Batch.EthBlockNum
180 }
181 }
182 }
183 // Insert batches
184 assert.NoError(t, historyDB.AddBatches(batches))
185 // Set expected total fee
186 for _, batch := range batches {
187 total := .0
188 for tokenID, amount := range batch.CollectedFees {
189 af := new(big.Float).SetInt(amount)
190 amountFloat, _ := af.Float64()
191 total += tokensValue[tokenID] * amountFloat
192 }
193 batch.TotalFeesUSD = &total
194 }
195 // Get batches from the DB
196 fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
197 assert.NoError(t, err)
198 assert.Equal(t, len(batches), len(fetchedBatches))
199 for i, fetchedBatch := range fetchedBatches {
200 assert.Equal(t, batches[i], fetchedBatch)
201 }
202 // Test GetLastBatchNum
203 fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
204 assert.NoError(t, err)
205 assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
206 // Test GetLastL1TxsNum
207 fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
208 assert.NoError(t, err)
209 assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
210 // Test GetLastL1BatchBlockNum
211 fetchedLastL1BatchBlockNum, err := historyDB.GetLastL1BatchBlockNum()
212 assert.NoError(t, err)
213 assert.Equal(t, lastL1BatchBlockNum, fetchedLastL1BatchBlockNum)
214}
215
216func TestBids(t *testing.T) {
217 const fromBlock int64 = 1
218 const toBlock int64 = 5
219 // Prepare blocks in the DB
220 blocks := setTestBlocks(fromBlock, toBlock)
221 // Generate fake coordinators
222 const nCoords = 5
223 coords := test.GenCoordinators(nCoords, blocks)
224 err := historyDB.AddCoordinators(coords)
225 assert.NoError(t, err)
226 // Generate fake bids
227 const nBids = 20
228 bids := test.GenBids(nBids, blocks, coords)
229 err = historyDB.AddBids(bids)
230 assert.NoError(t, err)
231 // Fetch bids
232 fetchedBids, err := historyDB.GetAllBids()
233 assert.NoError(t, err)
234 // Compare fetched bids vs generated bids
235 for i, bid := range fetchedBids {
236 assert.Equal(t, bids[i], bid)
237 }
238}
239
240func TestTokens(t *testing.T) {
241 const fromBlock int64 = 1
242 const toBlock int64 = 5
243 // Prepare blocks in the DB
244 blocks := setTestBlocks(fromBlock, toBlock)
245 // Generate fake tokens
246 const nTokens = 5
247 tokens, ethToken := test.GenTokens(nTokens, blocks)
248 err := historyDB.AddTokens(tokens)
249 assert.NoError(t, err)
250 tokens = append([]common.Token{ethToken}, tokens...)
251 // Fetch tokens
252 fetchedTokens, err := historyDB.GetTokensTest()
253 assert.NoError(t, err)
254 // Compare fetched tokens vs generated tokens
255 // All the tokens should have USDUpdate setted by the DB trigger
256 for i, token := range fetchedTokens {
257 assert.Equal(t, tokens[i].TokenID, token.TokenID)
258 assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
259 assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
260 assert.Equal(t, tokens[i].Name, token.Name)
261 assert.Equal(t, tokens[i].Symbol, token.Symbol)
262 assert.Nil(t, token.USD)
263 assert.Nil(t, token.USDUpdate)
264 }
265
266 // Update token value
267 for i, token := range tokens {
268 value := 1.01 * float64(i)
269 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
270 }
271 // Fetch tokens
272 fetchedTokens, err = historyDB.GetTokensTest()
273 assert.NoError(t, err)
274 // Compare fetched tokens vs generated tokens
275 // All the tokens should have USDUpdate setted by the DB trigger
276 for i, token := range fetchedTokens {
277 value := 1.01 * float64(i)
278 assert.Equal(t, value, *token.USD)
279 nameZone, offset := token.USDUpdate.Zone()
280 assert.Equal(t, "UTC", nameZone)
281 assert.Equal(t, 0, offset)
282 }
283}
284
285func TestTokensUTF8(t *testing.T) {
286 // Reset DB
287 test.WipeDB(historyDB.DB())
288 const fromBlock int64 = 1
289 const toBlock int64 = 5
290 // Prepare blocks in the DB
291 blocks := setTestBlocks(fromBlock, toBlock)
292 // Generate fake tokens
293 const nTokens = 5
294 tokens, ethToken := test.GenTokens(nTokens, blocks)
295 nonUTFTokens := make([]common.Token, len(tokens)+1)
296 // Force token.name and token.symbol to be non UTF-8 Strings
297 for i, token := range tokens {
298 token.Name = fmt.Sprint("NON-UTF8-NAME-\xc5-", i)
299 token.Symbol = fmt.Sprint("S-\xc5-", i)
300 tokens[i] = token
301 nonUTFTokens[i] = token
302 }
303 err := historyDB.AddTokens(tokens)
304 assert.NoError(t, err)
305 // Work with nonUTFTokens as tokens one gets updated and non UTF-8 characters are lost
306 nonUTFTokens = append([]common.Token{ethToken}, nonUTFTokens...)
307 // Fetch tokens
308 fetchedTokens, err := historyDB.GetTokensTest()
309 assert.NoError(t, err)
310 // Compare fetched tokens vs generated tokens
311 // All the tokens should have USDUpdate setted by the DB trigger
312 for i, token := range fetchedTokens {
313 assert.Equal(t, nonUTFTokens[i].TokenID, token.TokenID)
314 assert.Equal(t, nonUTFTokens[i].EthBlockNum, token.EthBlockNum)
315 assert.Equal(t, nonUTFTokens[i].EthAddr, token.EthAddr)
316 assert.Equal(t, strings.ToValidUTF8(nonUTFTokens[i].Name, " "), token.Name)
317 assert.Equal(t, strings.ToValidUTF8(nonUTFTokens[i].Symbol, " "), token.Symbol)
318 assert.Nil(t, token.USD)
319 assert.Nil(t, token.USDUpdate)
320 }
321
322 // Update token value
323 for i, token := range nonUTFTokens {
324 value := 1.01 * float64(i)
325 assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
326 }
327 // Fetch tokens
328 fetchedTokens, err = historyDB.GetTokensTest()
329 assert.NoError(t, err)
330 // Compare fetched tokens vs generated tokens
331 // All the tokens should have USDUpdate setted by the DB trigger
332 for i, token := range fetchedTokens {
333 value := 1.01 * float64(i)
334 assert.Equal(t, value, *token.USD)
335 nameZone, offset := token.USDUpdate.Zone()
336 assert.Equal(t, "UTC", nameZone)
337 assert.Equal(t, 0, offset)
338 }
339}
340
341func TestAccounts(t *testing.T) {
342 const fromBlock int64 = 1
343 const toBlock int64 = 5
344 // Prepare blocks in the DB
345 blocks := setTestBlocks(fromBlock, toBlock)
346 // Generate fake tokens
347 const nTokens = 5
348 tokens, ethToken := test.GenTokens(nTokens, blocks)
349 err := historyDB.AddTokens(tokens)
350 assert.NoError(t, err)
351 tokens = append([]common.Token{ethToken}, tokens...)
352 // Generate fake batches
353 const nBatches = 10
354 batches := test.GenBatches(nBatches, blocks)
355 err = historyDB.AddBatches(batches)
356 assert.NoError(t, err)
357 // Generate fake accounts
358 const nAccounts = 3
359 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
360 err = historyDB.AddAccounts(accs)
361 assert.NoError(t, err)
362 // Fetch accounts
363 fetchedAccs, err := historyDB.GetAllAccounts()
364 assert.NoError(t, err)
365 // Compare fetched accounts vs generated accounts
366 for i, acc := range fetchedAccs {
367 accs[i].Balance = nil
368 assert.Equal(t, accs[i], acc)
369 }
370}
371
372func TestTxs(t *testing.T) {
373 // Reset DB
374 test.WipeDB(historyDB.DB())
375
376 set := `
377 Type: Blockchain
378
379 AddToken(1)
380 AddToken(2)
381 CreateAccountDeposit(1) A: 10
382 CreateAccountDeposit(1) B: 10
383 > batchL1
384 > batchL1
385 > block
386
387 CreateAccountDepositTransfer(1) C-A: 20, 10
388 CreateAccountCoordinator(1) User0
389 > batchL1
390 > batchL1
391 > block
392
393 Deposit(1) B: 10
394 Deposit(1) C: 10
395 Transfer(1) C-A : 10 (1)
396 Transfer(1) B-C : 10 (1)
397 Transfer(1) A-B : 10 (1)
398 Exit(1) A: 10 (1)
399 > batch
400 > block
401
402 DepositTransfer(1) A-B: 10, 10
403 > batchL1
404 > block
405
406 ForceTransfer(1) A-B: 10
407 ForceExit(1) A: 5
408 > batchL1
409 > batchL1
410 > block
411
412 CreateAccountDeposit(2) D: 10
413 > batchL1
414 > block
415
416 CreateAccountDeposit(2) E: 10
417 > batchL1
418 > batchL1
419 > block
420
421 `
422 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
423 tilCfgExtra := til.ConfigExtra{
424 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
425 CoordUser: "A",
426 }
427 blocks, err := tc.GenerateBlocks(set)
428 require.NoError(t, err)
429 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
430 require.NoError(t, err)
431
432 // Sanity check
433 require.Equal(t, 7, len(blocks))
434 require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
435 require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
436 require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
437 require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
438 require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
439 require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
440 require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
441
442 var null *common.BatchNum = nil
443 var txID common.TxID
444
445 // Insert blocks into DB
446 for i := range blocks {
447 if i == len(blocks)-1 {
448 blocks[i].Block.Timestamp = time.Now()
449 dbL1Txs, err := historyDB.GetAllL1UserTxs()
450 assert.NoError(t, err)
451 // Check batch_num is nil before forging
452 assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
453 // Save this TxId
454 txID = dbL1Txs[len(dbL1Txs)-1].TxID
455 }
456 err = historyDB.AddBlockSCData(&blocks[i])
457 assert.NoError(t, err)
458 }
459
460 // Check blocks
461 dbBlocks, err := historyDB.GetAllBlocks()
462 assert.NoError(t, err)
463 assert.Equal(t, len(blocks)+1, len(dbBlocks))
464
465 // Check batches
466 batches, err := historyDB.GetAllBatches()
467 assert.NoError(t, err)
468 assert.Equal(t, 11, len(batches))
469
470 // Check L1 Transactions
471 dbL1Txs, err := historyDB.GetAllL1UserTxs()
472 assert.NoError(t, err)
473 assert.Equal(t, 10, len(dbL1Txs))
474
475 // Tx Type
476 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
477 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
478 assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
479 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
480 assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
481 assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
482 assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
483 assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
484 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
485 assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
486
487 // Tx ID
488 assert.Equal(t, "0x00e979da4b80d60a17ce56fa19278c6f3a7e1b43359fb8a8ea46d0264de7d653ab", dbL1Txs[0].TxID.String())
489 assert.Equal(t, "0x00af9bf96eb60f2d618519402a2f6b07057a034fa2baefd379fe8e1c969f1c5cf4", dbL1Txs[1].TxID.String())
490 assert.Equal(t, "0x00a256ee191905243320ea830840fd666a73c7b4e6f89ce4bd47ddf998dfee627a", dbL1Txs[2].TxID.String())
491 assert.Equal(t, "0x00930696d03ae0a1e6150b6ccb88043cb539a4e06a7f8baf213029ce9a0600197e", dbL1Txs[3].TxID.String())
492 assert.Equal(t, "0x00de8e41d49f23832f66364e8702c4b78237eb0c95542a94d34188e51696e74fc8", dbL1Txs[4].TxID.String())
493 assert.Equal(t, "0x007a44d6d60b15f3789d4ff49d62377a70255bf13a8d42e41ef49bf4c7b77d2c1b", dbL1Txs[5].TxID.String())
494 assert.Equal(t, "0x00c33f316240f8d33a973db2d0e901e4ac1c96de30b185fcc6b63dac4d0e147bd4", dbL1Txs[6].TxID.String())
495 assert.Equal(t, "0x00b55f0882c5229d1be3d9d3c1a076290f249cd0bae5ae6e609234606befb91233", dbL1Txs[7].TxID.String())
496 assert.Equal(t, "0x009133d4c8a412ca45f50bccdbcfdb8393b0dd8efe953d0cc3bcc82796b7a581b6", dbL1Txs[8].TxID.String())
497 assert.Equal(t, "0x00f5e8ab141ac16d673e654ba7747c2f12e93ea2c50ba6c05563752ca531968c62", dbL1Txs[9].TxID.String())
498
499 // Tx From IDx
500 assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
501 assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
502 assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
503 assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
504 assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
505 assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
506 assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
507 assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
508 assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
509 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
510 assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
511 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
512 assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
513
514 // Tx to IDx
515 assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
516 assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
517 assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
518
519 // Token ID
520 assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
521 assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
522 assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
523 assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
524 assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
525 assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
526 assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
527 assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
528 assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
529 assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
530
531 // Batch Number
532 var bn common.BatchNum = common.BatchNum(2)
533
534 assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
535 assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
536
537 bn = common.BatchNum(4)
538 assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
539
540 bn = common.BatchNum(7)
541 assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
542 assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
543 assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
544
545 bn = common.BatchNum(8)
546 assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
547 assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
548
549 bn = common.BatchNum(10)
550 assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
551
552 bn = common.BatchNum(11)
553 assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
554
555 // eth_block_num
556 assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
557 assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
558 assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
559 assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
560 assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
561 assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
562 assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
563 assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
564 assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
565 assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
566
567 // User Origin
568 assert.Equal(t, true, dbL1Txs[0].UserOrigin)
569 assert.Equal(t, true, dbL1Txs[1].UserOrigin)
570 assert.Equal(t, true, dbL1Txs[2].UserOrigin)
571 assert.Equal(t, true, dbL1Txs[3].UserOrigin)
572 assert.Equal(t, true, dbL1Txs[4].UserOrigin)
573 assert.Equal(t, true, dbL1Txs[5].UserOrigin)
574 assert.Equal(t, true, dbL1Txs[6].UserOrigin)
575 assert.Equal(t, true, dbL1Txs[7].UserOrigin)
576 assert.Equal(t, true, dbL1Txs[8].UserOrigin)
577 assert.Equal(t, true, dbL1Txs[9].UserOrigin)
578
579 // Deposit Amount
580 assert.Equal(t, big.NewInt(10), dbL1Txs[0].DepositAmount)
581 assert.Equal(t, big.NewInt(10), dbL1Txs[1].DepositAmount)
582 assert.Equal(t, big.NewInt(20), dbL1Txs[2].DepositAmount)
583 assert.Equal(t, big.NewInt(10), dbL1Txs[3].DepositAmount)
584 assert.Equal(t, big.NewInt(10), dbL1Txs[4].DepositAmount)
585 assert.Equal(t, big.NewInt(10), dbL1Txs[5].DepositAmount)
586 assert.Equal(t, big.NewInt(0), dbL1Txs[6].DepositAmount)
587 assert.Equal(t, big.NewInt(0), dbL1Txs[7].DepositAmount)
588 assert.Equal(t, big.NewInt(10), dbL1Txs[8].DepositAmount)
589 assert.Equal(t, big.NewInt(10), dbL1Txs[9].DepositAmount)
590
591 // Check saved txID's batch_num is not nil
592 assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
593 assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
594
595 // Check Coordinator TXs
596 coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
597 assert.NoError(t, err)
598 assert.Equal(t, 1, len(coordTxs))
599 assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
600 assert.Equal(t, false, coordTxs[0].UserOrigin)
601
602 // Check L2 TXs
603 dbL2Txs, err := historyDB.GetAllL2Txs()
604 assert.NoError(t, err)
605 assert.Equal(t, 4, len(dbL2Txs))
606
607 // Tx Type
608 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
609 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
610 assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
611 assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
612
613 // Tx ID
614 assert.Equal(t, "0x02d709307533c4e3c03f20751fc4d72bc18b225d14f9616525540a64342c7c350d", dbL2Txs[0].TxID.String())
615 assert.Equal(t, "0x02e88bc5503f282cca045847668511290e642410a459bb67b1fafcd1b6097c149c", dbL2Txs[1].TxID.String())
616 assert.Equal(t, "0x027911262b43315c0b24942a02fe228274b6e4d57a476bfcdd7a324b3091362c7d", dbL2Txs[2].TxID.String())
617 assert.Equal(t, "0x02f572b63f2a5c302e1b9337ea6944bfbac3d199e4ddd262b5a53759c72ec10ee6", dbL2Txs[3].TxID.String())
618
619 // Tx From and To IDx
620 assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
621 assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
622 assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
623
624 // Batch Number
625 assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
626 assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
627 assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
628 assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
629
630 // eth_block_num
631 assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
632 assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
633 assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
634
635 // Amount
636 assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
637 assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
638 assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
639 assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
640}
641
642func TestExitTree(t *testing.T) {
643 nBatches := 17
644 blocks := setTestBlocks(1, 10)
645 batches := test.GenBatches(nBatches, blocks)
646 err := historyDB.AddBatches(batches)
647 assert.NoError(t, err)
648 const nTokens = 50
649 tokens, ethToken := test.GenTokens(nTokens, blocks)
650 err = historyDB.AddTokens(tokens)
651 assert.NoError(t, err)
652 tokens = append([]common.Token{ethToken}, tokens...)
653 const nAccounts = 3
654 accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
655 assert.NoError(t, historyDB.AddAccounts(accs))
656 exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
657 err = historyDB.AddExitTree(exitTree)
658 assert.NoError(t, err)
659}
660
661func TestGetUnforgedL1UserTxs(t *testing.T) {
662 test.WipeDB(historyDB.DB())
663
664 set := `
665 Type: Blockchain
666 AddToken(1)
667 AddToken(2)
668 AddToken(3)
669
670 CreateAccountDeposit(1) A: 20
671 CreateAccountDeposit(2) A: 20
672 CreateAccountDeposit(1) B: 5
673 CreateAccountDeposit(1) C: 5
674 CreateAccountDeposit(1) D: 5
675
676 > block
677 `
678 tc := til.NewContext(uint16(0), 128)
679 blocks, err := tc.GenerateBlocks(set)
680 require.NoError(t, err)
681 // Sanity check
682 require.Equal(t, 1, len(blocks))
683 require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
684
685 toForgeL1TxsNum := int64(1)
686
687 for i := range blocks {
688 err = historyDB.AddBlockSCData(&blocks[i])
689 require.NoError(t, err)
690 }
691
692 l1UserTxs, err := historyDB.GetUnforgedL1UserTxs(toForgeL1TxsNum)
693 require.NoError(t, err)
694 assert.Equal(t, 5, len(l1UserTxs))
695 assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
696
697 // No l1UserTxs for this toForgeL1TxsNum
698 l1UserTxs, err = historyDB.GetUnforgedL1UserTxs(2)
699 require.NoError(t, err)
700 assert.Equal(t, 0, len(l1UserTxs))
701}
702
703func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
704 //nolint:govet
705 rollup := &common.RollupVariables{
706 0,
707 big.NewInt(10),
708 12,
709 13,
710 [5]common.BucketParams{},
711 false,
712 }
713 //nolint:govet
714 auction := &common.AuctionVariables{
715 0,
716 ethCommon.BigToAddress(big.NewInt(2)),
717 ethCommon.BigToAddress(big.NewInt(3)),
718 "https://boot.coord.com",
719 [6]*big.Int{
720 big.NewInt(1), big.NewInt(2), big.NewInt(3),
721 big.NewInt(4), big.NewInt(5), big.NewInt(6),
722 },
723 0,
724 2,
725 4320,
726 [3]uint16{10, 11, 12},
727 1000,
728 20,
729 }
730 //nolint:govet
731 wDelayer := &common.WDelayerVariables{
732 0,
733 ethCommon.BigToAddress(big.NewInt(2)),
734 ethCommon.BigToAddress(big.NewInt(3)),
735 13,
736 14,
737 false,
738 }
739 return rollup, auction, wDelayer
740}
741
742func TestSetInitialSCVars(t *testing.T) {
743 test.WipeDB(historyDB.DB())
744 _, _, _, err := historyDB.GetSCVars()
745 assert.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
746 rollup, auction, wDelayer := exampleInitSCVars()
747 err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
748 require.NoError(t, err)
749 dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
750 require.NoError(t, err)
751 require.Equal(t, rollup, dbRollup)
752 require.Equal(t, auction, dbAuction)
753 require.Equal(t, wDelayer, dbWDelayer)
754}
755
756func TestSetExtraInfoForgedL1UserTxs(t *testing.T) {
757 test.WipeDB(historyDB.DB())
758
759 set := `
760 Type: Blockchain
761
762 AddToken(1)
763
764 CreateAccountDeposit(1) A: 2000
765 CreateAccountDeposit(1) B: 500
766 CreateAccountDeposit(1) C: 500
767
768 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{*}
769 > block // blockNum=2
770
771 > batchL1 // forge defined L1UserTxs{*}
772 > block // blockNum=3
773 `
774
775 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
776 tilCfgExtra := til.ConfigExtra{
777 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
778 CoordUser: "A",
779 }
780 blocks, err := tc.GenerateBlocks(set)
781 require.NoError(t, err)
782 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
783 require.NoError(t, err)
784 err = tc.FillBlocksForgedL1UserTxs(blocks)
785 require.NoError(t, err)
786
787 // Add only first block so that the L1UserTxs are not marked as forged
788 for i := range blocks[:1] {
789 err = historyDB.AddBlockSCData(&blocks[i])
790 require.NoError(t, err)
791 }
792 // Add second batch to trigger the update of the batch_num,
793 // while avoiding the implicit call of setExtraInfoForgedL1UserTxs
794 err = historyDB.addBlock(historyDB.db, &blocks[1].Block)
795 require.NoError(t, err)
796 err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch)
797 require.NoError(t, err)
798 err = historyDB.addAccounts(historyDB.db, blocks[1].Rollup.Batches[0].CreatedAccounts)
799 require.NoError(t, err)
800
801 // Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block
802 l1Txs := blocks[1].Rollup.Batches[0].L1UserTxs
803 require.Equal(t, 3, len(l1Txs))
804 // Change some values to test all cases
805 l1Txs[1].EffectiveAmount = big.NewInt(0)
806 l1Txs[2].EffectiveDepositAmount = big.NewInt(0)
807 l1Txs[2].EffectiveAmount = big.NewInt(0)
808 err = historyDB.setExtraInfoForgedL1UserTxs(historyDB.db, l1Txs)
809 require.NoError(t, err)
810
811 dbL1Txs, err := historyDB.GetAllL1UserTxs()
812 require.NoError(t, err)
813 for i, tx := range dbL1Txs {
814 log.Infof("%d %v %v", i, tx.EffectiveAmount, tx.EffectiveDepositAmount)
815 assert.NotNil(t, tx.EffectiveAmount)
816 assert.NotNil(t, tx.EffectiveDepositAmount)
817 switch tx.TxID {
818 case l1Txs[0].TxID:
819 assert.Equal(t, l1Txs[0].DepositAmount, tx.EffectiveDepositAmount)
820 assert.Equal(t, l1Txs[0].Amount, tx.EffectiveAmount)
821 case l1Txs[1].TxID:
822 assert.Equal(t, l1Txs[1].DepositAmount, tx.EffectiveDepositAmount)
823 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
824 case l1Txs[2].TxID:
825 assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
826 assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
827 }
828 }
829}
830
831func TestUpdateExitTree(t *testing.T) {
832 test.WipeDB(historyDB.DB())
833
834 set := `
835 Type: Blockchain
836
837 AddToken(1)
838
839 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
840 CreateAccountDeposit(1) D: 500 // Idx=256+3=259
841
842 CreateAccountCoordinator(1) A // Idx=256+0=256
843 CreateAccountCoordinator(1) B // Idx=256+1=257
844
845 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
846 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
847 > block // blockNum=2
848
849 ForceExit(1) A: 100
850 ForceExit(1) B: 80
851
852 Exit(1) C: 50 (172)
853 Exit(1) D: 30 (172)
854
855 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
856 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
857 > block // blockNum=3
858
859 > block // blockNum=4 (empty block)
860 > block // blockNum=5 (empty block)
861 `
862
863 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
864 tilCfgExtra := til.ConfigExtra{
865 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
866 CoordUser: "A",
867 }
868 blocks, err := tc.GenerateBlocks(set)
869 require.NoError(t, err)
870 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
871 require.NoError(t, err)
872
873 // Add all blocks except for the last two
874 for i := range blocks[:len(blocks)-2] {
875 err = historyDB.AddBlockSCData(&blocks[i])
876 require.NoError(t, err)
877 }
878
879 // Add withdraws to the second-to-last block, and insert block into the DB
880 block := &blocks[len(blocks)-2]
881 require.Equal(t, int64(4), block.Block.Num)
882 tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
883 // block.WDelayer.Deposits = append(block.WDelayer.Deposits,
884 // common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
885 // common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
886 // )
887 block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
888 common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
889 common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
890 Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
891 common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
892 common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
893 Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
894 )
895 err = historyDB.addBlock(historyDB.db, &block.Block)
896 require.NoError(t, err)
897
898 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
899 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
900 require.NoError(t, err)
901
902 // Check that exits in DB match with the expected values
903 dbExits, err := historyDB.GetAllExits()
904 require.NoError(t, err)
905 assert.Equal(t, 4, len(dbExits))
906 dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
907 for _, dbExit := range dbExits {
908 dbExitsByIdx[dbExit.AccountIdx] = dbExit
909 }
910 for _, withdraw := range block.Rollup.Withdrawals {
911 assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
912 if withdraw.InstantWithdraw {
913 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
914 } else {
915 assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
916 }
917 }
918
919 // Add delayed withdraw to the last block, and insert block into the DB
920 block = &blocks[len(blocks)-1]
921 require.Equal(t, int64(5), block.Block.Num)
922 block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
923 common.WDelayerTransfer{
924 Owner: tc.UsersByIdx[257].Addr,
925 Token: tokenAddr,
926 Amount: big.NewInt(80),
927 })
928 err = historyDB.addBlock(historyDB.db, &block.Block)
929 require.NoError(t, err)
930
931 err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
932 block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
933 require.NoError(t, err)
934
935 // Check that delayed withdrawn has been set
936 dbExits, err = historyDB.GetAllExits()
937 require.NoError(t, err)
938 for _, dbExit := range dbExits {
939 dbExitsByIdx[dbExit.AccountIdx] = dbExit
940 }
941 require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
942}
943
944func TestGetBestBidCoordinator(t *testing.T) {
945 test.WipeDB(historyDB.DB())
946
947 rollup, auction, wDelayer := exampleInitSCVars()
948 err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
949 require.NoError(t, err)
950
951 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
952 blocks, err := tc.GenerateBlocks(`
953 Type: Blockchain
954 > block // blockNum=2
955 `)
956 require.NoError(t, err)
957 err = historyDB.AddBlockSCData(&blocks[0])
958 require.NoError(t, err)
959
960 coords := []common.Coordinator{
961 {
962 Bidder: ethCommon.BigToAddress(big.NewInt(1)),
963 Forger: ethCommon.BigToAddress(big.NewInt(2)),
964 EthBlockNum: 2,
965 URL: "foo",
966 },
967 {
968 Bidder: ethCommon.BigToAddress(big.NewInt(3)),
969 Forger: ethCommon.BigToAddress(big.NewInt(4)),
970 EthBlockNum: 2,
971 URL: "bar",
972 },
973 }
974 err = historyDB.addCoordinators(historyDB.db, coords)
975 require.NoError(t, err)
976
977 bids := []common.Bid{
978 {
979 SlotNum: 10,
980 BidValue: big.NewInt(10),
981 EthBlockNum: 2,
982 Bidder: coords[0].Bidder,
983 },
984 {
985 SlotNum: 10,
986 BidValue: big.NewInt(20),
987 EthBlockNum: 2,
988 Bidder: coords[1].Bidder,
989 },
990 }
991
992 err = historyDB.addBids(historyDB.db, bids)
993 require.NoError(t, err)
994
995 forger10, err := historyDB.GetBestBidCoordinator(10)
996 require.NoError(t, err)
997 require.Equal(t, coords[1].Forger, forger10.Forger)
998 require.Equal(t, coords[1].Bidder, forger10.Bidder)
999 require.Equal(t, coords[1].URL, forger10.URL)
1000 require.Equal(t, bids[1].SlotNum, forger10.SlotNum)
1001 require.Equal(t, bids[1].BidValue, forger10.BidValue)
1002 for i := range forger10.DefaultSlotSetBid {
1003 require.Equal(t, auction.DefaultSlotSetBid[i], forger10.DefaultSlotSetBid[i])
1004 }
1005
1006 _, err = historyDB.GetBestBidCoordinator(11)
1007 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
1008}
1009
1010func TestAddBucketUpdates(t *testing.T) {
1011 test.WipeDB(historyDB.DB())
1012 const fromBlock int64 = 1
1013 const toBlock int64 = 5 + 1
1014 setTestBlocks(fromBlock, toBlock)
1015
1016 bucketUpdates := []common.BucketUpdate{
1017 {
1018 EthBlockNum: 4,
1019 NumBucket: 0,
1020 BlockStamp: 4,
1021 Withdrawals: big.NewInt(123),
1022 },
1023 {
1024 EthBlockNum: 5,
1025 NumBucket: 2,
1026 BlockStamp: 5,
1027 Withdrawals: big.NewInt(42),
1028 },
1029 }
1030 err := historyDB.addBucketUpdates(historyDB.db, bucketUpdates)
1031 require.NoError(t, err)
1032 dbBucketUpdates, err := historyDB.GetAllBucketUpdates()
1033 require.NoError(t, err)
1034 assert.Equal(t, bucketUpdates, dbBucketUpdates)
1035}
1036
1037func TestAddTokenExchanges(t *testing.T) {
1038 test.WipeDB(historyDB.DB())
1039 const fromBlock int64 = 1
1040 const toBlock int64 = 5 + 1
1041 setTestBlocks(fromBlock, toBlock)
1042
1043 tokenExchanges := []common.TokenExchange{
1044 {
1045 EthBlockNum: 4,
1046 Address: ethCommon.BigToAddress(big.NewInt(111)),
1047 ValueUSD: 12345,
1048 },
1049 {
1050 EthBlockNum: 5,
1051 Address: ethCommon.BigToAddress(big.NewInt(222)),
1052 ValueUSD: 67890,
1053 },
1054 }
1055 err := historyDB.addTokenExchanges(historyDB.db, tokenExchanges)
1056 require.NoError(t, err)
1057 dbTokenExchanges, err := historyDB.GetAllTokenExchanges()
1058 require.NoError(t, err)
1059 assert.Equal(t, tokenExchanges, dbTokenExchanges)
1060}
1061
1062func TestAddEscapeHatchWithdrawals(t *testing.T) {
1063 test.WipeDB(historyDB.DB())
1064 const fromBlock int64 = 1
1065 const toBlock int64 = 5 + 1
1066 setTestBlocks(fromBlock, toBlock)
1067
1068 escapeHatchWithdrawals := []common.WDelayerEscapeHatchWithdrawal{
1069 {
1070 EthBlockNum: 4,
1071 Who: ethCommon.BigToAddress(big.NewInt(111)),
1072 To: ethCommon.BigToAddress(big.NewInt(222)),
1073 TokenAddr: ethCommon.BigToAddress(big.NewInt(333)),
1074 Amount: big.NewInt(10002),
1075 },
1076 {
1077 EthBlockNum: 5,
1078 Who: ethCommon.BigToAddress(big.NewInt(444)),
1079 To: ethCommon.BigToAddress(big.NewInt(555)),
1080 TokenAddr: ethCommon.BigToAddress(big.NewInt(666)),
1081 Amount: big.NewInt(20003),
1082 },
1083 }
1084 err := historyDB.addEscapeHatchWithdrawals(historyDB.db, escapeHatchWithdrawals)
1085 require.NoError(t, err)
1086 dbEscapeHatchWithdrawals, err := historyDB.GetAllEscapeHatchWithdrawals()
1087 require.NoError(t, err)
1088 assert.Equal(t, escapeHatchWithdrawals, dbEscapeHatchWithdrawals)
1089}
1090
1091func TestGetMetricsAPI(t *testing.T) {
1092 test.WipeDB(historyDB.DB())
1093 set := `
1094 Type: Blockchain
1095
1096 AddToken(1)
1097
1098 CreateAccountDeposit(1) A: 1000 // numTx=1
1099 CreateAccountDeposit(1) B: 2000 // numTx=2
1100 CreateAccountDeposit(1) C: 3000 //numTx=3
1101
1102 // block 0 is stored as default in the DB
1103 // block 1 does not exist
1104 > batchL1 // numBatches=1
1105 > batchL1 // numBatches=2
1106 > block // blockNum=2
1107
1108 Transfer(1) C-A : 10 (1) // numTx=4
1109 > batch // numBatches=3
1110 > block // blockNum=3
1111 Transfer(1) B-C : 10 (1) // numTx=5
1112 > batch // numBatches=5
1113 > block // blockNum=4
1114 Transfer(1) A-B : 10 (1) // numTx=6
1115 > batch // numBatches=5
1116 > block // blockNum=5
1117 Transfer(1) A-B : 10 (1) // numTx=7
1118 > batch // numBatches=6
1119 > block // blockNum=6
1120 `
1121
1122 const numBatches int = 6
1123 const numTx int = 7
1124 const blockNum = 6 - 1
1125
1126 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
1127 tilCfgExtra := til.ConfigExtra{
1128 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
1129 CoordUser: "A",
1130 }
1131 blocks, err := tc.GenerateBlocks(set)
1132 require.NoError(t, err)
1133 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1134 require.NoError(t, err)
1135
1136 // Sanity check
1137 require.Equal(t, blockNum, len(blocks))
1138
1139 // Adding one batch per block
1140 // batch frequency can be chosen
1141 const frequency int = 15
1142
1143 for i := range blocks {
1144 blocks[i].Block.Timestamp = time.Now().Add(-time.Second * time.Duration(frequency*(len(blocks)-i)))
1145 err = historyDB.AddBlockSCData(&blocks[i])
1146 assert.NoError(t, err)
1147 }
1148
1149 res, err := historyDBWithACC.GetMetricsAPI(common.BatchNum(numBatches))
1150 assert.NoError(t, err)
1151
1152 assert.Equal(t, float64(numTx)/float64(numBatches-1), res.TransactionsPerBatch)
1153
1154 // Frequency is not exactly the desired one, some decimals may appear
1155 assert.GreaterOrEqual(t, res.BatchFrequency, float64(frequency))
1156 assert.Less(t, res.BatchFrequency, float64(frequency+1))
1157 // Truncate frecuency into an int to do an exact check
1158 assert.Equal(t, frequency, int(res.BatchFrequency))
1159 // This may also be different in some decimals
1160 // Truncate it to the third decimal to compare
1161 assert.Equal(t, math.Trunc((float64(numTx)/float64(frequency*blockNum-frequency))/0.001)*0.001, math.Trunc(res.TransactionsPerSecond/0.001)*0.001)
1162 assert.Equal(t, int64(3), res.TotalAccounts)
1163 assert.Equal(t, int64(3), res.TotalBJJs)
1164 // Til does not set fees
1165 assert.Equal(t, float64(0), res.AvgTransactionFee)
1166}
1167
1168func TestGetMetricsAPIMoreThan24Hours(t *testing.T) {
1169 test.WipeDB(historyDB.DB())
1170
1171 testUsersLen := 3
1172 var set []til.Instruction
1173 for user := 0; user < testUsersLen; user++ {
1174 set = append(set, til.Instruction{
1175 Typ: common.TxTypeCreateAccountDeposit,
1176 TokenID: common.TokenID(0),
1177 DepositAmount: big.NewInt(1000000),
1178 Amount: big.NewInt(0),
1179 From: fmt.Sprintf("User%02d", user),
1180 })
1181 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1182 }
1183 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1184 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1185 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1186
1187 // Transfers
1188 for x := 0; x < 6000; x++ {
1189 set = append(set, til.Instruction{
1190 Typ: common.TxTypeTransfer,
1191 TokenID: common.TokenID(0),
1192 DepositAmount: big.NewInt(1),
1193 Amount: big.NewInt(0),
1194 From: "User00",
1195 To: "User01",
1196 })
1197 set = append(set, til.Instruction{Typ: til.TypeNewBatch})
1198 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1199 }
1200
1201 var chainID uint16 = 0
1202 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1203 blocks, err := tc.GenerateBlocksFromInstructions(set)
1204 assert.NoError(t, err)
1205
1206 tilCfgExtra := til.ConfigExtra{
1207 CoordUser: "A",
1208 }
1209 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1210 require.NoError(t, err)
1211
1212 const numBatches int = 6002
1213 const numTx int = 6003
1214 const blockNum = 6005 - 1
1215
1216 // Sanity check
1217 require.Equal(t, blockNum, len(blocks))
1218
1219 // Adding one batch per block
1220 // batch frequency can be chosen
1221 const frequency int = 15
1222
1223 for i := range blocks {
1224 blocks[i].Block.Timestamp = time.Now().Add(-time.Second * time.Duration(frequency*(len(blocks)-i)))
1225 err = historyDB.AddBlockSCData(&blocks[i])
1226 assert.NoError(t, err)
1227 }
1228
1229 res, err := historyDBWithACC.GetMetricsAPI(common.BatchNum(numBatches))
1230 assert.NoError(t, err)
1231
1232 assert.Equal(t, math.Trunc((float64(numTx)/float64(numBatches-1))/0.001)*0.001, math.Trunc(res.TransactionsPerBatch/0.001)*0.001)
1233
1234 // Frequency is not exactly the desired one, some decimals may appear
1235 assert.GreaterOrEqual(t, res.BatchFrequency, float64(frequency))
1236 assert.Less(t, res.BatchFrequency, float64(frequency+1))
1237 // Truncate frecuency into an int to do an exact check
1238 assert.Equal(t, frequency, int(res.BatchFrequency))
1239 // This may also be different in some decimals
1240 // Truncate it to the third decimal to compare
1241 assert.Equal(t, math.Trunc((float64(numTx)/float64(frequency*blockNum-frequency))/0.001)*0.001, math.Trunc(res.TransactionsPerSecond/0.001)*0.001)
1242 assert.Equal(t, int64(3), res.TotalAccounts)
1243 assert.Equal(t, int64(3), res.TotalBJJs)
1244 // Til does not set fees
1245 assert.Equal(t, float64(0), res.AvgTransactionFee)
1246}
1247
1248func TestGetMetricsAPIEmpty(t *testing.T) {
1249 test.WipeDB(historyDB.DB())
1250 _, err := historyDBWithACC.GetMetricsAPI(0)
1251 assert.NoError(t, err)
1252}
1253
1254func TestGetAvgTxFeeEmpty(t *testing.T) {
1255 test.WipeDB(historyDB.DB())
1256 _, err := historyDBWithACC.GetAvgTxFeeAPI()
1257 assert.NoError(t, err)
1258}
1259
1260func TestGetLastL1TxsNum(t *testing.T) {
1261 test.WipeDB(historyDB.DB())
1262 _, err := historyDB.GetLastL1TxsNum()
1263 assert.NoError(t, err)
1264}
1265
1266func TestGetLastTxsPosition(t *testing.T) {
1267 test.WipeDB(historyDB.DB())
1268 _, err := historyDB.GetLastTxsPosition(0)
1269 assert.Equal(t, sql.ErrNoRows.Error(), err.Error())
1270}
1271
1272func TestGetFirstBatchBlockNumBySlot(t *testing.T) {
1273 test.WipeDB(historyDB.DB())
1274
1275 set := `
1276 Type: Blockchain
1277
1278 // Slot = 0
1279
1280 > block // 2
1281 > block // 3
1282 > block // 4
1283 > block // 5
1284
1285 // Slot = 1
1286
1287 > block // 6
1288 > block // 7
1289 > batch
1290 > block // 8
1291 > block // 9
1292
1293 // Slot = 2
1294
1295 > batch
1296 > block // 10
1297 > block // 11
1298 > block // 12
1299 > block // 13
1300
1301 `
1302 tc := til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
1303 blocks, err := tc.GenerateBlocks(set)
1304 assert.NoError(t, err)
1305
1306 tilCfgExtra := til.ConfigExtra{
1307 CoordUser: "A",
1308 }
1309 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1310 require.NoError(t, err)
1311
1312 for i := range blocks {
1313 for j := range blocks[i].Rollup.Batches {
1314 blocks[i].Rollup.Batches[j].Batch.SlotNum = int64(i) / 4
1315 }
1316 }
1317
1318 // Add all blocks
1319 for i := range blocks {
1320 err = historyDB.AddBlockSCData(&blocks[i])
1321 require.NoError(t, err)
1322 }
1323
1324 _, err = historyDB.GetFirstBatchBlockNumBySlot(0)
1325 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
1326
1327 bn1, err := historyDB.GetFirstBatchBlockNumBySlot(1)
1328 require.NoError(t, err)
1329 assert.Equal(t, int64(8), bn1)
1330
1331 bn2, err := historyDB.GetFirstBatchBlockNumBySlot(2)
1332 require.NoError(t, err)
1333 assert.Equal(t, int64(10), bn2)
1334}
1335
1336func TestTxItemID(t *testing.T) {
1337 test.WipeDB(historyDB.DB())
1338 testUsersLen := 10
1339 var set []til.Instruction
1340 for user := 0; user < testUsersLen; user++ {
1341 set = append(set, til.Instruction{
1342 Typ: common.TxTypeCreateAccountDeposit,
1343 TokenID: common.TokenID(0),
1344 DepositAmount: big.NewInt(1000000),
1345 Amount: big.NewInt(0),
1346 From: fmt.Sprintf("User%02d", user),
1347 })
1348 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1349 }
1350 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1351 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1352 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1353 for user := 0; user < testUsersLen; user++ {
1354 set = append(set, til.Instruction{
1355 Typ: common.TxTypeDeposit,
1356 TokenID: common.TokenID(0),
1357 DepositAmount: big.NewInt(100000),
1358 Amount: big.NewInt(0),
1359 From: fmt.Sprintf("User%02d", user),
1360 })
1361 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1362 }
1363 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1364 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1365 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1366 for user := 0; user < testUsersLen; user++ {
1367 set = append(set, til.Instruction{
1368 Typ: common.TxTypeDepositTransfer,
1369 TokenID: common.TokenID(0),
1370 DepositAmount: big.NewInt(10000 * int64(user+1)),
1371 Amount: big.NewInt(1000 * int64(user+1)),
1372 From: fmt.Sprintf("User%02d", user),
1373 To: fmt.Sprintf("User%02d", (user+1)%testUsersLen),
1374 })
1375 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1376 }
1377 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1378 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1379 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1380 for user := 0; user < testUsersLen; user++ {
1381 set = append(set, til.Instruction{
1382 Typ: common.TxTypeForceTransfer,
1383 TokenID: common.TokenID(0),
1384 Amount: big.NewInt(100 * int64(user+1)),
1385 DepositAmount: big.NewInt(0),
1386 From: fmt.Sprintf("User%02d", user),
1387 To: fmt.Sprintf("User%02d", (user+1)%testUsersLen),
1388 })
1389 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1390 }
1391 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1392 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1393 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1394 for user := 0; user < testUsersLen; user++ {
1395 set = append(set, til.Instruction{
1396 Typ: common.TxTypeForceExit,
1397 TokenID: common.TokenID(0),
1398 Amount: big.NewInt(10 * int64(user+1)),
1399 DepositAmount: big.NewInt(0),
1400 From: fmt.Sprintf("User%02d", user),
1401 })
1402 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1403 }
1404 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1405 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
1406 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
1407 var chainID uint16 = 0
1408 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1409 blocks, err := tc.GenerateBlocksFromInstructions(set)
1410 assert.NoError(t, err)
1411
1412 tilCfgExtra := til.ConfigExtra{
1413 CoordUser: "A",
1414 }
1415 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1416 require.NoError(t, err)
1417
1418 // Add all blocks
1419 for i := range blocks {
1420 err = historyDB.AddBlockSCData(&blocks[i])
1421 require.NoError(t, err)
1422 }
1423
1424 txs, err := historyDB.GetAllL1UserTxs()
1425 require.NoError(t, err)
1426 position := 0
1427 for _, tx := range txs {
1428 if tx.Position == 0 {
1429 position = 0
1430 }
1431 assert.Equal(t, position, tx.Position)
1432 position++
1433 }
1434}
1435
1436// setTestBlocks WARNING: this will delete the blocks and recreate them
1437func setTestBlocks(from, to int64) []common.Block {
1438 test.WipeDB(historyDB.DB())
1439 blocks := test.GenBlocks(from, to)
1440 if err := historyDB.AddBlocks(blocks); err != nil {
1441 panic(err)
1442 }
1443 return blocks
1444}