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