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	"testing"
  8
  9	ethCommon "github.com/ethereum/go-ethereum/common"
 10	"github.com/hermeznetwork/hermez-node/common"
 11	"github.com/hermeznetwork/hermez-node/db/statedb"
 12	"github.com/hermeznetwork/hermez-node/log"
 13	"github.com/hermeznetwork/hermez-node/test/til"
 14	"github.com/hermeznetwork/hermez-node/test/txsets"
 15	"github.com/stretchr/testify/assert"
 16	"github.com/stretchr/testify/require"
 17)
 18
 19func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
 20	idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
 21	acc, err := sdb.GetAccount(idx)
 22	require.NoError(t, err)
 23	assert.Equal(t, expected, acc.Balance.String())
 24}
 25
 26func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
 27	acc, err := sdb.GetAccount(idx)
 28	require.NoError(t, err)
 29	assert.Equal(t, expected, acc.Balance.String())
 30}
 31
 32func TestComputeEffectiveAmounts(t *testing.T) {
 33	dir, err := ioutil.TempDir("", "tmpdb")
 34	require.NoError(t, err)
 35	defer assert.NoError(t, os.RemoveAll(dir))
 36
 37	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
 38		Type: statedb.TypeSynchronizer, NLevels: 32})
 39	assert.NoError(t, err)
 40
 41	set := `
 42		Type: Blockchain
 43		AddToken(1)
 44	
 45		CreateAccountDeposit(0) A: 10
 46		CreateAccountDeposit(0) B: 10
 47		CreateAccountDeposit(1) C: 10
 48		> batchL1
 49		> batchL1
 50		> block
 51	`
 52	chainID := uint16(0)
 53	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
 54	blocks, err := tc.GenerateBlocks(set)
 55	require.NoError(t, err)
 56
 57	config := Config{
 58		NLevels:  32,
 59		MaxFeeTx: 64,
 60		MaxTx:    512,
 61		MaxL1Tx:  16,
 62		ChainID:  chainID,
 63	}
 64	tp := NewTxProcessor(sdb, config)
 65	_, err = tp.ProcessTxs(nil, blocks[0].Rollup.L1UserTxs, nil, nil)
 66	require.NoError(t, err)
 67
 68	tx := common.L1Tx{
 69		FromIdx:       256,
 70		ToIdx:         257,
 71		Amount:        big.NewInt(10),
 72		DepositAmount: big.NewInt(0),
 73		FromEthAddr:   tc.Users["A"].Addr,
 74		UserOrigin:    true,
 75	}
 76	tp.computeEffectiveAmounts(&tx)
 77	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
 78	assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
 79
 80	// expect error due not enough funds
 81	tx = common.L1Tx{
 82		FromIdx:       256,
 83		ToIdx:         257,
 84		Amount:        big.NewInt(11),
 85		DepositAmount: big.NewInt(0),
 86		FromEthAddr:   tc.Users["A"].Addr,
 87		UserOrigin:    true,
 88	}
 89	tp.computeEffectiveAmounts(&tx)
 90	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
 91	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
 92
 93	// expect no-error as there are enough funds in a
 94	// CreateAccountDepositTransfer transction
 95	tx = common.L1Tx{
 96		FromIdx:       0,
 97		ToIdx:         257,
 98		Amount:        big.NewInt(10),
 99		DepositAmount: big.NewInt(10),
100		UserOrigin:    true,
101	}
102	tp.computeEffectiveAmounts(&tx)
103	assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
104	assert.Equal(t, big.NewInt(10), tx.EffectiveAmount)
105
106	// expect error due not enough funds in a CreateAccountDepositTransfer
107	// transction
108	tx = common.L1Tx{
109		FromIdx:       0,
110		ToIdx:         257,
111		Amount:        big.NewInt(11),
112		DepositAmount: big.NewInt(10),
113		UserOrigin:    true,
114	}
115	tp.computeEffectiveAmounts(&tx)
116	assert.Equal(t, big.NewInt(10), tx.EffectiveDepositAmount)
117	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
118
119	// expect error due not same TokenID
120	tx = common.L1Tx{
121		FromIdx:       256,
122		ToIdx:         258,
123		Amount:        big.NewInt(5),
124		DepositAmount: big.NewInt(0),
125		FromEthAddr:   tc.Users["A"].Addr,
126		UserOrigin:    true,
127	}
128	tp.computeEffectiveAmounts(&tx)
129	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
130	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
131
132	// expect error due not same EthAddr
133	tx = common.L1Tx{
134		FromIdx:       256,
135		ToIdx:         257,
136		Amount:        big.NewInt(8),
137		DepositAmount: big.NewInt(0),
138		FromEthAddr:   tc.Users["B"].Addr,
139		UserOrigin:    true,
140	}
141	tp.computeEffectiveAmounts(&tx)
142	assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
143	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
144
145	// expect on TxTypeDepositTransfer EffectiveAmount=0, but
146	// EffectiveDepositAmount!=0, due not enough funds to make the transfer
147	tx = common.L1Tx{
148		FromIdx:       256,
149		ToIdx:         257,
150		Amount:        big.NewInt(20),
151		DepositAmount: big.NewInt(8),
152		FromEthAddr:   tc.Users["A"].Addr,
153		UserOrigin:    true,
154	}
155	tp.computeEffectiveAmounts(&tx)
156	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
157	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
158
159	// expect on TxTypeDepositTransfer EffectiveAmount=0, but
160	// EffectiveDepositAmount!=0, due different EthAddr from FromIdx
161	// address
162	tx = common.L1Tx{
163		FromIdx:       256,
164		ToIdx:         257,
165		Amount:        big.NewInt(8),
166		DepositAmount: big.NewInt(8),
167		FromEthAddr:   tc.Users["B"].Addr,
168		UserOrigin:    true,
169	}
170	tp.computeEffectiveAmounts(&tx)
171	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
172	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
173
174	// CreateAccountDepositTransfer for TokenID=1 when receiver does not
175	// have an account for that TokenID, expect that the
176	// EffectiveDepositAmount=DepositAmount, but EffectiveAmount==0
177	tx = common.L1Tx{
178		FromIdx:       0,
179		ToIdx:         257,
180		Amount:        big.NewInt(8),
181		DepositAmount: big.NewInt(8),
182		FromEthAddr:   tc.Users["A"].Addr,
183		TokenID:       2,
184		UserOrigin:    true,
185		Type:          common.TxTypeCreateAccountDepositTransfer,
186	}
187	tp.computeEffectiveAmounts(&tx)
188	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
189	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
190
191	// DepositTransfer for TokenID=1 when receiver does not have an account
192	// for that TokenID, expect that the
193	// EffectiveDepositAmount=DepositAmount, but EffectiveAmount=0
194	tx = common.L1Tx{
195		FromIdx:       258,
196		ToIdx:         256,
197		Amount:        big.NewInt(8),
198		DepositAmount: big.NewInt(8),
199		FromEthAddr:   tc.Users["C"].Addr,
200		TokenID:       1,
201		UserOrigin:    true,
202		Type:          common.TxTypeDepositTransfer,
203	}
204	tp.computeEffectiveAmounts(&tx)
205	assert.Equal(t, big.NewInt(8), tx.EffectiveDepositAmount)
206	assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
207}
208
209func TestProcessTxsBalances(t *testing.T) {
210	dir, err := ioutil.TempDir("", "tmpdb")
211	require.NoError(t, err)
212	defer assert.NoError(t, os.RemoveAll(dir))
213
214	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
215		Type: statedb.TypeSynchronizer, NLevels: 32})
216	assert.NoError(t, err)
217
218	chainID := uint16(0)
219	// generate test transactions from test.SetBlockchain0 code
220	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
221	blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
222	require.NoError(t, err)
223
224	config := Config{
225		NLevels:  32,
226		MaxFeeTx: 64,
227		MaxTx:    512,
228		MaxL1Tx:  16,
229		ChainID:  chainID,
230	}
231	tp := NewTxProcessor(sdb, config)
232
233	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
234	_, err = tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
235	require.NoError(t, err)
236	assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
237
238	log.Debug("block:0 batch:2")
239	l1UserTxs := []common.L1Tx{}
240	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
241	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
242	require.NoError(t, err)
243	assert.Equal(t, "0", tp.s.MT.Root().BigInt().String())
244
245	log.Debug("block:0 batch:3")
246	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
247	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
248	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
249	require.NoError(t, err)
250	checkBalance(t, tc, sdb, "A", 0, "500")
251	assert.Equal(t, "13644148972047617726265275926674266298636745191961029124811988256139761111521", tp.s.MT.Root().BigInt().String())
252
253	log.Debug("block:0 batch:4")
254	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
255	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
256	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
257	require.NoError(t, err)
258	checkBalance(t, tc, sdb, "A", 0, "500")
259	checkBalance(t, tc, sdb, "A", 1, "500")
260	assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
261
262	log.Debug("block:0 batch:5")
263	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
264	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
265	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
266	require.NoError(t, err)
267	checkBalance(t, tc, sdb, "A", 0, "500")
268	checkBalance(t, tc, sdb, "A", 1, "500")
269	assert.Equal(t, "12433441613247342495680642890662773367605896324555599297255745922589338651261", tp.s.MT.Root().BigInt().String())
270
271	log.Debug("block:0 batch:6")
272	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
273	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
274	_, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
275	require.NoError(t, err)
276	checkBalance(t, tc, sdb, "A", 0, "600")
277	checkBalance(t, tc, sdb, "A", 1, "500")
278	checkBalance(t, tc, sdb, "B", 0, "400")
279	assert.Equal(t, "4191361650490017591061467288209836928064232431729236465872209988325272262963", tp.s.MT.Root().BigInt().String())
280
281	coordIdxs := []common.Idx{261, 262}
282	log.Debug("block:0 batch:7")
283	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
284	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[6].L2Txs)
285	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
286	require.NoError(t, err)
287	checkBalance(t, tc, sdb, "Coord", 0, "10")
288	checkBalance(t, tc, sdb, "Coord", 1, "20")
289	checkBalance(t, tc, sdb, "A", 0, "600")
290	checkBalance(t, tc, sdb, "A", 1, "280")
291	checkBalance(t, tc, sdb, "B", 0, "290")
292	checkBalance(t, tc, sdb, "B", 1, "200")
293	checkBalance(t, tc, sdb, "C", 0, "100")
294	checkBalance(t, tc, sdb, "D", 0, "800")
295	assert.Equal(t, "7614010373759339299470010949167613050707822522530721724565424494781010548240", tp.s.MT.Root().BigInt().String())
296
297	log.Debug("block:0 batch:8")
298	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
299	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[7].L2Txs)
300	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
301	require.NoError(t, err)
302	checkBalance(t, tc, sdb, "Coord", 0, "35")
303	checkBalance(t, tc, sdb, "Coord", 1, "30")
304	checkBalance(t, tc, sdb, "A", 0, "430")
305	checkBalance(t, tc, sdb, "A", 1, "280")
306	checkBalance(t, tc, sdb, "B", 0, "390")
307	checkBalance(t, tc, sdb, "B", 1, "90")
308	checkBalance(t, tc, sdb, "C", 0, "45")
309	checkBalance(t, tc, sdb, "C", 1, "100")
310	checkBalance(t, tc, sdb, "D", 0, "800")
311	assert.Equal(t, "21231789250434471575486264439945776732824482207853465397552873521865656677689", tp.s.MT.Root().BigInt().String())
312
313	coordIdxs = []common.Idx{262}
314	log.Debug("block:1 batch:1")
315	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
316	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
317	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
318	require.NoError(t, err)
319	checkBalance(t, tc, sdb, "Coord", 0, "75")
320	checkBalance(t, tc, sdb, "Coord", 1, "30")
321	checkBalance(t, tc, sdb, "A", 0, "730")
322	checkBalance(t, tc, sdb, "A", 1, "280")
323	checkBalance(t, tc, sdb, "B", 0, "380")
324	checkBalance(t, tc, sdb, "B", 1, "90")
325	checkBalance(t, tc, sdb, "C", 0, "845")
326	checkBalance(t, tc, sdb, "C", 1, "100")
327	checkBalance(t, tc, sdb, "D", 0, "470")
328	assert.Equal(t, "11289313644810782435120113035387729451095637380468777086895109386127538554246", tp.s.MT.Root().BigInt().String())
329
330	coordIdxs = []common.Idx{}
331	log.Debug("block:1 batch:2")
332	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
333	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
334	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
335	require.NoError(t, err)
336	assert.Equal(t, "10342681351319338354912862547249967104198317571995055517008223832276478908482", tp.s.MT.Root().BigInt().String())
337
338	// use Set of PoolL2 txs
339	poolL2Txs, err := tc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow1)
340	assert.NoError(t, err)
341
342	_, err = tp.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
343	require.NoError(t, err)
344	checkBalance(t, tc, sdb, "Coord", 0, "75")
345	checkBalance(t, tc, sdb, "Coord", 1, "30")
346	checkBalance(t, tc, sdb, "A", 0, "510")
347	checkBalance(t, tc, sdb, "A", 1, "170")
348	checkBalance(t, tc, sdb, "B", 0, "480")
349	checkBalance(t, tc, sdb, "B", 1, "190")
350	checkBalance(t, tc, sdb, "C", 0, "845")
351	checkBalance(t, tc, sdb, "C", 1, "100")
352	checkBalance(t, tc, sdb, "D", 0, "360")
353	checkBalance(t, tc, sdb, "F", 0, "100")
354}
355
356func TestProcessTxsSynchronizer(t *testing.T) {
357	dir, err := ioutil.TempDir("", "tmpdb")
358	require.NoError(t, err)
359	defer assert.NoError(t, os.RemoveAll(dir))
360
361	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
362		Type: statedb.TypeSynchronizer, NLevels: 32})
363	assert.NoError(t, err)
364
365	chainID := uint16(0)
366	// generate test transactions from test.SetBlockchain0 code
367	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
368	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
369	require.NoError(t, err)
370
371	assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
372	assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
373	assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
374	assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
375	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
376	assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
377	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
378	assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
379
380	// Coordinator Idx where to send the fees
381	coordIdxs := []common.Idx{256, 257, 258, 259}
382
383	// Idx of user 'A'
384	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
385
386	config := Config{
387		NLevels:  32,
388		MaxFeeTx: 64,
389		MaxTx:    512,
390		MaxL1Tx:  32,
391		ChainID:  chainID,
392	}
393	tp := NewTxProcessor(sdb, config)
394
395	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
396	// to create the Coordinator accounts to receive the fees
397	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
398	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
399	require.NoError(t, err)
400	assert.Equal(t, 4, len(ptOut.CreatedAccounts))
401	assert.Equal(t, 0, len(ptOut.CollectedFees))
402
403	log.Debug("block:0 batch:2")
404	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
405	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
406		blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
407	require.NoError(t, err)
408	assert.Equal(t, 0, len(ptOut.ExitInfos))
409	assert.Equal(t, 31, len(ptOut.CreatedAccounts))
410	assert.Equal(t, 4, len(ptOut.CollectedFees))
411	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
412	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
413	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
414	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
415	acc, err := sdb.GetAccount(idxA1)
416	require.NoError(t, err)
417	assert.Equal(t, "50", acc.Balance.String())
418
419	log.Debug("block:0 batch:3")
420	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
421	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
422	require.NoError(t, err)
423	assert.Equal(t, 0, len(ptOut.ExitInfos))
424	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
425	assert.Equal(t, 4, len(ptOut.CollectedFees))
426	assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
427	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
428	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
429	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
430	acc, err = sdb.GetAccount(idxA1)
431	require.NoError(t, err)
432	assert.Equal(t, "35", acc.Balance.String())
433
434	log.Debug("block:1 batch:1")
435	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
436	// before processing expect l2Txs[0:2].Nonce==0
437	assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
438	assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
439	assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
440
441	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
442	require.NoError(t, err)
443
444	// after processing expect l2Txs[0:2].Nonce!=0 and has expected value
445	assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
446	assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
447	assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
448
449	assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
450	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
451	assert.Equal(t, 4, len(ptOut.CollectedFees))
452	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
453	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
454	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
455	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
456	acc, err = sdb.GetAccount(idxA1)
457	require.NoError(t, err)
458	assert.Equal(t, "57", acc.Balance.String())
459
460	log.Debug("block:1 batch:2")
461	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
462	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
463		blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
464	require.NoError(t, err)
465
466	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
467	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
468	assert.Equal(t, 4, len(ptOut.CollectedFees))
469	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
470	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
471	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
472	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
473	acc, err = sdb.GetAccount(idxA1)
474	assert.NoError(t, err)
475	assert.Equal(t, "77", acc.Balance.String())
476
477	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
478	acc, err = sdb.GetAccount(idxB0)
479	require.NoError(t, err)
480	assert.Equal(t, "51", acc.Balance.String())
481
482	// get balance of Coordinator account for TokenID==0
483	acc, err = sdb.GetAccount(common.Idx(256))
484	require.NoError(t, err)
485	assert.Equal(t, "2", acc.Balance.String())
486}
487
488func TestProcessTxsBatchBuilder(t *testing.T) {
489	dir, err := ioutil.TempDir("", "tmpdb")
490	require.NoError(t, err)
491	defer assert.NoError(t, os.RemoveAll(dir))
492
493	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
494		Type: statedb.TypeBatchBuilder, NLevels: 32})
495	assert.NoError(t, err)
496
497	chainID := uint16(0)
498	// generate test transactions from test.SetBlockchain0 code
499	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
500	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
501	require.NoError(t, err)
502
503	// Coordinator Idx where to send the fees
504	coordIdxs := []common.Idx{256, 257, 258, 259}
505
506	// Idx of user 'A'
507	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
508
509	config := Config{
510		NLevels:  32,
511		MaxFeeTx: 64,
512		MaxTx:    512,
513		MaxL1Tx:  32,
514		ChainID:  chainID,
515	}
516	tp := NewTxProcessor(sdb, config)
517
518	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
519	// to create the Coordinator accounts to receive the fees
520	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
521	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
522	require.NoError(t, err)
523	// expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
524	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
525
526	log.Debug("block:0 batch:2")
527	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
528	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
529	require.NoError(t, err)
530	assert.Equal(t, 0, len(ptOut.ExitInfos))
531	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
532	acc, err := sdb.GetAccount(idxA1)
533	require.NoError(t, err)
534	assert.Equal(t, "50", acc.Balance.String())
535
536	log.Debug("block:0 batch:3")
537	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
538	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
539	require.NoError(t, err)
540	assert.Equal(t, 0, len(ptOut.ExitInfos))
541	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
542	acc, err = sdb.GetAccount(idxA1)
543	require.NoError(t, err)
544	assert.Equal(t, "35", acc.Balance.String())
545
546	log.Debug("block:1 batch:1")
547	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
548	_, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
549	require.NoError(t, err)
550	acc, err = sdb.GetAccount(idxA1)
551	require.NoError(t, err)
552	assert.Equal(t, "57", acc.Balance.String())
553
554	log.Debug("block:1 batch:2")
555	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
556	_, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
557	require.NoError(t, err)
558	acc, err = sdb.GetAccount(idxA1)
559	assert.NoError(t, err)
560	assert.Equal(t, "77", acc.Balance.String())
561
562	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
563	acc, err = sdb.GetAccount(idxB0)
564	require.NoError(t, err)
565	assert.Equal(t, "51", acc.Balance.String())
566
567	// get balance of Coordinator account for TokenID==0
568	acc, err = sdb.GetAccount(common.Idx(256))
569	require.NoError(t, err)
570	assert.Equal(t, common.TokenID(0), acc.TokenID)
571	assert.Equal(t, "2", acc.Balance.String())
572	acc, err = sdb.GetAccount(common.Idx(257))
573	require.NoError(t, err)
574	assert.Equal(t, common.TokenID(1), acc.TokenID)
575	assert.Equal(t, "2", acc.Balance.String())
576
577	assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
578}
579
580func TestProcessTxsRootTestVectors(t *testing.T) {
581	dir, err := ioutil.TempDir("", "tmpdb")
582	require.NoError(t, err)
583	defer assert.NoError(t, os.RemoveAll(dir))
584
585	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
586		Type: statedb.TypeBatchBuilder, NLevels: 32})
587	assert.NoError(t, err)
588
589	// same values than in the js test
590	bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
591	assert.NoError(t, err)
592	l1Txs := []common.L1Tx{
593		{
594			FromIdx:       0,
595			DepositAmount: big.NewInt(16000000),
596			Amount:        big.NewInt(0),
597			TokenID:       1,
598			FromBJJ:       bjj0,
599			FromEthAddr:   ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
600			ToIdx:         0,
601			Type:          common.TxTypeCreateAccountDeposit,
602			UserOrigin:    true,
603		},
604	}
605	l2Txs := []common.PoolL2Tx{
606		{
607			FromIdx: 256,
608			ToIdx:   256,
609			TokenID: 1,
610			Amount:  big.NewInt(1000),
611			Nonce:   0,
612			Fee:     126,
613			Type:    common.TxTypeTransfer,
614		},
615	}
616
617	chainID := uint16(0)
618	config := Config{
619		NLevels:  32,
620		MaxFeeTx: 8,
621		MaxTx:    32,
622		MaxL1Tx:  16,
623		ChainID:  chainID,
624	}
625	tp := NewTxProcessor(sdb, config)
626	_, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
627	require.NoError(t, err)
628	assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
629}
630
631func TestCreateAccountDepositMaxValue(t *testing.T) {
632	dir, err := ioutil.TempDir("", "tmpdb")
633	require.NoError(t, err)
634	defer assert.NoError(t, os.RemoveAll(dir))
635
636	nLevels := 16
637	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
638		Type: statedb.TypeBatchBuilder, NLevels: nLevels})
639	assert.NoError(t, err)
640
641	users := txsets.GenerateJsUsers(t)
642
643	daMaxF40 := common.Float40(0xFFFFFFFFFF)
644	daMaxBI, err := daMaxF40.BigInt()
645	require.NoError(t, err)
646	assert.Equal(t, "343597383670000000000000000000000000000000", daMaxBI.String())
647
648	daMax1F40 := common.Float40(0xFFFFFFFFFE)
649	require.NoError(t, err)
650	daMax1BI, err := daMax1F40.BigInt()
651	require.NoError(t, err)
652	assert.Equal(t, "343597383660000000000000000000000000000000", daMax1BI.String())
653
654	l1Txs := []common.L1Tx{
655		{
656			FromIdx:       0,
657			DepositAmount: daMaxBI,
658			Amount:        big.NewInt(0),
659			TokenID:       1,
660			FromBJJ:       users[0].BJJ.Public().Compress(),
661			FromEthAddr:   users[0].Addr,
662			ToIdx:         0,
663			Type:          common.TxTypeCreateAccountDeposit,
664			UserOrigin:    true,
665		},
666		{
667			FromIdx:       0,
668			DepositAmount: daMax1BI,
669			Amount:        big.NewInt(0),
670			TokenID:       1,
671			FromBJJ:       users[1].BJJ.Public().Compress(),
672			FromEthAddr:   users[1].Addr,
673			ToIdx:         0,
674			Type:          common.TxTypeCreateAccountDeposit,
675			UserOrigin:    true,
676		},
677	}
678
679	chainID := uint16(0)
680	config := Config{
681		NLevels:  uint32(nLevels),
682		MaxTx:    3,
683		MaxL1Tx:  2,
684		MaxFeeTx: 2,
685		ChainID:  chainID,
686	}
687	tp := NewTxProcessor(sdb, config)
688
689	_, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
690	require.NoError(t, err)
691
692	// check balances
693	acc, err := sdb.GetAccount(common.Idx(256))
694	require.NoError(t, err)
695	assert.Equal(t, daMaxBI, acc.Balance)
696	acc, err = sdb.GetAccount(common.Idx(257))
697	require.NoError(t, err)
698	assert.Equal(t, daMax1BI, acc.Balance)
699}
700
701func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
702	dir, err := ioutil.TempDir("", "tmpdb")
703	require.NoError(t, err)
704	defer assert.NoError(t, os.RemoveAll(dir))
705
706	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
707		Type: statedb.TypeBatchBuilder, NLevels: 32})
708	assert.NoError(t, err)
709
710	chainID := uint16(1)
711
712	// generate test transactions from test.SetBlockchain0 code
713	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
714
715	set := `
716		Type: Blockchain
717
718		CreateAccountDeposit(0) A: 200
719
720		> batchL1 // freeze L1User{1}
721
722		CreateAccountCoordinator(0) Coord
723		CreateAccountCoordinator(0) B
724
725		Transfer(0) A-B: 100 (126)
726
727		> batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
728		> block
729	`
730	blocks, err := tc.GenerateBlocks(set)
731	require.NoError(t, err)
732
733	config := Config{
734		NLevels:  32,
735		MaxFeeTx: 64,
736		MaxTx:    512,
737		MaxL1Tx:  16,
738		ChainID:  chainID,
739	}
740	tp := NewTxProcessor(sdb, config)
741	// batch1
742	_, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
743	require.NoError(t, err)
744
745	return tp, tc, blocks
746}
747
748func TestMultipleCoordIdxForTokenID(t *testing.T) {
749	// Check that ProcessTxs always uses the first occurrence of the
750	// CoordIdx for each TokenID
751
752	coordIdxs := []common.Idx{257, 257, 257}
753	tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
754	l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
755	l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
756	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
757	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
758	_, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
759	require.NoError(t, err)
760
761	checkBalanceByIdx(t, tp.s, 256, "90")  // A
762	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
763	checkBalanceByIdx(t, tp.s, 258, "100") // B
764	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
765
766	// reset StateDB values
767	coordIdxs = []common.Idx{259, 257}
768	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
769	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
770	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
771	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
772	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
773	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
774	require.NoError(t, err)
775
776	checkBalanceByIdx(t, tp.s, 256, "90")  // A
777	checkBalanceByIdx(t, tp.s, 257, "0")   // Coord0
778	checkBalanceByIdx(t, tp.s, 258, "100") // B
779	checkBalanceByIdx(t, tp.s, 259, "10")  // Coord0
780
781	// reset StateDB values
782	coordIdxs = []common.Idx{257, 259}
783	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
784	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
785	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
786	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
787	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
788	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
789	require.NoError(t, err)
790
791	checkBalanceByIdx(t, tp.s, 256, "90")  // A
792	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
793	checkBalanceByIdx(t, tp.s, 258, "100") // B
794	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
795}
796
797func TestTwoExits(t *testing.T) {
798	// In the first part we generate a batch with two force exits for the
799	// same account of 20 each.  The txprocessor output should be a single
800	// exitInfo with balance of 40.
801	dir, err := ioutil.TempDir("", "tmpdb")
802	require.NoError(t, err)
803	defer assert.NoError(t, os.RemoveAll(dir))
804
805	sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
806		Type: statedb.TypeSynchronizer, NLevels: 32})
807	assert.NoError(t, err)
808
809	chainID := uint16(1)
810
811	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
812
813	// Two exits for the same account.  The tx processor should output a
814	// single exit with the accumulated exit balance
815	set := `
816		Type: Blockchain
817
818		CreateAccountDeposit(0) A: 100
819
820		> batchL1 // freeze L1User{1}
821		> batchL1 // forge L1User{1}
822
823		ForceExit(0) A: 20
824		ForceExit(0) A: 20
825
826		> batchL1 // freeze L1User{2}
827		> batchL1 // forge L1User{2}
828		> block
829	`
830	blocks, err := tc.GenerateBlocks(set)
831	require.NoError(t, err)
832	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
833	require.NoError(t, err)
834	err = tc.FillBlocksForgedL1UserTxs(blocks)
835	require.NoError(t, err)
836
837	// Sanity check
838	require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
839	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
840
841	config := Config{
842		NLevels:  32,
843		MaxFeeTx: 64,
844		MaxTx:    512,
845		MaxL1Tx:  16,
846		ChainID:  chainID,
847	}
848	tp := NewTxProcessor(sdb, config)
849	ptOuts := []*ProcessTxOutput{}
850	for _, block := range blocks {
851		for _, batch := range block.Rollup.Batches {
852			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
853			require.NoError(t, err)
854			ptOuts = append(ptOuts, ptOut)
855		}
856	}
857
858	assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
859	assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
860	acc, err := sdb.GetAccount(256)
861	require.NoError(t, err)
862	assert.Equal(t, big.NewInt(60), acc.Balance)
863
864	// In the second part we start a fresh statedb and generate a batch
865	// with one force exit for the same account as before.  The txprocessor
866	// output should be a single exitInfo with balance of 40, and the exit
867	// merkle tree proof should be equal to the previous one.
868
869	dir2, err := ioutil.TempDir("", "tmpdb")
870	require.NoError(t, err)
871	defer assert.NoError(t, os.RemoveAll(dir2))
872
873	sdb2, err := statedb.NewStateDB(statedb.Config{Path: dir2, Keep: 128,
874		Type: statedb.TypeSynchronizer, NLevels: 32})
875	assert.NoError(t, err)
876
877	tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
878
879	// Single exit with balance of both exits in previous set.  The exit
880	// root should match.
881	set2 := `
882		Type: Blockchain
883
884		CreateAccountDeposit(0) A: 100
885
886		> batchL1 // freeze L1User{1}
887		> batchL1 // forge L1User{1}
888
889		ForceExit(0) A: 40
890
891		> batchL1 // freeze L1User{2}
892		> batchL1 // forge L1User{2}
893		> block
894	`
895	blocks, err = tc.GenerateBlocks(set2)
896	require.NoError(t, err)
897	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
898	require.NoError(t, err)
899	err = tc.FillBlocksForgedL1UserTxs(blocks)
900	require.NoError(t, err)
901
902	tp = NewTxProcessor(sdb2, config)
903	ptOuts2 := []*ProcessTxOutput{}
904	for _, block := range blocks {
905		for _, batch := range block.Rollup.Batches {
906			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
907			require.NoError(t, err)
908			ptOuts2 = append(ptOuts2, ptOut)
909		}
910	}
911
912	assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
913}