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