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