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