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