arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/txprocessor/txprocessor_test.go
txprocessor/txprocessor_test.goRaw
   1package txprocessor
   2
   3import (
   4	"io/ioutil"
   5	"math/big"
   6	"os"
   7	"sort"
   8	"testing"
   9
  10	ethCommon "github.com/ethereum/go-ethereum/common"
  11	"github.com/hermeznetwork/hermez-node/common"
  12	"github.com/hermeznetwork/hermez-node/db/statedb"
  13	"github.com/hermeznetwork/hermez-node/log"
  14	"github.com/hermeznetwork/hermez-node/test/til"
  15	"github.com/hermeznetwork/hermez-node/test/txsets"
  16	"github.com/stretchr/testify/assert"
  17	"github.com/stretchr/testify/require"
  18)
  19
  20func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
  21	idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
  22	acc, err := sdb.GetAccount(idx)
  23	require.NoError(t, err)
  24	assert.Equal(t, expected, acc.Balance.String())
  25}
  26
  27func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
  28	acc, err := sdb.GetAccount(idx)
  29	require.NoError(t, err)
  30	assert.Equal(t, expected, acc.Balance.String())
  31}
  32
  33func TestComputeEffectiveAmounts(t *testing.T) {
  34	dir, err := ioutil.TempDir("", "tmpdb")
  35	require.NoError(t, err)
  36	defer assert.NoError(t, os.RemoveAll(dir))
  37
  38	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
  39		Type: statedb.TypeSynchronizer, NLevels: 32})
  40	assert.NoError(t, err)
  41
  42	set := `
  43		Type: Blockchain
  44		AddToken(1)
  45	
  46		CreateAccountDeposit(0) A: 10
  47		CreateAccountDeposit(0) B: 10
  48		CreateAccountDeposit(1) C: 10
  49		> batchL1
  50		> batchL1
  51		> block
  52	`
  53	chainID := uint16(0)
  54	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
  55	blocks, err := tc.GenerateBlocks(set)
  56	require.NoError(t, err)
  57
  58	config := Config{
  59		NLevels:  32,
  60		MaxFeeTx: 64,
  61		MaxTx:    512,
  62		MaxL1Tx:  16,
  63		ChainID:  chainID,
  64	}
  65	tp := NewTxProcessor(sdb, config)
  66	_, err = tp.ProcessTxs(nil, blocks[0].Rollup.L1UserTxs, nil, nil)
  67	require.NoError(t, err)
  68
  69	tx := common.L1Tx{
  70		FromIdx:       256,
  71		ToIdx:         257,
  72		Amount:        big.NewInt(10),
  73		DepositAmount: big.NewInt(0),
  74		FromEthAddr:   tc.Users["A"].Addr,
  75		UserOrigin:    true,
  76	}
  77	tp.computeEffectiveAmounts(&tx)
  78	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  79	assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
  80
  81	// expect error due not enough funds
  82	tx = common.L1Tx{
  83		FromIdx:       256,
  84		ToIdx:         257,
  85		Amount:        big.NewInt(11),
  86		DepositAmount: big.NewInt(0),
  87		FromEthAddr:   tc.Users["A"].Addr,
  88		UserOrigin:    true,
  89	}
  90	tp.computeEffectiveAmounts(&tx)
  91	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
  92	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
  93
  94	// expect no-error as there are enough funds in a
  95	// CreateAccountDepositTransfer transction
  96	tx = common.L1Tx{
  97		FromIdx:       0,
  98		ToIdx:         257,
  99		Amount:        big.NewInt(10),
 100		DepositAmount: big.NewInt(10),
 101		UserOrigin:    true,
 102	}
 103	tp.computeEffectiveAmounts(&tx)
 104	assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
 105	assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
 106
 107	// expect error due not enough funds in a CreateAccountDepositTransfer
 108	// transction
 109	tx = common.L1Tx{
 110		FromIdx:       0,
 111		ToIdx:         257,
 112		Amount:        big.NewInt(11),
 113		DepositAmount: big.NewInt(10),
 114		UserOrigin:    true,
 115	}
 116	tp.computeEffectiveAmounts(&tx)
 117	assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
 118	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 119
 120	// expect error due not same TokenID
 121	tx = common.L1Tx{
 122		FromIdx:       256,
 123		ToIdx:         258,
 124		Amount:        big.NewInt(5),
 125		DepositAmount: big.NewInt(0),
 126		FromEthAddr:   tc.Users["A"].Addr,
 127		UserOrigin:    true,
 128	}
 129	tp.computeEffectiveAmounts(&tx)
 130	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
 131	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 132
 133	// expect error due not same EthAddr
 134	tx = common.L1Tx{
 135		FromIdx:       256,
 136		ToIdx:         257,
 137		Amount:        big.NewInt(8),
 138		DepositAmount: big.NewInt(0),
 139		FromEthAddr:   tc.Users["B"].Addr,
 140		UserOrigin:    true,
 141	}
 142	tp.computeEffectiveAmounts(&tx)
 143	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
 144	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 145
 146	// expect on TxTypeDepositTransfer EffectiveAmount=0, but
 147	// EffectiveDepositAmount!=0, due not enough funds to make the transfer
 148	tx = common.L1Tx{
 149		FromIdx:       256,
 150		ToIdx:         257,
 151		Amount:        big.NewInt(20),
 152		DepositAmount: big.NewInt(8),
 153		FromEthAddr:   tc.Users["A"].Addr,
 154		UserOrigin:    true,
 155	}
 156	tp.computeEffectiveAmounts(&tx)
 157	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
 158	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 159
 160	// expect on TxTypeDepositTransfer EffectiveAmount=0, but
 161	// EffectiveDepositAmount!=0, due different EthAddr from FromIdx
 162	// address
 163	tx = common.L1Tx{
 164		FromIdx:       256,
 165		ToIdx:         257,
 166		Amount:        big.NewInt(8),
 167		DepositAmount: big.NewInt(8),
 168		FromEthAddr:   tc.Users["B"].Addr,
 169		UserOrigin:    true,
 170	}
 171	tp.computeEffectiveAmounts(&tx)
 172	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
 173	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 174
 175	// CreateAccountDepositTransfer for TokenID=1 when receiver does not
 176	// have an account for that TokenID, expect that the
 177	// EffectiveDepositAmount=DepositAmount, but EffectiveAmount==0
 178	tx = common.L1Tx{
 179		FromIdx:       0,
 180		ToIdx:         257,
 181		Amount:        big.NewInt(8),
 182		DepositAmount: big.NewInt(8),
 183		FromEthAddr:   tc.Users["A"].Addr,
 184		TokenID:       2,
 185		UserOrigin:    true,
 186		Type:          common.TxTypeCreateAccountDepositTransfer,
 187	}
 188	tp.computeEffectiveAmounts(&tx)
 189	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
 190	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 191
 192	// DepositTransfer for TokenID=1 when receiver does not have an account
 193	// for that TokenID, expect that the
 194	// EffectiveDepositAmount=DepositAmount, but EffectiveAmount=0
 195	tx = common.L1Tx{
 196		FromIdx:       258,
 197		ToIdx:         256,
 198		Amount:        big.NewInt(8),
 199		DepositAmount: big.NewInt(8),
 200		FromEthAddr:   tc.Users["C"].Addr,
 201		TokenID:       1,
 202		UserOrigin:    true,
 203		Type:          common.TxTypeDepositTransfer,
 204	}
 205	tp.computeEffectiveAmounts(&tx)
 206	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
 207	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 208}
 209
 210func TestProcessTxsBalances(t *testing.T) {
 211	dir, err := ioutil.TempDir("", "tmpdb")
 212	require.NoError(t, err)
 213	defer assert.NoError(t, os.RemoveAll(dir))
 214
 215	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 216		Type: statedb.TypeSynchronizer, NLevels: 32})
 217	assert.NoError(t, err)
 218
 219	chainID := uint16(0)
 220	// generate test transactions from test.SetBlockchain0 code
 221	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 222	blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
 223	require.NoError(t, err)
 224
 225	config := Config{
 226		NLevels:  32,
 227		MaxFeeTx: 64,
 228		MaxTx:    512,
 229		MaxL1Tx:  16,
 230		ChainID:  chainID,
 231	}
 232	tp := NewTxProcessor(sdb, config)
 233
 234	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
 235	_, err = tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
 236	require.NoError(t, err)
 237	assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
 238
 239	log.Debug("block:0 batch:2")
 240	l1UserTxs := []common.L1Tx{}
 241	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 242	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 243	require.NoError(t, err)
 244	assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
 245
 246	log.Debug("block:0 batch:3")
 247	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
 248	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
 249	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
 250	require.NoError(t, err)
 251	checkBalance(t, tc, sdb, "A", 0, "500")
 252	assert.Equal(t, "13644148972047617726265275926674266298636745191961029124811988256139761111521", tp.s.MT.Root().BigInt().String())
 253
 254	log.Debug("block:0 batch:4")
 255	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
 256	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
 257	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
 258	require.NoError(t, err)
 259	checkBalance(t, tc, sdb, "A", 0, "500")
 260	checkBalance(t, tc, sdb, "A", 1, "500")
 261	assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
 262
 263	log.Debug("block:0 batch:5")
 264	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
 265	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
 266	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
 267	require.NoError(t, err)
 268	checkBalance(t, tc, sdb, "A", 0, "500")
 269	checkBalance(t, tc, sdb, "A", 1, "500")
 270	assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
 271
 272	log.Debug("block:0 batch:6")
 273	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
 274	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
 275	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
 276	require.NoError(t, err)
 277	checkBalance(t, tc, sdb, "A", 0, "600")
 278	checkBalance(t, tc, sdb, "A", 1, "500")
 279	checkBalance(t, tc, sdb, "B", 0, "400")
 280	assert.Equal(t, "4191361650490017591061467288209836928064232431729236465872209988325272262963", tp.s.MT.Root().BigInt().String())
 281
 282	coordIdxs := []common.Idx{261, 262}
 283	log.Debug("block:0 batch:7")
 284	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
 285	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[6].L2Txs)
 286	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
 287	require.NoError(t, err)
 288	checkBalance(t, tc, sdb, "Coord", 0, "10")
 289	checkBalance(t, tc, sdb, "Coord", 1, "20")
 290	checkBalance(t, tc, sdb, "A", 0, "600")
 291	checkBalance(t, tc, sdb, "A", 1, "280")
 292	checkBalance(t, tc, sdb, "B", 0, "290")
 293	checkBalance(t, tc, sdb, "B", 1, "200")
 294	checkBalance(t, tc, sdb, "C", 0, "100")
 295	checkBalance(t, tc, sdb, "D", 0, "800")
 296	assert.Equal(t, "7614010373759339299470010949167613050707822522530721724565424494781010548240", tp.s.MT.Root().BigInt().String())
 297
 298	log.Debug("block:0 batch:8")
 299	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
 300	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[7].L2Txs)
 301	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
 302	require.NoError(t, err)
 303	checkBalance(t, tc, sdb, "Coord", 0, "35")
 304	checkBalance(t, tc, sdb, "Coord", 1, "30")
 305	checkBalance(t, tc, sdb, "A", 0, "430")
 306	checkBalance(t, tc, sdb, "A", 1, "280")
 307	checkBalance(t, tc, sdb, "B", 0, "390")
 308	checkBalance(t, tc, sdb, "B", 1, "90")
 309	checkBalance(t, tc, sdb, "C", 0, "45")
 310	checkBalance(t, tc, sdb, "C", 1, "100")
 311	checkBalance(t, tc, sdb, "D", 0, "800")
 312	assert.Equal(t, "21231789250434471575486264439945776732824482207853465397552873521865656677689", tp.s.MT.Root().BigInt().String())
 313
 314	coordIdxs = []common.Idx{262}
 315	log.Debug("block:1 batch:1")
 316	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
 317	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
 318	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
 319	require.NoError(t, err)
 320	checkBalance(t, tc, sdb, "Coord", 0, "75")
 321	checkBalance(t, tc, sdb, "Coord", 1, "30")
 322	checkBalance(t, tc, sdb, "A", 0, "730")
 323	checkBalance(t, tc, sdb, "A", 1, "280")
 324	checkBalance(t, tc, sdb, "B", 0, "380")
 325	checkBalance(t, tc, sdb, "B", 1, "90")
 326	checkBalance(t, tc, sdb, "C", 0, "845")
 327	checkBalance(t, tc, sdb, "C", 1, "100")
 328	checkBalance(t, tc, sdb, "D", 0, "470")
 329	assert.Equal(t, "11289313644810782435120113035387729451095637380468777086895109386127538554246", tp.s.MT.Root().BigInt().String())
 330
 331	coordIdxs = []common.Idx{}
 332	log.Debug("block:1 batch:2")
 333	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
 334	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
 335	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 336	require.NoError(t, err)
 337	assert.Equal(t, "10342681351319338354912862547249967104198317571995055517008223832276478908482", tp.s.MT.Root().BigInt().String())
 338
 339	// use Set of PoolL2 txs
 340	poolL2Txs, err := tc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow1)
 341	assert.NoError(t, err)
 342
 343	_, err = tp.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
 344	require.NoError(t, err)
 345	checkBalance(t, tc, sdb, "Coord", 0, "75")
 346	checkBalance(t, tc, sdb, "Coord", 1, "30")
 347	checkBalance(t, tc, sdb, "A", 0, "510")
 348	checkBalance(t, tc, sdb, "A", 1, "170")
 349	checkBalance(t, tc, sdb, "B", 0, "480")
 350	checkBalance(t, tc, sdb, "B", 1, "190")
 351	checkBalance(t, tc, sdb, "C", 0, "845")
 352	checkBalance(t, tc, sdb, "C", 1, "100")
 353	checkBalance(t, tc, sdb, "D", 0, "360")
 354	checkBalance(t, tc, sdb, "F", 0, "100")
 355}
 356
 357func TestProcessTxsSynchronizer(t *testing.T) {
 358	dir, err := ioutil.TempDir("", "tmpdb")
 359	require.NoError(t, err)
 360	defer assert.NoError(t, os.RemoveAll(dir))
 361
 362	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 363		Type: statedb.TypeSynchronizer, NLevels: 32})
 364	assert.NoError(t, err)
 365
 366	chainID := uint16(0)
 367	// generate test transactions from test.SetBlockchain0 code
 368	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 369	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
 370	require.NoError(t, err)
 371
 372	assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
 373	assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
 374	assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
 375	assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
 376	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
 377	assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
 378	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
 379	assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
 380
 381	// Coordinator Idx where to send the fees
 382	coordIdxs := []common.Idx{256, 257, 258, 259}
 383
 384	// Idx of user 'A'
 385	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
 386
 387	config := Config{
 388		NLevels:  32,
 389		MaxFeeTx: 64,
 390		MaxTx:    512,
 391		MaxL1Tx:  32,
 392		ChainID:  chainID,
 393	}
 394	tp := NewTxProcessor(sdb, config)
 395
 396	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
 397	// to create the Coordinator accounts to receive the fees
 398	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
 399	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
 400	require.NoError(t, err)
 401	assert.Equal(t, 4, len(ptOut.CreatedAccounts))
 402	assert.Equal(t, 0, len(ptOut.CollectedFees))
 403
 404	log.Debug("block:0 batch:2")
 405	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 406	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
 407		blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 408	require.NoError(t, err)
 409	assert.Equal(t, 0, len(ptOut.ExitInfos))
 410	assert.Equal(t, 31, len(ptOut.CreatedAccounts))
 411	assert.Equal(t, 4, len(ptOut.CollectedFees))
 412	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
 413	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
 414	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
 415	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
 416	acc, err := sdb.GetAccount(idxA1)
 417	require.NoError(t, err)
 418	assert.Equal(t, "50", acc.Balance.String())
 419
 420	log.Debug("block:0 batch:3")
 421	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
 422	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
 423	require.NoError(t, err)
 424	assert.Equal(t, 0, len(ptOut.ExitInfos))
 425	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
 426	assert.Equal(t, 4, len(ptOut.CollectedFees))
 427	assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
 428	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
 429	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
 430	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
 431	acc, err = sdb.GetAccount(idxA1)
 432	require.NoError(t, err)
 433	assert.Equal(t, "35", acc.Balance.String())
 434
 435	log.Debug("block:1 batch:1")
 436	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
 437	// before processing expect l2Txs[0:2].Nonce==0
 438	assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
 439	assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
 440	assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
 441
 442	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
 443	require.NoError(t, err)
 444
 445	// after processing expect l2Txs[0:2].Nonce!=0 and has expected value
 446	assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
 447	assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
 448	assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
 449
 450	assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
 451	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
 452	assert.Equal(t, 4, len(ptOut.CollectedFees))
 453	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
 454	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
 455	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
 456	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
 457	acc, err = sdb.GetAccount(idxA1)
 458	require.NoError(t, err)
 459	assert.Equal(t, "57", acc.Balance.String())
 460
 461	log.Debug("block:1 batch:2")
 462	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
 463	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
 464		blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 465	require.NoError(t, err)
 466
 467	assert.Equal(t, 1, len(ptOut.ExitInfos)) // 1, as previous batch was without L1UserTxs, and has pending the 'ForceExit(1) A: 5', and the 2 exit transactions get grouped under 1 ExitInfo
 468	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
 469	assert.Equal(t, 4, len(ptOut.CollectedFees))
 470	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
 471	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
 472	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
 473	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
 474	acc, err = sdb.GetAccount(idxA1)
 475	assert.NoError(t, err)
 476	assert.Equal(t, "77", acc.Balance.String())
 477
 478	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
 479	acc, err = sdb.GetAccount(idxB0)
 480	require.NoError(t, err)
 481	assert.Equal(t, "51", acc.Balance.String())
 482
 483	// get balance of Coordinator account for TokenID==0
 484	acc, err = sdb.GetAccount(common.Idx(256))
 485	require.NoError(t, err)
 486	assert.Equal(t, "2", acc.Balance.String())
 487}
 488
 489func TestProcessTxsBatchBuilder(t *testing.T) {
 490	dir, err := ioutil.TempDir("", "tmpdb")
 491	require.NoError(t, err)
 492	defer assert.NoError(t, os.RemoveAll(dir))
 493
 494	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 495		Type: statedb.TypeBatchBuilder, NLevels: 32})
 496	assert.NoError(t, err)
 497
 498	chainID := uint16(0)
 499	// generate test transactions from test.SetBlockchain0 code
 500	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 501	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
 502	require.NoError(t, err)
 503
 504	// Coordinator Idx where to send the fees
 505	coordIdxs := []common.Idx{256, 257, 258, 259}
 506
 507	// Idx of user 'A'
 508	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
 509
 510	config := Config{
 511		NLevels:  32,
 512		MaxFeeTx: 64,
 513		MaxTx:    512,
 514		MaxL1Tx:  32,
 515		ChainID:  chainID,
 516	}
 517	tp := NewTxProcessor(sdb, config)
 518
 519	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
 520	// to create the Coordinator accounts to receive the fees
 521	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
 522	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
 523	require.NoError(t, err)
 524	// expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
 525	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
 526
 527	log.Debug("block:0 batch:2")
 528	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 529	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 530	require.NoError(t, err)
 531	assert.Equal(t, 0, len(ptOut.ExitInfos))
 532	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
 533	acc, err := sdb.GetAccount(idxA1)
 534	require.NoError(t, err)
 535	assert.Equal(t, "50", acc.Balance.String())
 536
 537	log.Debug("block:0 batch:3")
 538	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
 539	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
 540	require.NoError(t, err)
 541	assert.Equal(t, 0, len(ptOut.ExitInfos))
 542	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
 543	acc, err = sdb.GetAccount(idxA1)
 544	require.NoError(t, err)
 545	assert.Equal(t, "35", acc.Balance.String())
 546
 547	log.Debug("block:1 batch:1")
 548	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
 549	_, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
 550	require.NoError(t, err)
 551	acc, err = sdb.GetAccount(idxA1)
 552	require.NoError(t, err)
 553	assert.Equal(t, "57", acc.Balance.String())
 554
 555	log.Debug("block:1 batch:2")
 556	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
 557	_, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
 558	require.NoError(t, err)
 559	acc, err = sdb.GetAccount(idxA1)
 560	assert.NoError(t, err)
 561	assert.Equal(t, "77", acc.Balance.String())
 562
 563	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
 564	acc, err = sdb.GetAccount(idxB0)
 565	require.NoError(t, err)
 566	assert.Equal(t, "51", acc.Balance.String())
 567
 568	// get balance of Coordinator account for TokenID==0
 569	acc, err = sdb.GetAccount(common.Idx(256))
 570	require.NoError(t, err)
 571	assert.Equal(t, common.TokenID(0), acc.TokenID)
 572	assert.Equal(t, "2", acc.Balance.String())
 573	acc, err = sdb.GetAccount(common.Idx(257))
 574	require.NoError(t, err)
 575	assert.Equal(t, common.TokenID(1), acc.TokenID)
 576	assert.Equal(t, "2", acc.Balance.String())
 577
 578	assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
 579}
 580
 581func TestProcessTxsRootTestVectors(t *testing.T) {
 582	dir, err := ioutil.TempDir("", "tmpdb")
 583	require.NoError(t, err)
 584	defer assert.NoError(t, os.RemoveAll(dir))
 585
 586	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 587		Type: statedb.TypeBatchBuilder, NLevels: 32})
 588	assert.NoError(t, err)
 589
 590	// same values than in the js test
 591	bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
 592	assert.NoError(t, err)
 593	l1Txs := []common.L1Tx{
 594		{
 595			FromIdx:       0,
 596			DepositAmount: big.NewInt(16000000),
 597			Amount:        big.NewInt(0),
 598			TokenID:       1,
 599			FromBJJ:       bjj0,
 600			FromEthAddr:   ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
 601			ToIdx:         0,
 602			Type:          common.TxTypeCreateAccountDeposit,
 603			UserOrigin:    true,
 604		},
 605	}
 606	l2Txs := []common.PoolL2Tx{
 607		{
 608			FromIdx: 256,
 609			ToIdx:   256,
 610			TokenID: 1,
 611			Amount:  big.NewInt(1000),
 612			Nonce:   0,
 613			Fee:     126,
 614			Type:    common.TxTypeTransfer,
 615		},
 616	}
 617
 618	chainID := uint16(0)
 619	config := Config{
 620		NLevels:  32,
 621		MaxFeeTx: 8,
 622		MaxTx:    32,
 623		MaxL1Tx:  16,
 624		ChainID:  chainID,
 625	}
 626	tp := NewTxProcessor(sdb, config)
 627	_, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
 628	require.NoError(t, err)
 629	assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
 630}
 631
 632func TestCreateAccountDepositMaxValue(t *testing.T) {
 633	dir, err := ioutil.TempDir("", "tmpdb")
 634	require.NoError(t, err)
 635	defer assert.NoError(t, os.RemoveAll(dir))
 636
 637	nLevels := 16
 638	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 639		Type: statedb.TypeBatchBuilder, NLevels: nLevels})
 640	assert.NoError(t, err)
 641
 642	users := txsets.GenerateJsUsers(t)
 643
 644	daMaxF40 := common.Float40(0xFFFFFFFFFF)
 645	daMaxBI, err := daMaxF40.BigInt()
 646	require.NoError(t, err)
 647	assert.Equal(t, "343597383670000000000000000000000000000000", daMaxBI.String())
 648
 649	daMax1F40 := common.Float40(0xFFFFFFFFFE)
 650	require.NoError(t, err)
 651	daMax1BI, err := daMax1F40.BigInt()
 652	require.NoError(t, err)
 653	assert.Equal(t, "343597383660000000000000000000000000000000", daMax1BI.String())
 654
 655	l1Txs := []common.L1Tx{
 656		{
 657			FromIdx:       0,
 658			DepositAmount: daMaxBI,
 659			Amount:        big.NewInt(0),
 660			TokenID:       1,
 661			FromBJJ:       users[0].BJJ.Public().Compress(),
 662			FromEthAddr:   users[0].Addr,
 663			ToIdx:         0,
 664			Type:          common.TxTypeCreateAccountDeposit,
 665			UserOrigin:    true,
 666		},
 667		{
 668			FromIdx:       0,
 669			DepositAmount: daMax1BI,
 670			Amount:        big.NewInt(0),
 671			TokenID:       1,
 672			FromBJJ:       users[1].BJJ.Public().Compress(),
 673			FromEthAddr:   users[1].Addr,
 674			ToIdx:         0,
 675			Type:          common.TxTypeCreateAccountDeposit,
 676			UserOrigin:    true,
 677		},
 678	}
 679
 680	chainID := uint16(0)
 681	config := Config{
 682		NLevels:  uint32(nLevels),
 683		MaxTx:    3,
 684		MaxL1Tx:  2,
 685		MaxFeeTx: 2,
 686		ChainID:  chainID,
 687	}
 688	tp := NewTxProcessor(sdb, config)
 689
 690	_, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
 691	require.NoError(t, err)
 692
 693	// check balances
 694	acc, err := sdb.GetAccount(common.Idx(256))
 695	require.NoError(t, err)
 696	assert.Equal(t, daMaxBI, acc.Balance)
 697	acc, err = sdb.GetAccount(common.Idx(257))
 698	require.NoError(t, err)
 699	assert.Equal(t, daMax1BI, acc.Balance)
 700}
 701
 702func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
 703	dir, err := ioutil.TempDir("", "tmpdb")
 704	require.NoError(t, err)
 705	defer assert.NoError(t, os.RemoveAll(dir))
 706
 707	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 708		Type: statedb.TypeBatchBuilder, NLevels: 32})
 709	assert.NoError(t, err)
 710
 711	chainID := uint16(1)
 712
 713	// generate test transactions from test.SetBlockchain0 code
 714	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 715
 716	set := `
 717		Type: Blockchain
 718
 719		CreateAccountDeposit(0) A: 200
 720
 721		> batchL1 // freeze L1User{1}
 722
 723		CreateAccountCoordinator(0) Coord
 724		CreateAccountCoordinator(0) B
 725
 726		Transfer(0) A-B: 100 (126)
 727
 728		> batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
 729		> block
 730	`
 731	blocks, err := tc.GenerateBlocks(set)
 732	require.NoError(t, err)
 733
 734	config := Config{
 735		NLevels:  32,
 736		MaxFeeTx: 64,
 737		MaxTx:    512,
 738		MaxL1Tx:  16,
 739		ChainID:  chainID,
 740	}
 741	tp := NewTxProcessor(sdb, config)
 742	// batch1
 743	_, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
 744	require.NoError(t, err)
 745
 746	return tp, tc, blocks
 747}
 748
 749func TestMultipleCoordIdxForTokenID(t *testing.T) {
 750	// Check that ProcessTxs always uses the first occurrence of the
 751	// CoordIdx for each TokenID
 752
 753	coordIdxs := []common.Idx{257, 257, 257}
 754	tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
 755	l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
 756	l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
 757	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
 758	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 759	_, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
 760	require.NoError(t, err)
 761
 762	checkBalanceByIdx(t, tp.s, 256, "90")  // A
 763	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
 764	checkBalanceByIdx(t, tp.s, 258, "100") // B
 765	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
 766
 767	// reset StateDB values
 768	coordIdxs = []common.Idx{259, 257}
 769	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
 770	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
 771	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
 772	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
 773	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 774	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
 775	require.NoError(t, err)
 776
 777	checkBalanceByIdx(t, tp.s, 256, "90")  // A
 778	checkBalanceByIdx(t, tp.s, 257, "0")   // Coord0
 779	checkBalanceByIdx(t, tp.s, 258, "100") // B
 780	checkBalanceByIdx(t, tp.s, 259, "10")  // Coord0
 781
 782	// reset StateDB values
 783	coordIdxs = []common.Idx{257, 259}
 784	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
 785	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
 786	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
 787	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
 788	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
 789	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
 790	require.NoError(t, err)
 791
 792	checkBalanceByIdx(t, tp.s, 256, "90")  // A
 793	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
 794	checkBalanceByIdx(t, tp.s, 258, "100") // B
 795	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
 796}
 797
 798func testTwoExits(t *testing.T, stateDBType statedb.TypeStateDB) ([]*ProcessTxOutput,
 799	[]*ProcessTxOutput, []*ProcessTxOutput) {
 800	// In the first part we generate a batch with two force exits for the
 801	// same account of 20 each.  The txprocessor output should be a single
 802	// exitInfo with balance of 40.
 803	dir, err := ioutil.TempDir("", "tmpdb")
 804	require.NoError(t, err)
 805	defer assert.NoError(t, os.RemoveAll(dir))
 806
 807	nLevels := 16
 808	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 809		Type: stateDBType, NLevels: nLevels})
 810	assert.NoError(t, err)
 811
 812	chainID := uint16(1)
 813
 814	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 815
 816	// Two exits for the same account.  The tx processor should output a
 817	// single exit with the accumulated exit balance
 818	set := `
 819		Type: Blockchain
 820
 821		CreateAccountDeposit(0) A: 100
 822
 823		> batchL1 // freeze L1User{1}
 824		> batchL1 // forge L1User{1}
 825
 826		ForceExit(0) A: 20
 827		ForceExit(0) A: 20
 828
 829		> batchL1 // freeze L1User{2}
 830		> batchL1 // forge L1User{2}
 831		> block
 832	`
 833	blocks, err := tc.GenerateBlocks(set)
 834	require.NoError(t, err)
 835	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
 836	require.NoError(t, err)
 837	err = tc.FillBlocksForgedL1UserTxs(blocks)
 838	require.NoError(t, err)
 839
 840	// Sanity check
 841	require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
 842	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
 843
 844	config := Config{
 845		NLevels:  uint32(nLevels),
 846		MaxTx:    3,
 847		MaxL1Tx:  2,
 848		MaxFeeTx: 2,
 849		ChainID:  chainID,
 850	}
 851	tp := NewTxProcessor(sdb, config)
 852	ptOuts := []*ProcessTxOutput{}
 853	for _, block := range blocks {
 854		for _, batch := range block.Rollup.Batches {
 855			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
 856			require.NoError(t, err)
 857			ptOuts = append(ptOuts, ptOut)
 858		}
 859	}
 860
 861	acc, err := sdb.GetAccount(256)
 862	require.NoError(t, err)
 863	assert.Equal(t, big.NewInt(60), acc.Balance)
 864
 865	// In the second part we start a fresh statedb and generate a batch
 866	// with one force exit for the same account as before.  The txprocessor
 867	// output should be a single exitInfo with balance of 40, and the exit
 868	// merkle tree proof should be equal to the previous one.
 869
 870	dir2, err := ioutil.TempDir("", "tmpdb")
 871	require.NoError(t, err)
 872	defer assert.NoError(t, os.RemoveAll(dir2))
 873
 874	sdb2, err := statedb.NewStateDB(statedb.Config{Path: dir2, Keep: 128,
 875		Type: stateDBType, NLevels: nLevels})
 876	assert.NoError(t, err)
 877
 878	tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 879
 880	// Single exit with balance of both exits in previous set.  The exit
 881	// root should match.
 882	set2 := `
 883		Type: Blockchain
 884
 885		CreateAccountDeposit(0) A: 100
 886
 887		> batchL1 // freeze L1User{1}
 888		> batchL1 // forge L1User{1}
 889
 890		ForceExit(0) A: 40
 891
 892		> batchL1 // freeze L1User{2}
 893		> batchL1 // forge L1User{2}
 894		> block
 895	`
 896	blocks, err = tc.GenerateBlocks(set2)
 897	require.NoError(t, err)
 898	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
 899	require.NoError(t, err)
 900	err = tc.FillBlocksForgedL1UserTxs(blocks)
 901	require.NoError(t, err)
 902
 903	tp = NewTxProcessor(sdb2, config)
 904	ptOuts2 := []*ProcessTxOutput{}
 905	for _, block := range blocks {
 906		for _, batch := range block.Rollup.Batches {
 907			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
 908			require.NoError(t, err)
 909			ptOuts2 = append(ptOuts2, ptOut)
 910		}
 911	}
 912
 913	// In the third part we start a fresh statedb and generate a batch with
 914	// two force exit for the same account as before but where the 1st Exit
 915	// is with all the amount, and the 2nd Exit is with more amount than
 916	// the available balance.  The txprocessor output should be a single
 917	// exitInfo with balance of 40, and the exit merkle tree proof should
 918	// be equal to the previous ones.
 919
 920	dir3, err := ioutil.TempDir("", "tmpdb")
 921	require.NoError(t, err)
 922	defer assert.NoError(t, os.RemoveAll(dir3))
 923
 924	sdb3, err := statedb.NewStateDB(statedb.Config{Path: dir3, Keep: 128,
 925		Type: stateDBType, NLevels: nLevels})
 926	assert.NoError(t, err)
 927
 928	tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 929
 930	// Single exit with balance of both exits in previous set.  The exit
 931	// root should match.
 932	set3 := `
 933		Type: Blockchain
 934
 935		CreateAccountDeposit(0) A: 100
 936
 937		> batchL1 // freeze L1User{1}
 938		> batchL1 // forge L1User{1}
 939
 940		ForceExit(0) A: 40
 941		ForceExit(0) A: 100
 942
 943		> batchL1 // freeze L1User{2}
 944		> batchL1 // forge L1User{2}
 945		> block
 946	`
 947	blocks, err = tc.GenerateBlocks(set3)
 948	require.NoError(t, err)
 949	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
 950	require.NoError(t, err)
 951	err = tc.FillBlocksForgedL1UserTxs(blocks)
 952	require.NoError(t, err)
 953
 954	tp = NewTxProcessor(sdb3, config)
 955	ptOuts3 := []*ProcessTxOutput{}
 956	for _, block := range blocks {
 957		for _, batch := range block.Rollup.Batches {
 958			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
 959			require.NoError(t, err)
 960			ptOuts3 = append(ptOuts3, ptOut)
 961		}
 962	}
 963
 964	return ptOuts, ptOuts2, ptOuts3
 965}
 966
 967func TestTwoExitsSynchronizer(t *testing.T) {
 968	ptOuts, ptOuts2, ptOuts3 := testTwoExits(t, statedb.TypeSynchronizer)
 969
 970	assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
 971	assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
 972
 973	assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
 974	assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts3[3].ExitInfos[0].MerkleProof)
 975}
 976
 977func TestExitOf0Amount(t *testing.T) {
 978	// Test to check that when doing an Exit with amount 0 the Exit Root
 979	// does not change (as there is no new Exit Leaf created)
 980
 981	dir, err := ioutil.TempDir("", "tmpdb")
 982	require.NoError(t, err)
 983	defer assert.NoError(t, os.RemoveAll(dir))
 984
 985	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 986		Type: statedb.TypeBatchBuilder, NLevels: 32})
 987	assert.NoError(t, err)
 988
 989	chainID := uint16(1)
 990
 991	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 992
 993	set := `
 994		Type: Blockchain
 995
 996		CreateAccountDeposit(0) A: 100
 997		CreateAccountDeposit(0) B: 100
 998
 999		> batchL1 // batch1: freeze L1User{2}
1000		> batchL1 // batch2: forge L1User{2}
1001
1002		ForceExit(0) A: 10
1003		ForceExit(0) B: 0
1004
1005		> batchL1 // batch3: freeze L1User{2}
1006		> batchL1 // batch4: forge L1User{2}
1007
1008		ForceExit(0) A: 10
1009
1010		> batchL1 // batch5: freeze L1User{1}
1011		> batchL1 // batch6: forge L1User{1}
1012
1013		ForceExit(0) A: 0
1014		> batchL1 // batch7: freeze L1User{1}
1015		> batchL1 // batch8: forge L1User{1}
1016		> block
1017	`
1018	blocks, err := tc.GenerateBlocks(set)
1019	require.NoError(t, err)
1020	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
1021	require.NoError(t, err)
1022	err = tc.FillBlocksForgedL1UserTxs(blocks)
1023	require.NoError(t, err)
1024
1025	// Sanity check
1026	require.Equal(t, 2, len(blocks[0].Rollup.Batches[1].L1UserTxs))
1027	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
1028	require.Equal(t, big.NewInt(10), blocks[0].Rollup.Batches[3].L1UserTxs[0].Amount)
1029	require.Equal(t, big.NewInt(0), blocks[0].Rollup.Batches[3].L1UserTxs[1].Amount)
1030
1031	config := Config{
1032		NLevels:  32,
1033		MaxFeeTx: 64,
1034		MaxTx:    512,
1035		MaxL1Tx:  16,
1036		ChainID:  chainID,
1037	}
1038	tp := NewTxProcessor(sdb, config)
1039
1040	// For this test are only processed the batches with transactions:
1041	// - Batch2, equivalent to Batches[1]
1042	// - Batch4, equivalent to Batches[3]
1043	// - Batch6, equivalent to Batches[5]
1044	// - Batch8, equivalent to Batches[7]
1045
1046	// process Batch2:
1047	_, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[1].L1UserTxs, nil, nil)
1048	require.NoError(t, err)
1049	// process Batch4:
1050	ptOut, err := tp.ProcessTxs(nil, blocks[0].Rollup.Batches[3].L1UserTxs, nil, nil)
1051	require.NoError(t, err)
1052	assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1053	exitRootBatch4 := ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String()
1054
1055	// process Batch6:
1056	ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[5].L1UserTxs, nil, nil)
1057	require.NoError(t, err)
1058	assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1059	// Expect that the ExitRoot for the Batch6 will be equal than for the
1060	// Batch4, as the Batch4 & Batch6 have the same tx with Exit Amount=10,
1061	// and Batch4 has a 2nd tx with Exit Amount=0.
1062	assert.Equal(t, exitRootBatch4, ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1063
1064	// For the Batch8, as there is only 1 exit with Amount=0, the ExitRoot
1065	// should be 0.
1066	// process Batch8:
1067	ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[7].L1UserTxs, nil, nil)
1068	require.NoError(t, err)
1069	assert.Equal(t, "0", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1070}
1071
1072func TestUpdatedAccounts(t *testing.T) {
1073	dir, err := ioutil.TempDir("", "tmpdb")
1074	require.NoError(t, err)
1075	defer assert.NoError(t, os.RemoveAll(dir))
1076
1077	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
1078		Type: statedb.TypeSynchronizer, NLevels: 32})
1079	assert.NoError(t, err)
1080
1081	set := `
1082		Type: Blockchain
1083		AddToken(1)
1084		CreateAccountCoordinator(0) Coord // 256
1085		CreateAccountCoordinator(1) Coord // 257
1086		> batch // 1
1087		CreateAccountDeposit(0) A: 50 // 258
1088		CreateAccountDeposit(0) B: 60 // 259
1089		CreateAccountDeposit(1) A: 70 // 260
1090		CreateAccountDeposit(1) B: 80 // 261
1091		> batchL1 // 2
1092		> batchL1 // 3
1093		Transfer(0) A-B: 5 (126)
1094		> batch // 4
1095		Exit(1) B: 5 (126)
1096		> batch // 5
1097		> block
1098	`
1099
1100	chainID := uint16(0)
1101	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1102	blocks, err := tc.GenerateBlocks(set)
1103	require.NoError(t, err)
1104	tilCfgExtra := til.ConfigExtra{
1105		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
1106		CoordUser:     "Coord",
1107	}
1108	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1109	require.NoError(t, err)
1110	tc.FillBlocksL1UserTxsBatchNum(blocks)
1111	err = tc.FillBlocksForgedL1UserTxs(blocks)
1112	require.NoError(t, err)
1113
1114	require.Equal(t, 5, len(blocks[0].Rollup.Batches))
1115
1116	config := Config{
1117		NLevels:  32,
1118		MaxFeeTx: 64,
1119		MaxTx:    512,
1120		MaxL1Tx:  16,
1121		ChainID:  chainID,
1122	}
1123	tp := NewTxProcessor(sdb, config)
1124
1125	sortedKeys := func(m map[common.Idx]*common.Account) []int {
1126		keys := make([]int, 0)
1127		for k := range m {
1128			keys = append(keys, int(k))
1129		}
1130		sort.Ints(keys)
1131		return keys
1132	}
1133
1134	for _, batch := range blocks[0].Rollup.Batches {
1135		l2Txs := common.L2TxsToPoolL2Txs(batch.L2Txs)
1136		ptOut, err := tp.ProcessTxs(batch.Batch.FeeIdxsCoordinator, batch.L1UserTxs,
1137			batch.L1CoordinatorTxs, l2Txs)
1138		require.NoError(t, err)
1139		switch batch.Batch.BatchNum {
1140		case 1:
1141			assert.Equal(t, 2, len(ptOut.UpdatedAccounts))
1142			assert.Equal(t, []int{256, 257}, sortedKeys(ptOut.UpdatedAccounts))
1143		case 2:
1144			assert.Equal(t, 0, len(ptOut.UpdatedAccounts))
1145			assert.Equal(t, []int{}, sortedKeys(ptOut.UpdatedAccounts))
1146		case 3:
1147			assert.Equal(t, 4, len(ptOut.UpdatedAccounts))
1148			assert.Equal(t, []int{258, 259, 260, 261}, sortedKeys(ptOut.UpdatedAccounts))
1149		case 4:
1150			assert.Equal(t, 2+1, len(ptOut.UpdatedAccounts))
1151			assert.Equal(t, []int{256, 258, 259}, sortedKeys(ptOut.UpdatedAccounts))
1152		case 5:
1153			assert.Equal(t, 1+1, len(ptOut.UpdatedAccounts))
1154			assert.Equal(t, []int{257, 261}, sortedKeys(ptOut.UpdatedAccounts))
1155		}
1156		for idx, updAcc := range ptOut.UpdatedAccounts {
1157			acc, err := sdb.GetAccount(idx)
1158			require.NoError(t, err)
1159			// If acc.Balance is 0, set it to 0 with big.NewInt so
1160			// that the comparison succeeds.  Without this, the
1161			// comparison will not succeed because acc.Balance is
1162			// set from a slice, and thus the internal big.Int
1163			// buffer is not nil (big.Int.abs)
1164			if acc.Balance.BitLen() == 0 {
1165				acc.Balance = big.NewInt(0)
1166			}
1167			assert.Equal(t, acc, updAcc)
1168		}
1169	}
1170}