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) {
 799	// In the first part we generate a batch with two force exits for the
 800	// same account of 20 each.  The txprocessor output should be a single
 801	// exitInfo with balance of 40.
 802	dir, err := ioutil.TempDir("", "tmpdb")
 803	require.NoError(t, err)
 804	defer assert.NoError(t, os.RemoveAll(dir))
 805
 806	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 807		Type: statedb.TypeSynchronizer, NLevels: 32})
 808	assert.NoError(t, err)
 809
 810	chainID := uint16(1)
 811
 812	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 813
 814	// Two exits for the same account.  The tx processor should output a
 815	// single exit with the accumulated exit balance
 816	set := `
 817		Type: Blockchain
 818
 819		CreateAccountDeposit(0) A: 100
 820
 821		> batchL1 // freeze L1User{1}
 822		> batchL1 // forge L1User{1}
 823
 824		ForceExit(0) A: 20
 825		ForceExit(0) A: 20
 826
 827		> batchL1 // freeze L1User{2}
 828		> batchL1 // forge L1User{2}
 829		> block
 830	`
 831	blocks, err := tc.GenerateBlocks(set)
 832	require.NoError(t, err)
 833	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
 834	require.NoError(t, err)
 835	err = tc.FillBlocksForgedL1UserTxs(blocks)
 836	require.NoError(t, err)
 837
 838	// Sanity check
 839	require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
 840	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
 841
 842	config := Config{
 843		NLevels:  32,
 844		MaxFeeTx: 64,
 845		MaxTx:    512,
 846		MaxL1Tx:  16,
 847		ChainID:  chainID,
 848	}
 849	tp := NewTxProcessor(sdb, config)
 850	ptOuts := []*ProcessTxOutput{}
 851	for _, block := range blocks {
 852		for _, batch := range block.Rollup.Batches {
 853			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
 854			require.NoError(t, err)
 855			ptOuts = append(ptOuts, ptOut)
 856		}
 857	}
 858
 859	assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
 860	assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
 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: statedb.TypeSynchronizer, NLevels: 32})
 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	assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
 914}
 915
 916func TestExitOf0Amount(t *testing.T) {
 917	// Test to check that when doing an Exit with amount 0 the Exit Root
 918	// does not change (as there is no new Exit Leaf created)
 919
 920	dir, err := ioutil.TempDir("", "tmpdb")
 921	require.NoError(t, err)
 922	defer assert.NoError(t, os.RemoveAll(dir))
 923
 924	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 925		Type: statedb.TypeBatchBuilder, NLevels: 32})
 926	assert.NoError(t, err)
 927
 928	chainID := uint16(1)
 929
 930	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 931
 932	set := `
 933		Type: Blockchain
 934
 935		CreateAccountDeposit(0) A: 100
 936		CreateAccountDeposit(0) B: 100
 937
 938		> batchL1 // batch1: freeze L1User{2}
 939		> batchL1 // batch2: forge L1User{2}
 940
 941		ForceExit(0) A: 10
 942		ForceExit(0) B: 0
 943
 944		> batchL1 // batch3: freeze L1User{2}
 945		> batchL1 // batch4: forge L1User{2}
 946
 947		ForceExit(0) A: 10
 948
 949		> batchL1 // batch5: freeze L1User{1}
 950		> batchL1 // batch6: forge L1User{1}
 951
 952		ForceExit(0) A: 0
 953		> batchL1 // batch7: freeze L1User{1}
 954		> batchL1 // batch8: forge L1User{1}
 955		> block
 956	`
 957	blocks, err := tc.GenerateBlocks(set)
 958	require.NoError(t, err)
 959	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
 960	require.NoError(t, err)
 961	err = tc.FillBlocksForgedL1UserTxs(blocks)
 962	require.NoError(t, err)
 963
 964	// Sanity check
 965	require.Equal(t, 2, len(blocks[0].Rollup.Batches[1].L1UserTxs))
 966	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
 967	require.Equal(t, big.NewInt(10), blocks[0].Rollup.Batches[3].L1UserTxs[0].Amount)
 968	require.Equal(t, big.NewInt(0), blocks[0].Rollup.Batches[3].L1UserTxs[1].Amount)
 969
 970	config := Config{
 971		NLevels:  32,
 972		MaxFeeTx: 64,
 973		MaxTx:    512,
 974		MaxL1Tx:  16,
 975		ChainID:  chainID,
 976	}
 977	tp := NewTxProcessor(sdb, config)
 978
 979	// For this test are only processed the batches with transactions:
 980	// - Batch2, equivalent to Batches[1]
 981	// - Batch4, equivalent to Batches[3]
 982	// - Batch6, equivalent to Batches[5]
 983	// - Batch8, equivalent to Batches[7]
 984
 985	// process Batch2:
 986	_, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[1].L1UserTxs, nil, nil)
 987	require.NoError(t, err)
 988	// process Batch4:
 989	ptOut, err := tp.ProcessTxs(nil, blocks[0].Rollup.Batches[3].L1UserTxs, nil, nil)
 990	require.NoError(t, err)
 991	assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
 992	exitRootBatch4 := ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String()
 993
 994	// process Batch6:
 995	ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[5].L1UserTxs, nil, nil)
 996	require.NoError(t, err)
 997	assert.Equal(t, "14329759303391468223438874789317921522067594445474390443816827472846339238908", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
 998	// Expect that the ExitRoot for the Batch6 will be equal than for the
 999	// Batch4, as the Batch4 & Batch6 have the same tx with Exit Amount=10,
1000	// and Batch4 has a 2nd tx with Exit Amount=0.
1001	assert.Equal(t, exitRootBatch4, ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1002
1003	// For the Batch8, as there is only 1 exit with Amount=0, the ExitRoot
1004	// should be 0.
1005	// process Batch8:
1006	ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[7].L1UserTxs, nil, nil)
1007	require.NoError(t, err)
1008	assert.Equal(t, "0", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1009}
1010
1011func TestUpdatedAccounts(t *testing.T) {
1012	dir, err := ioutil.TempDir("", "tmpdb")
1013	require.NoError(t, err)
1014	defer assert.NoError(t, os.RemoveAll(dir))
1015
1016	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
1017		Type: statedb.TypeSynchronizer, NLevels: 32})
1018	assert.NoError(t, err)
1019
1020	set := `
1021Type: Blockchain
1022AddToken(1)
1023CreateAccountCoordinator(0) Coord // 256
1024CreateAccountCoordinator(1) Coord // 257
1025> batch // 1
1026CreateAccountDeposit(0) A: 50 // 258
1027CreateAccountDeposit(0) B: 60 // 259
1028CreateAccountDeposit(1) A: 70 // 260
1029CreateAccountDeposit(1) B: 80 // 261
1030> batchL1 // 2
1031> batchL1 // 3
1032Transfer(0) A-B: 5 (126)
1033> batch // 4
1034Exit(1) B: 5 (126)
1035> batch // 5
1036> block
1037	`
1038
1039	chainID := uint16(0)
1040	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1041	blocks, err := tc.GenerateBlocks(set)
1042	require.NoError(t, err)
1043	tilCfgExtra := til.ConfigExtra{
1044		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
1045		CoordUser:     "Coord",
1046	}
1047	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1048	require.NoError(t, err)
1049	tc.FillBlocksL1UserTxsBatchNum(blocks)
1050	err = tc.FillBlocksForgedL1UserTxs(blocks)
1051	require.NoError(t, err)
1052
1053	require.Equal(t, 5, len(blocks[0].Rollup.Batches))
1054
1055	config := Config{
1056		NLevels:  32,
1057		MaxFeeTx: 64,
1058		MaxTx:    512,
1059		MaxL1Tx:  16,
1060		ChainID:  chainID,
1061	}
1062	tp := NewTxProcessor(sdb, config)
1063
1064	sortedKeys := func(m map[common.Idx]*common.Account) []int {
1065		keys := make([]int, 0)
1066		for k := range m {
1067			keys = append(keys, int(k))
1068		}
1069		sort.Ints(keys)
1070		return keys
1071	}
1072
1073	for _, batch := range blocks[0].Rollup.Batches {
1074		l2Txs := common.L2TxsToPoolL2Txs(batch.L2Txs)
1075		ptOut, err := tp.ProcessTxs(batch.Batch.FeeIdxsCoordinator, batch.L1UserTxs,
1076			batch.L1CoordinatorTxs, l2Txs)
1077		require.NoError(t, err)
1078		switch batch.Batch.BatchNum {
1079		case 1:
1080			assert.Equal(t, 2, len(ptOut.UpdatedAccounts))
1081			assert.Equal(t, []int{256, 257}, sortedKeys(ptOut.UpdatedAccounts))
1082		case 2:
1083			assert.Equal(t, 0, len(ptOut.UpdatedAccounts))
1084			assert.Equal(t, []int{}, sortedKeys(ptOut.UpdatedAccounts))
1085		case 3:
1086			assert.Equal(t, 4, len(ptOut.UpdatedAccounts))
1087			assert.Equal(t, []int{258, 259, 260, 261}, sortedKeys(ptOut.UpdatedAccounts))
1088		case 4:
1089			assert.Equal(t, 2+1, len(ptOut.UpdatedAccounts))
1090			assert.Equal(t, []int{256, 258, 259}, sortedKeys(ptOut.UpdatedAccounts))
1091		case 5:
1092			assert.Equal(t, 1+1, len(ptOut.UpdatedAccounts))
1093			assert.Equal(t, []int{257, 261}, sortedKeys(ptOut.UpdatedAccounts))
1094		}
1095		for idx, updAcc := range ptOut.UpdatedAccounts {
1096			acc, err := sdb.GetAccount(idx)
1097			require.NoError(t, err)
1098			// If acc.Balance is 0, set it to 0 with big.NewInt so
1099			// that the comparison succeeds.  Without this, the
1100			// comparison will not succeed because acc.Balance is
1101			// set from a slice, and thus the internal big.Int
1102			// buffer is not nil (big.Int.abs)
1103			if acc.Balance.BitLen() == 0 {
1104				acc.Balance = big.NewInt(0)
1105			}
1106			assert.Equal(t, acc, updAcc)
1107		}
1108	}
1109}