You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

699 lines
22 KiB

package historydb
import (
"database/sql"
"math"
"math/big"
"os"
"testing"
"time"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/test"
"github.com/hermeznetwork/hermez-node/test/til"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var historyDB *HistoryDB
// In order to run the test you need to run a Posgres DB with
// a database named "history" that is accessible by
// user: "hermez"
// pass: set it using the env var POSTGRES_PASS
// 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;"
// After running the test you can stop the container by running: sudo docker kill hermez-db-test
// If you already did that for the L2DB you don't have to do it again
func TestMain(m *testing.M) {
// init DB
pass := os.Getenv("POSTGRES_PASS")
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
if err != nil {
panic(err)
}
historyDB = NewHistoryDB(db)
if err != nil {
panic(err)
}
// Run tests
result := m.Run()
// Close DB
if err := db.Close(); err != nil {
log.Error("Error closing the history DB:", err)
}
os.Exit(result)
}
func TestBlocks(t *testing.T) {
var fromBlock, toBlock int64
fromBlock = 0
toBlock = 7
// Reset DB
test.WipeDB(historyDB.DB())
// Generate blocks using til
set1 := `
Type: Blockchain
// block 0 is stored as default in the DB
// block 1 does not exist
> block // blockNum=2
> block // blockNum=3
> block // blockNum=4
> block // blockNum=5
> block // blockNum=6
`
tc := til.NewContext(1)
blocks, err := tc.GenerateBlocks(set1)
require.NoError(t, err)
// Save timestamp of a block with UTC and change it without UTC
timestamp := time.Now().Add(time.Second * 13)
blocks[fromBlock].Block.Timestamp = timestamp
// Insert blocks into DB
for i := 0; i < len(blocks); i++ {
err := historyDB.AddBlock(&blocks[i].Block)
assert.NoError(t, err)
}
// Add block 0 to the generated blocks
blocks = append(
[]common.BlockData{common.BlockData{Block: test.Block0}}, //nolint:gofmt
blocks...,
)
// Get all blocks from DB
fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
assert.Equal(t, len(blocks), len(fetchedBlocks))
// Compare generated vs getted blocks
assert.NoError(t, err)
for i := range fetchedBlocks {
assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
}
// Compare saved timestamp vs getted
nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
assert.Equal(t, offsetUTC, offsetFetchedBlock)
// Get blocks from the DB one by one
for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
fetchedBlock, err := historyDB.GetBlock(i)
assert.NoError(t, err)
assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
}
// Get last block
lastBlock, err := historyDB.GetLastBlock()
assert.NoError(t, err)
assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
}
func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
assert.Equal(t, expected.Hash, actual.Hash)
assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
}
func TestBatches(t *testing.T) {
// Reset DB
test.WipeDB(historyDB.DB())
// Generate batches using til (and blocks for foreign key)
set := `
Type: Blockchain
AddToken(1) // Will have value in USD
AddToken(2) // Will NOT have value in USD
CreateAccountDeposit(1) A: 2000
CreateAccountDeposit(2) A: 2000
CreateAccountDeposit(1) B: 1000
CreateAccountDeposit(2) B: 1000
> batchL1
> batchL1
Transfer(1) A-B: 100 (5)
Transfer(2) B-A: 100 (199)
> batch // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
> block
Transfer(1) A-B: 100 (5)
> batch // batchNum=3, L2 only batch, forges transfer (with USD value)
Transfer(2) B-A: 100 (199)
> batch // batchNum=4, L2 only batch, forges transfer (without USD value)
> block
`
tc := til.NewContext(common.RollupConstMaxL1UserTx)
tilCfgExtra := til.ConfigExtra{
BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
CoordUser: "A",
}
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.Nil(t, err)
// Insert to DB
batches := []common.Batch{}
tokensValue := make(map[common.TokenID]float64)
lastL1TxsNum := new(int64)
for _, block := range blocks {
// Insert block
assert.NoError(t, historyDB.AddBlock(&block.Block))
// Insert tokens
for i, token := range block.Rollup.AddedTokens {
assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
if i%2 != 0 {
// Set value to the token
value := (float64(i) + 5) * 5.389329
assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
}
}
// Combine all generated batches into single array
for _, batch := range block.Rollup.Batches {
batches = append(batches, batch.Batch)
forgeTxsNum := batch.Batch.ForgeL1TxsNum
if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
*lastL1TxsNum = *forgeTxsNum
}
}
}
// Insert batches
assert.NoError(t, historyDB.AddBatches(batches))
// Set expected total fee
for _, batch := range batches {
total := .0
for tokenID, amount := range batch.CollectedFees {
af := new(big.Float).SetInt(amount)
amountFloat, _ := af.Float64()
total += tokensValue[tokenID] * amountFloat
}
batch.TotalFeesUSD = &total
}
// Get batches from the DB
fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
assert.NoError(t, err)
assert.Equal(t, len(batches), len(fetchedBatches))
for i, fetchedBatch := range fetchedBatches {
assert.Equal(t, batches[i], fetchedBatch)
}
// Test GetLastBatchNum
fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
assert.NoError(t, err)
assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
// Test GetLastL1TxsNum
fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
assert.NoError(t, err)
assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
}
func TestBids(t *testing.T) {
const fromBlock int64 = 1
const toBlock int64 = 5
// Prepare blocks in the DB
blocks := setTestBlocks(fromBlock, toBlock)
// Generate fake coordinators
const nCoords = 5
coords := test.GenCoordinators(nCoords, blocks)
err := historyDB.AddCoordinators(coords)
assert.NoError(t, err)
// Generate fake bids
const nBids = 20
bids := test.GenBids(nBids, blocks, coords)
err = historyDB.AddBids(bids)
assert.NoError(t, err)
// Fetch bids
fetchedBids, err := historyDB.GetAllBids()
assert.NoError(t, err)
// Compare fetched bids vs generated bids
for i, bid := range fetchedBids {
assert.Equal(t, bids[i], bid)
}
}
func TestTokens(t *testing.T) {
const fromBlock int64 = 1
const toBlock int64 = 5
// Prepare blocks in the DB
blocks := setTestBlocks(fromBlock, toBlock)
// Generate fake tokens
const nTokens = 5
tokens, ethToken := test.GenTokens(nTokens, blocks)
err := historyDB.AddTokens(tokens)
assert.NoError(t, err)
tokens = append([]common.Token{ethToken}, tokens...)
limit := uint(10)
// Fetch tokens
fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
assert.NoError(t, err)
// Compare fetched tokens vs generated tokens
// All the tokens should have USDUpdate setted by the DB trigger
for i, token := range fetchedTokens {
assert.Equal(t, tokens[i].TokenID, token.TokenID)
assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
assert.Equal(t, tokens[i].Name, token.Name)
assert.Equal(t, tokens[i].Symbol, token.Symbol)
assert.Nil(t, token.USD)
assert.Nil(t, token.USDUpdate)
}
// Update token value
for i, token := range tokens {
value := 1.01 * float64(i)
assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
}
// Fetch tokens
fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
assert.NoError(t, err)
// Compare fetched tokens vs generated tokens
// All the tokens should have USDUpdate setted by the DB trigger
for i, token := range fetchedTokens {
value := 1.01 * float64(i)
assert.Equal(t, value, *token.USD)
nameZone, offset := token.USDUpdate.Zone()
assert.Equal(t, "UTC", nameZone)
assert.Equal(t, 0, offset)
}
}
func TestAccounts(t *testing.T) {
const fromBlock int64 = 1
const toBlock int64 = 5
// Prepare blocks in the DB
blocks := setTestBlocks(fromBlock, toBlock)
// Generate fake tokens
const nTokens = 5
tokens, ethToken := test.GenTokens(nTokens, blocks)
err := historyDB.AddTokens(tokens)
assert.NoError(t, err)
tokens = append([]common.Token{ethToken}, tokens...)
// Generate fake batches
const nBatches = 10
batches := test.GenBatches(nBatches, blocks)
err = historyDB.AddBatches(batches)
assert.NoError(t, err)
// Generate fake accounts
const nAccounts = 3
accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
err = historyDB.AddAccounts(accs)
assert.NoError(t, err)
// Fetch accounts
fetchedAccs, err := historyDB.GetAccounts()
assert.NoError(t, err)
// Compare fetched accounts vs generated accounts
for i, acc := range fetchedAccs {
accs[i].Balance = nil
assert.Equal(t, accs[i], acc)
}
}
func TestTxs(t *testing.T) {
// Reset DB
test.WipeDB(historyDB.DB())
// TODO: Generate batches using til (and blocks for foreign key)
set := `
Type: Blockchain
// Things to test:
// One tx of each type
// batches that forge user L1s
// historic USD is not set if USDUpdate is too old (24h)
`
tc := til.NewContext(common.RollupConstMaxL1UserTx)
tilCfgExtra := til.ConfigExtra{
BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
CoordUser: "A",
}
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.Nil(t, err)
/*
OLD TEST
const fromBlock int64 = 1
const toBlock int64 = 5
// Prepare blocks in the DB
blocks := setTestBlocks(fromBlock, toBlock)
// Generate fake tokens
const nTokens = 500
tokens, ethToken := test.GenTokens(nTokens, blocks)
err := historyDB.AddTokens(tokens)
assert.NoError(t, err)
tokens = append([]common.Token{ethToken}, tokens...)
// Generate fake batches
const nBatches = 10
batches := test.GenBatches(nBatches, blocks)
err = historyDB.AddBatches(batches)
assert.NoError(t, err)
// Generate fake accounts
const nAccounts = 3
accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
err = historyDB.AddAccounts(accs)
assert.NoError(t, err)
Uncomment once the transaction generation is fixed
!! test that batches that forge user L1s !!
!! Missing tests to check that !!
// Generate fake L1 txs
const nL1s = 64
_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
err = historyDB.AddL1Txs(l1txs)
assert.NoError(t, err)
// Generate fake L2 txs
const nL2s = 2048 - nL1s
_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
err = historyDB.AddL2Txs(l2txs)
assert.NoError(t, err)
// Compare fetched txs vs generated txs.
fetchAndAssertTxs(t, l1txs, l2txs)
// Test trigger: L1 integrity
// from_eth_addr can't be null
l1txs[0].FromEthAddr = ethCommon.Address{}
err = historyDB.AddL1Txs(l1txs)
assert.Error(t, err)
l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
// from_bjj can't be null
l1txs[0].FromBJJ = nil
err = historyDB.AddL1Txs(l1txs)
assert.Error(t, err)
privK := babyjub.NewRandPrivKey()
l1txs[0].FromBJJ = privK.Public()
// load_amount can't be null
l1txs[0].LoadAmount = nil
err = historyDB.AddL1Txs(l1txs)
assert.Error(t, err)
// Test trigger: L2 integrity
// batch_num can't be null
l2txs[0].BatchNum = 0
err = historyDB.AddL2Txs(l2txs)
assert.Error(t, err)
l2txs[0].BatchNum = 1
// nonce can't be null
l2txs[0].Nonce = 0
err = historyDB.AddL2Txs(l2txs)
assert.Error(t, err)
// Test trigger: forge L1 txs
// add next batch to DB
batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
batch := batches[0]
batch.BatchNum = batchNum
batch.ForgeL1TxsNum = toForgeL1TxsNum
assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
// Set batch num in txs that should have been marked as forged in the DB
for i := 0; i < len(l1txs); i++ {
fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
assert.NoError(t, err)
if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
assert.Equal(t, batchNum, *fetchedTx.BatchNum)
} else {
if fetchedTx.BatchNum != nil {
assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
}
}
}
// Test helper functions for Synchronizer
// GetLastTxsPosition
expectedPosition := -1
var choosenToForgeL1TxsNum int64 = -1
for _, tx := range l1txs {
if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
expectedPosition = tx.Position
} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
expectedPosition = tx.Position
}
}
position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
assert.NoError(t, err)
assert.Equal(t, expectedPosition, position)
// GetL1UserTxs: not needed? tests were broken
// txs, err := historyDB.GetL1UserTxs(2)
// assert.NoError(t, err)
// assert.NotZero(t, len(txs))
// assert.NoError(t, err)
// assert.Equal(t, 22, position)
// // Test Update L1 TX Batch_num
// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
// txs[0].BatchNum = common.BatchNum(1)
// txs, err = historyDB.GetL1UserTxs(2)
// assert.NoError(t, err)
// assert.NotZero(t, len(txs))
// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
*/
}
/*
func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
for i := 0; i < len(l1txs); i++ {
tx := l1txs[i].Tx()
fmt.Println("ASDF", i, tx.TxID)
fetchedTx, err := historyDB.GetTx(tx.TxID)
require.NoError(t, err)
test.AssertUSD(t, tx.USD, fetchedTx.USD)
test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
assert.Equal(t, tx, fetchedTx)
}
for i := 0; i < len(l2txs); i++ {
tx := l2txs[i].Tx()
fetchedTx, err := historyDB.GetTx(tx.TxID)
tx.TokenID = fetchedTx.TokenID
assert.NoError(t, err)
test.AssertUSD(t, fetchedTx.USD, tx.USD)
test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
assert.Equal(t, tx, fetchedTx)
}
}
*/
func TestExitTree(t *testing.T) {
nBatches := 17
blocks := setTestBlocks(1, 10)
batches := test.GenBatches(nBatches, blocks)
err := historyDB.AddBatches(batches)
assert.NoError(t, err)
const nTokens = 50
tokens, ethToken := test.GenTokens(nTokens, blocks)
err = historyDB.AddTokens(tokens)
assert.NoError(t, err)
tokens = append([]common.Token{ethToken}, tokens...)
const nAccounts = 3
accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
assert.NoError(t, historyDB.AddAccounts(accs))
exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
err = historyDB.AddExitTree(exitTree)
assert.NoError(t, err)
}
func TestGetL1UserTxs(t *testing.T) {
test.WipeDB(historyDB.DB())
set := `
Type: Blockchain
AddToken(1)
AddToken(2)
AddToken(3)
CreateAccountDeposit(1) A: 20
CreateAccountDeposit(2) A: 20
CreateAccountDeposit(1) B: 5
CreateAccountDeposit(1) C: 5
CreateAccountDeposit(1) D: 5
> block
`
tc := til.NewContext(128)
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
// Sanity check
require.Equal(t, 1, len(blocks))
require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
toForgeL1TxsNum := int64(1)
for i := range blocks {
err = historyDB.AddBlockSCData(&blocks[i])
require.Nil(t, err)
}
l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
require.Nil(t, err)
assert.Equal(t, 5, len(l1UserTxs))
assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
// No l1UserTxs for this toForgeL1TxsNum
l1UserTxs, err = historyDB.GetL1UserTxs(2)
require.Nil(t, err)
assert.Equal(t, 0, len(l1UserTxs))
}
func TestSetInitialSCVars(t *testing.T) {
test.WipeDB(historyDB.DB())
_, _, _, err := historyDB.GetSCVars()
assert.Equal(t, sql.ErrNoRows, err)
//nolint:govet
rollup := &common.RollupVariables{
0,
big.NewInt(10),
12,
13,
[5]common.Bucket{},
}
//nolint:govet
auction := &common.AuctionVariables{
0,
ethCommon.BigToAddress(big.NewInt(2)),
ethCommon.BigToAddress(big.NewInt(3)),
[6]*big.Int{
big.NewInt(1), big.NewInt(2), big.NewInt(3),
big.NewInt(4), big.NewInt(5), big.NewInt(6),
},
2,
4320,
[3]uint16{10, 11, 12},
1000,
20,
}
//nolint:govet
wDelayer := &common.WDelayerVariables{
0,
ethCommon.BigToAddress(big.NewInt(2)),
ethCommon.BigToAddress(big.NewInt(3)),
ethCommon.BigToAddress(big.NewInt(4)),
13,
14,
false,
}
err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
require.Nil(t, err)
dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
assert.Nil(t, err)
require.Equal(t, rollup, dbRollup)
require.Equal(t, auction, dbAuction)
require.Equal(t, wDelayer, dbWDelayer)
}
func TestUpdateExitTree(t *testing.T) {
test.WipeDB(historyDB.DB())
set := `
Type: Blockchain
AddToken(1)
CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
CreateAccountDeposit(1) D: 500 // Idx=256+3=259
CreateAccountCoordinator(1) A // Idx=256+0=256
CreateAccountCoordinator(1) B // Idx=256+1=257
> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
> block // blockNum=2
ForceExit(1) A: 100
ForceExit(1) B: 80
Exit(1) C: 50 (172)
Exit(1) D: 30 (172)
> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
> block // blockNum=3
> block // blockNum=4 (empty block)
> block // blockNum=5 (empty block)
`
tc := til.NewContext(common.RollupConstMaxL1UserTx)
tilCfgExtra := til.ConfigExtra{
BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
CoordUser: "A",
}
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.Nil(t, err)
// Add all blocks except for the last two
for i := range blocks[:len(blocks)-2] {
err = historyDB.AddBlockSCData(&blocks[i])
require.Nil(t, err)
}
// Add withdraws to the second-to-last block, and insert block into the DB
block := &blocks[len(blocks)-2]
require.Equal(t, int64(4), block.Block.EthBlockNum)
tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
// block.WDelayer.Deposits = append(block.WDelayer.Deposits,
// common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
// common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
// )
block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
)
err = historyDB.addBlock(historyDB.db, &block.Block)
require.Nil(t, err)
err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
require.Nil(t, err)
// Check that exits in DB match with the expected values
dbExits, err := historyDB.GetAllExits()
require.Nil(t, err)
assert.Equal(t, 4, len(dbExits))
dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
for _, dbExit := range dbExits {
dbExitsByIdx[dbExit.AccountIdx] = dbExit
}
for _, withdraw := range block.Rollup.Withdrawals {
assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
if withdraw.InstantWithdraw {
assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
} else {
assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
}
}
// Add delayed withdraw to the last block, and insert block into the DB
block = &blocks[len(blocks)-1]
require.Equal(t, int64(5), block.Block.EthBlockNum)
block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
common.WDelayerTransfer{
Owner: tc.UsersByIdx[257].Addr,
Token: tokenAddr,
Amount: big.NewInt(80),
})
err = historyDB.addBlock(historyDB.db, &block.Block)
require.Nil(t, err)
err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum,
block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
require.Nil(t, err)
// Check that delayed withdrawn has been set
dbExits, err = historyDB.GetAllExits()
require.Nil(t, err)
for _, dbExit := range dbExits {
dbExitsByIdx[dbExit.AccountIdx] = dbExit
}
require.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[257].DelayedWithdrawn)
}
// setTestBlocks WARNING: this will delete the blocks and recreate them
func setTestBlocks(from, to int64) []common.Block {
test.WipeDB(historyDB.DB())
blocks := test.GenBlocks(from, to)
if err := historyDB.AddBlocks(blocks); err != nil {
panic(err)
}
return blocks
}