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