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