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