arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/txprocessor/txprocessor_test.go
txprocessor/txprocessor_test.goRaw
  1package txprocessor
  2
  3import (
  4	"encoding/binary"
  5	"encoding/hex"
  6	"fmt"
  7	"io/ioutil"
  8	"math/big"
  9	"os"
 10	"testing"
 11
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/hermeznetwork/hermez-node/common"
 14	"github.com/hermeznetwork/hermez-node/db/statedb"
 15	"github.com/hermeznetwork/hermez-node/log"
 16	"github.com/hermeznetwork/hermez-node/test/til"
 17	"github.com/hermeznetwork/hermez-node/test/txsets"
 18	"github.com/stretchr/testify/assert"
 19	"github.com/stretchr/testify/require"
 20)
 21
 22func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
 23	idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
 24	acc, err := sdb.GetAccount(idx)
 25	require.NoError(t, err)
 26	assert.Equal(t, expected, acc.Balance.String())
 27}
 28
 29func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
 30	acc, err := sdb.GetAccount(idx)
 31	require.NoError(t, err)
 32	assert.Equal(t, expected, acc.Balance.String())
 33}
 34
 35func TestComputeEffectiveAmounts(t *testing.T) {
 36	dir, err := ioutil.TempDir("", "tmpdb")
 37	require.NoError(t, err)
 38	defer assert.NoError(t, os.RemoveAll(dir))
 39
 40	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 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, 2, len(ptOut.ExitInfos)) // 2, as previous batch was without L1UserTxs, and has pending the 'ForceExit(1) A: 5'
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(dir, 128, statedb.TypeBatchBuilder, 32)
494	assert.NoError(t, err)
495
496	chainID := uint16(0)
497	// generate test transactions from test.SetBlockchain0 code
498	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
499	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
500	require.NoError(t, err)
501
502	// Coordinator Idx where to send the fees
503	coordIdxs := []common.Idx{256, 257, 258, 259}
504
505	// Idx of user 'A'
506	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
507
508	config := Config{
509		NLevels:  32,
510		MaxFeeTx: 64,
511		MaxTx:    512,
512		MaxL1Tx:  32,
513		ChainID:  chainID,
514	}
515	tp := NewTxProcessor(sdb, config)
516
517	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
518	// to create the Coordinator accounts to receive the fees
519	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
520	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
521	require.NoError(t, err)
522	// expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
523	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
524
525	log.Debug("block:0 batch:2")
526	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
527	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
528	require.NoError(t, err)
529	assert.Equal(t, 0, len(ptOut.ExitInfos))
530	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
531	acc, err := sdb.GetAccount(idxA1)
532	require.NoError(t, err)
533	assert.Equal(t, "50", acc.Balance.String())
534
535	log.Debug("block:0 batch:3")
536	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
537	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
538	require.NoError(t, err)
539	assert.Equal(t, 0, len(ptOut.ExitInfos))
540	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
541	acc, err = sdb.GetAccount(idxA1)
542	require.NoError(t, err)
543	assert.Equal(t, "35", acc.Balance.String())
544
545	log.Debug("block:1 batch:1")
546	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
547	_, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
548	require.NoError(t, err)
549	acc, err = sdb.GetAccount(idxA1)
550	require.NoError(t, err)
551	assert.Equal(t, "57", acc.Balance.String())
552
553	log.Debug("block:1 batch:2")
554	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
555	_, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
556	require.NoError(t, err)
557	acc, err = sdb.GetAccount(idxA1)
558	assert.NoError(t, err)
559	assert.Equal(t, "77", acc.Balance.String())
560
561	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
562	acc, err = sdb.GetAccount(idxB0)
563	require.NoError(t, err)
564	assert.Equal(t, "51", acc.Balance.String())
565
566	// get balance of Coordinator account for TokenID==0
567	acc, err = sdb.GetAccount(common.Idx(256))
568	require.NoError(t, err)
569	assert.Equal(t, common.TokenID(0), acc.TokenID)
570	assert.Equal(t, "2", acc.Balance.String())
571	acc, err = sdb.GetAccount(common.Idx(257))
572	require.NoError(t, err)
573	assert.Equal(t, common.TokenID(1), acc.TokenID)
574	assert.Equal(t, "2", acc.Balance.String())
575
576	assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
577}
578
579func TestProcessTxsRootTestVectors(t *testing.T) {
580	dir, err := ioutil.TempDir("", "tmpdb")
581	require.NoError(t, err)
582	defer assert.NoError(t, os.RemoveAll(dir))
583
584	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
585	assert.NoError(t, err)
586
587	// same values than in the js test
588	bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
589	assert.NoError(t, err)
590	l1Txs := []common.L1Tx{
591		{
592			FromIdx:       0,
593			DepositAmount: big.NewInt(16000000),
594			Amount:        big.NewInt(0),
595			TokenID:       1,
596			FromBJJ:       bjj0,
597			FromEthAddr:   ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
598			ToIdx:         0,
599			Type:          common.TxTypeCreateAccountDeposit,
600			UserOrigin:    true,
601		},
602	}
603	l2Txs := []common.PoolL2Tx{
604		{
605			FromIdx: 256,
606			ToIdx:   256,
607			TokenID: 1,
608			Amount:  big.NewInt(1000),
609			Nonce:   0,
610			Fee:     126,
611			Type:    common.TxTypeTransfer,
612		},
613	}
614
615	chainID := uint16(0)
616	config := Config{
617		NLevels:  32,
618		MaxFeeTx: 8,
619		MaxTx:    32,
620		MaxL1Tx:  16,
621		ChainID:  chainID,
622	}
623	tp := NewTxProcessor(sdb, config)
624	_, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
625	require.NoError(t, err)
626	assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
627}
628
629func TestCreateAccountDepositMaxValue(t *testing.T) {
630	dir, err := ioutil.TempDir("", "tmpdb")
631	require.NoError(t, err)
632	defer assert.NoError(t, os.RemoveAll(dir))
633
634	nLevels := 16
635	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, nLevels)
636	assert.NoError(t, err)
637
638	users := txsets.GenerateJsUsers(t)
639
640	daMaxHex, err := hex.DecodeString("FFFF")
641	require.NoError(t, err)
642	daMaxF16 := common.Float16(binary.BigEndian.Uint16(daMaxHex))
643	daMaxBI := daMaxF16.BigInt()
644	assert.Equal(t, "10235000000000000000000000000000000", daMaxBI.String())
645
646	daMax1Hex, err := hex.DecodeString("FFFE")
647	require.NoError(t, err)
648	daMax1F16 := common.Float16(binary.BigEndian.Uint16(daMax1Hex))
649	daMax1BI := daMax1F16.BigInt()
650	assert.Equal(t, "10225000000000000000000000000000000", daMax1BI.String())
651
652	l1Txs := []common.L1Tx{
653		{
654			FromIdx:       0,
655			DepositAmount: daMaxBI,
656			Amount:        big.NewInt(0),
657			TokenID:       1,
658			FromBJJ:       users[0].BJJ.Public().Compress(),
659			FromEthAddr:   users[0].Addr,
660			ToIdx:         0,
661			Type:          common.TxTypeCreateAccountDeposit,
662			UserOrigin:    true,
663		},
664		{
665			FromIdx:       0,
666			DepositAmount: daMax1BI,
667			Amount:        big.NewInt(0),
668			TokenID:       1,
669			FromBJJ:       users[1].BJJ.Public().Compress(),
670			FromEthAddr:   users[1].Addr,
671			ToIdx:         0,
672			Type:          common.TxTypeCreateAccountDeposit,
673			UserOrigin:    true,
674		},
675	}
676
677	chainID := uint16(0)
678	config := Config{
679		NLevels:  uint32(nLevels),
680		MaxTx:    3,
681		MaxL1Tx:  2,
682		MaxFeeTx: 2,
683		ChainID:  chainID,
684	}
685	tp := NewTxProcessor(sdb, config)
686
687	_, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
688	require.NoError(t, err)
689
690	// check balances
691	acc, err := sdb.GetAccount(common.Idx(256))
692	require.NoError(t, err)
693	assert.Equal(t, daMaxBI, acc.Balance)
694	acc, err = sdb.GetAccount(common.Idx(257))
695	require.NoError(t, err)
696	assert.Equal(t, daMax1BI, acc.Balance)
697}
698
699func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
700	dir, err := ioutil.TempDir("", "tmpdb")
701	require.NoError(t, err)
702	defer assert.NoError(t, os.RemoveAll(dir))
703
704	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
705	assert.NoError(t, err)
706
707	chainID := uint16(1)
708
709	// generate test transactions from test.SetBlockchain0 code
710	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
711
712	set := `
713		Type: Blockchain
714
715		CreateAccountDeposit(0) A: 200
716
717		> batchL1 // freeze L1User{1}
718
719		CreateAccountCoordinator(0) Coord
720		CreateAccountCoordinator(0) B
721
722		Transfer(0) A-B: 100 (126)
723
724		> batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
725		> block
726	`
727	blocks, err := tc.GenerateBlocks(set)
728	require.NoError(t, err)
729
730	config := Config{
731		NLevels:  32,
732		MaxFeeTx: 64,
733		MaxTx:    512,
734		MaxL1Tx:  16,
735		ChainID:  chainID,
736	}
737	tp := NewTxProcessor(sdb, config)
738	// batch1
739	_, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
740	require.NoError(t, err)
741
742	return tp, tc, blocks
743}
744
745func TestMultipleCoordIdxForTokenID(t *testing.T) {
746	// Check that ProcessTxs always uses the first occurrence of the
747	// CoordIdx for each TokenID
748
749	coordIdxs := []common.Idx{257, 257, 257}
750	tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
751	l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
752	l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
753	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
754	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
755	_, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
756	require.NoError(t, err)
757
758	checkBalanceByIdx(t, tp.s, 256, "90")  // A
759	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
760	checkBalanceByIdx(t, tp.s, 258, "100") // B
761	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
762
763	// reset StateDB values
764	coordIdxs = []common.Idx{259, 257}
765	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
766	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
767	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
768	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
769	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
770	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
771	require.NoError(t, err)
772
773	checkBalanceByIdx(t, tp.s, 256, "90")  // A
774	checkBalanceByIdx(t, tp.s, 257, "0")   // Coord0
775	checkBalanceByIdx(t, tp.s, 258, "100") // B
776	checkBalanceByIdx(t, tp.s, 259, "10")  // Coord0
777
778	// reset StateDB values
779	coordIdxs = []common.Idx{257, 259}
780	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
781	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
782	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
783	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
784	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
785	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
786	require.NoError(t, err)
787
788	checkBalanceByIdx(t, tp.s, 256, "90")  // A
789	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
790	checkBalanceByIdx(t, tp.s, 258, "100") // B
791	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
792}
793
794func TestTwoExits(t *testing.T) {
795	dir, err := ioutil.TempDir("", "tmpdb")
796	require.NoError(t, err)
797	defer assert.NoError(t, os.RemoveAll(dir))
798
799	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeSynchronizer, 32)
800	assert.NoError(t, err)
801
802	chainID := uint16(1)
803
804	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
805
806	// Two exits for the same account.  The tx processor should output a
807	// single exit with the accumulated exit balance
808	set := `
809		Type: Blockchain
810
811		CreateAccountDeposit(0) A: 100
812
813		> batchL1 // freeze L1User{1}
814		> batchL1 // forge L1User{1}
815
816		ForceExit(0) A: 20
817		ForceExit(0) A: 20
818
819		> batchL1 // freeze L1User{2}
820		> batchL1 // forge L1User{2}
821		> block
822	`
823	blocks, err := tc.GenerateBlocks(set)
824	require.NoError(t, err)
825	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
826	require.NoError(t, err)
827	err = tc.FillBlocksForgedL1UserTxs(blocks)
828	require.NoError(t, err)
829
830	// Sanity check
831	require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
832	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
833
834	config := Config{
835		NLevels:  32,
836		MaxFeeTx: 64,
837		MaxTx:    512,
838		MaxL1Tx:  16,
839		ChainID:  chainID,
840	}
841	tp := NewTxProcessor(sdb, config)
842	ptOuts := []*ProcessTxOutput{}
843	for _, block := range blocks {
844		for _, batch := range block.Rollup.Batches {
845			// fmt.Printf("Batch %v\n%#v\n", batch.Batch.BatchNum, batch.L1UserTxs)
846			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
847			require.NoError(t, err)
848			fmt.Printf("Exits (batch %v)\n%#v\n", batch.Batch.BatchNum, ptOut.ExitInfos)
849			ptOuts = append(ptOuts, ptOut)
850		}
851	}
852
853	assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
854	assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
855	acc, err := sdb.GetAccount(256)
856	require.NoError(t, err)
857	assert.Equal(t, big.NewInt(60), acc.Balance)
858}