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