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