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	"io/ioutil"
  7	"math/big"
  8	"os"
  9	"testing"
 10
 11	ethCommon "github.com/ethereum/go-ethereum/common"
 12	"github.com/hermeznetwork/hermez-node/common"
 13	"github.com/hermeznetwork/hermez-node/db/statedb"
 14	"github.com/hermeznetwork/hermez-node/log"
 15	"github.com/hermeznetwork/hermez-node/test/til"
 16	"github.com/hermeznetwork/hermez-node/test/txsets"
 17	"github.com/stretchr/testify/assert"
 18	"github.com/stretchr/testify/require"
 19)
 20
 21func checkBalance(t *testing.T, tc *til.Context, sdb *statedb.StateDB, username string, tokenid int, expected string) {
 22	idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
 23	acc, err := sdb.GetAccount(idx)
 24	require.NoError(t, err)
 25	assert.Equal(t, expected, acc.Balance.String())
 26}
 27
 28func checkBalanceByIdx(t *testing.T, sdb *statedb.StateDB, idx common.Idx, expected string) {
 29	acc, err := sdb.GetAccount(idx)
 30	require.NoError(t, err)
 31	assert.Equal(t, expected, acc.Balance.String())
 32}
 33
 34func TestComputeEffectiveAmounts(t *testing.T) {
 35	dir, err := ioutil.TempDir("", "tmpdb")
 36	require.NoError(t, err)
 37	defer assert.NoError(t, os.RemoveAll(dir))
 38
 39	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 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(dir, 128, statedb.TypeSynchronizer, 32)
362	assert.NoError(t, err)
363
364	chainID := uint16(0)
365	// generate test transactions from test.SetBlockchain0 code
366	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
367	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
368	require.NoError(t, err)
369
370	assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
371	assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
372	assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
373	assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
374	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
375	assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
376	assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
377	assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
378
379	// Coordinator Idx where to send the fees
380	coordIdxs := []common.Idx{256, 257, 258, 259}
381
382	// Idx of user 'A'
383	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
384
385	config := Config{
386		NLevels:  32,
387		MaxFeeTx: 64,
388		MaxTx:    512,
389		MaxL1Tx:  32,
390		ChainID:  chainID,
391	}
392	tp := NewTxProcessor(sdb, config)
393
394	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
395	// to create the Coordinator accounts to receive the fees
396	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
397	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
398	require.NoError(t, err)
399	assert.Equal(t, 4, len(ptOut.CreatedAccounts))
400	assert.Equal(t, 0, len(ptOut.CollectedFees))
401
402	log.Debug("block:0 batch:2")
403	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
404	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
405		blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
406	require.NoError(t, err)
407	assert.Equal(t, 0, len(ptOut.ExitInfos))
408	assert.Equal(t, 31, len(ptOut.CreatedAccounts))
409	assert.Equal(t, 4, len(ptOut.CollectedFees))
410	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
411	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
412	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
413	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
414	acc, err := sdb.GetAccount(idxA1)
415	require.NoError(t, err)
416	assert.Equal(t, "50", acc.Balance.String())
417
418	log.Debug("block:0 batch:3")
419	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
420	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
421	require.NoError(t, err)
422	assert.Equal(t, 0, len(ptOut.ExitInfos))
423	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
424	assert.Equal(t, 4, len(ptOut.CollectedFees))
425	assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
426	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
427	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
428	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
429	acc, err = sdb.GetAccount(idxA1)
430	require.NoError(t, err)
431	assert.Equal(t, "35", acc.Balance.String())
432
433	log.Debug("block:1 batch:1")
434	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
435	// before processing expect l2Txs[0:2].Nonce==0
436	assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
437	assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
438	assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
439
440	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
441	require.NoError(t, err)
442
443	// after processing expect l2Txs[0:2].Nonce!=0 and has expected value
444	assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
445	assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
446	assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
447
448	assert.Equal(t, 4, len(ptOut.ExitInfos)) // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
449	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
450	assert.Equal(t, 4, len(ptOut.CollectedFees))
451	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
452	assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
453	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
454	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
455	acc, err = sdb.GetAccount(idxA1)
456	require.NoError(t, err)
457	assert.Equal(t, "57", acc.Balance.String())
458
459	log.Debug("block:1 batch:2")
460	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
461	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
462		blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
463	require.NoError(t, err)
464
465	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
466	assert.Equal(t, 1, len(ptOut.CreatedAccounts))
467	assert.Equal(t, 4, len(ptOut.CollectedFees))
468	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
469	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
470	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
471	assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
472	acc, err = sdb.GetAccount(idxA1)
473	assert.NoError(t, err)
474	assert.Equal(t, "77", acc.Balance.String())
475
476	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
477	acc, err = sdb.GetAccount(idxB0)
478	require.NoError(t, err)
479	assert.Equal(t, "51", acc.Balance.String())
480
481	// get balance of Coordinator account for TokenID==0
482	acc, err = sdb.GetAccount(common.Idx(256))
483	require.NoError(t, err)
484	assert.Equal(t, "2", acc.Balance.String())
485}
486
487func TestProcessTxsBatchBuilder(t *testing.T) {
488	dir, err := ioutil.TempDir("", "tmpdb")
489	require.NoError(t, err)
490	defer assert.NoError(t, os.RemoveAll(dir))
491
492	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
493	assert.NoError(t, err)
494
495	chainID := uint16(0)
496	// generate test transactions from test.SetBlockchain0 code
497	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
498	blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
499	require.NoError(t, err)
500
501	// Coordinator Idx where to send the fees
502	coordIdxs := []common.Idx{256, 257, 258, 259}
503
504	// Idx of user 'A'
505	idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
506
507	config := Config{
508		NLevels:  32,
509		MaxFeeTx: 64,
510		MaxTx:    512,
511		MaxL1Tx:  32,
512		ChainID:  chainID,
513	}
514	tp := NewTxProcessor(sdb, config)
515
516	// Process the 1st batch, which contains the L1CoordinatorTxs necessary
517	// to create the Coordinator accounts to receive the fees
518	log.Debug("block:0 batch:1, only L1CoordinatorTxs")
519	ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
520	require.NoError(t, err)
521	// expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
522	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
523
524	log.Debug("block:0 batch:2")
525	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
526	ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs, blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
527	require.NoError(t, err)
528	assert.Equal(t, 0, len(ptOut.ExitInfos))
529	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
530	acc, err := sdb.GetAccount(idxA1)
531	require.NoError(t, err)
532	assert.Equal(t, "50", acc.Balance.String())
533
534	log.Debug("block:0 batch:3")
535	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
536	ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
537	require.NoError(t, err)
538	assert.Equal(t, 0, len(ptOut.ExitInfos))
539	assert.Equal(t, 0, len(ptOut.CreatedAccounts))
540	acc, err = sdb.GetAccount(idxA1)
541	require.NoError(t, err)
542	assert.Equal(t, "35", acc.Balance.String())
543
544	log.Debug("block:1 batch:1")
545	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
546	_, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
547	require.NoError(t, err)
548	acc, err = sdb.GetAccount(idxA1)
549	require.NoError(t, err)
550	assert.Equal(t, "57", acc.Balance.String())
551
552	log.Debug("block:1 batch:2")
553	l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
554	_, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
555	require.NoError(t, err)
556	acc, err = sdb.GetAccount(idxA1)
557	assert.NoError(t, err)
558	assert.Equal(t, "77", acc.Balance.String())
559
560	idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
561	acc, err = sdb.GetAccount(idxB0)
562	require.NoError(t, err)
563	assert.Equal(t, "51", acc.Balance.String())
564
565	// get balance of Coordinator account for TokenID==0
566	acc, err = sdb.GetAccount(common.Idx(256))
567	require.NoError(t, err)
568	assert.Equal(t, common.TokenID(0), acc.TokenID)
569	assert.Equal(t, "2", acc.Balance.String())
570	acc, err = sdb.GetAccount(common.Idx(257))
571	require.NoError(t, err)
572	assert.Equal(t, common.TokenID(1), acc.TokenID)
573	assert.Equal(t, "2", acc.Balance.String())
574
575	assert.Equal(t, "18894163991492573893706613133132363559300580460789469708968288074813925659539", sdb.MT.Root().BigInt().String())
576}
577
578func TestProcessTxsRootTestVectors(t *testing.T) {
579	dir, err := ioutil.TempDir("", "tmpdb")
580	require.NoError(t, err)
581	defer assert.NoError(t, os.RemoveAll(dir))
582
583	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
584	assert.NoError(t, err)
585
586	// same values than in the js test
587	bjj0, err := common.BJJFromStringWithChecksum("21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
588	assert.NoError(t, err)
589	l1Txs := []common.L1Tx{
590		{
591			FromIdx:       0,
592			DepositAmount: big.NewInt(16000000),
593			Amount:        big.NewInt(0),
594			TokenID:       1,
595			FromBJJ:       bjj0,
596			FromEthAddr:   ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
597			ToIdx:         0,
598			Type:          common.TxTypeCreateAccountDeposit,
599			UserOrigin:    true,
600		},
601	}
602	l2Txs := []common.PoolL2Tx{
603		{
604			FromIdx: 256,
605			ToIdx:   256,
606			TokenID: 1,
607			Amount:  big.NewInt(1000),
608			Nonce:   0,
609			Fee:     126,
610			Type:    common.TxTypeTransfer,
611		},
612	}
613
614	chainID := uint16(0)
615	config := Config{
616		NLevels:  32,
617		MaxFeeTx: 8,
618		MaxTx:    32,
619		MaxL1Tx:  16,
620		ChainID:  chainID,
621	}
622	tp := NewTxProcessor(sdb, config)
623	_, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
624	require.NoError(t, err)
625	assert.Equal(t, "9827704113668630072730115158977131501210702363656902211840117643154933433410", sdb.MT.Root().BigInt().String())
626}
627
628func TestCreateAccountDepositMaxValue(t *testing.T) {
629	dir, err := ioutil.TempDir("", "tmpdb")
630	require.NoError(t, err)
631	defer assert.NoError(t, os.RemoveAll(dir))
632
633	nLevels := 16
634	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, nLevels)
635	assert.NoError(t, err)
636
637	users := txsets.GenerateJsUsers(t)
638
639	daMaxHex, err := hex.DecodeString("FFFF")
640	require.NoError(t, err)
641	daMaxF16 := common.Float16(binary.BigEndian.Uint16(daMaxHex))
642	daMaxBI := daMaxF16.BigInt()
643	assert.Equal(t, "10235000000000000000000000000000000", daMaxBI.String())
644
645	daMax1Hex, err := hex.DecodeString("FFFE")
646	require.NoError(t, err)
647	daMax1F16 := common.Float16(binary.BigEndian.Uint16(daMax1Hex))
648	daMax1BI := daMax1F16.BigInt()
649	assert.Equal(t, "10225000000000000000000000000000000", daMax1BI.String())
650
651	l1Txs := []common.L1Tx{
652		{
653			FromIdx:       0,
654			DepositAmount: daMaxBI,
655			Amount:        big.NewInt(0),
656			TokenID:       1,
657			FromBJJ:       users[0].BJJ.Public().Compress(),
658			FromEthAddr:   users[0].Addr,
659			ToIdx:         0,
660			Type:          common.TxTypeCreateAccountDeposit,
661			UserOrigin:    true,
662		},
663		{
664			FromIdx:       0,
665			DepositAmount: daMax1BI,
666			Amount:        big.NewInt(0),
667			TokenID:       1,
668			FromBJJ:       users[1].BJJ.Public().Compress(),
669			FromEthAddr:   users[1].Addr,
670			ToIdx:         0,
671			Type:          common.TxTypeCreateAccountDeposit,
672			UserOrigin:    true,
673		},
674	}
675
676	chainID := uint16(0)
677	config := Config{
678		NLevels:  uint32(nLevels),
679		MaxTx:    3,
680		MaxL1Tx:  2,
681		MaxFeeTx: 2,
682		ChainID:  chainID,
683	}
684	tp := NewTxProcessor(sdb, config)
685
686	_, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
687	require.NoError(t, err)
688
689	// check balances
690	acc, err := sdb.GetAccount(common.Idx(256))
691	require.NoError(t, err)
692	assert.Equal(t, daMaxBI, acc.Balance)
693	acc, err = sdb.GetAccount(common.Idx(257))
694	require.NoError(t, err)
695	assert.Equal(t, daMax1BI, acc.Balance)
696}
697
698func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context, []common.BlockData) {
699	dir, err := ioutil.TempDir("", "tmpdb")
700	require.NoError(t, err)
701	defer assert.NoError(t, os.RemoveAll(dir))
702
703	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeBatchBuilder, 32)
704	assert.NoError(t, err)
705
706	chainID := uint16(1)
707
708	// generate test transactions from test.SetBlockchain0 code
709	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
710
711	set := `
712		Type: Blockchain
713
714		CreateAccountDeposit(0) A: 200
715
716		> batchL1 // freeze L1User{1}
717
718		CreateAccountCoordinator(0) Coord
719		CreateAccountCoordinator(0) B
720
721		Transfer(0) A-B: 100 (126)
722
723		> batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
724		> block
725	`
726	blocks, err := tc.GenerateBlocks(set)
727	require.NoError(t, err)
728
729	config := Config{
730		NLevels:  32,
731		MaxFeeTx: 64,
732		MaxTx:    512,
733		MaxL1Tx:  16,
734		ChainID:  chainID,
735	}
736	tp := NewTxProcessor(sdb, config)
737	// batch1
738	_, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
739	require.NoError(t, err)
740
741	return tp, tc, blocks
742}
743
744func TestMultipleCoordIdxForTokenID(t *testing.T) {
745	// Check that ProcessTxs always uses the first occurrence of the
746	// CoordIdx for each TokenID
747
748	coordIdxs := []common.Idx{257, 257, 257}
749	tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
750	l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
751	l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
752	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
753	l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
754	_, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
755	require.NoError(t, err)
756
757	checkBalanceByIdx(t, tp.s, 256, "90")  // A
758	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
759	checkBalanceByIdx(t, tp.s, 258, "100") // B
760	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
761
762	// reset StateDB values
763	coordIdxs = []common.Idx{259, 257}
764	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
765	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
766	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
767	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
768	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
769	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
770	require.NoError(t, err)
771
772	checkBalanceByIdx(t, tp.s, 256, "90")  // A
773	checkBalanceByIdx(t, tp.s, 257, "0")   // Coord0
774	checkBalanceByIdx(t, tp.s, 258, "100") // B
775	checkBalanceByIdx(t, tp.s, 259, "10")  // Coord0
776
777	// reset StateDB values
778	coordIdxs = []common.Idx{257, 259}
779	tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
780	l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
781	l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
782	l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
783	l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
784	_, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
785	require.NoError(t, err)
786
787	checkBalanceByIdx(t, tp.s, 256, "90")  // A
788	checkBalanceByIdx(t, tp.s, 257, "10")  // Coord0
789	checkBalanceByIdx(t, tp.s, 258, "100") // B
790	checkBalanceByIdx(t, tp.s, 259, "0")   // Coord0
791}
792
793func TestTwoExits(t *testing.T) {
794	// In the first part we generate a batch with two force exits for the
795	// same account of 20 each.  The txprocessor output should be a single
796	// exitInfo with balance of 40.
797	dir, err := ioutil.TempDir("", "tmpdb")
798	require.NoError(t, err)
799	defer assert.NoError(t, os.RemoveAll(dir))
800
801	sdb, err := statedb.NewStateDB(dir, 128, statedb.TypeSynchronizer, 32)
802	assert.NoError(t, err)
803
804	chainID := uint16(1)
805
806	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
807
808	// Two exits for the same account.  The tx processor should output a
809	// single exit with the accumulated exit balance
810	set := `
811		Type: Blockchain
812
813		CreateAccountDeposit(0) A: 100
814
815		> batchL1 // freeze L1User{1}
816		> batchL1 // forge L1User{1}
817
818		ForceExit(0) A: 20
819		ForceExit(0) A: 20
820
821		> batchL1 // freeze L1User{2}
822		> batchL1 // forge L1User{2}
823		> block
824	`
825	blocks, err := tc.GenerateBlocks(set)
826	require.NoError(t, err)
827	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
828	require.NoError(t, err)
829	err = tc.FillBlocksForgedL1UserTxs(blocks)
830	require.NoError(t, err)
831
832	// Sanity check
833	require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
834	require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
835
836	config := Config{
837		NLevels:  32,
838		MaxFeeTx: 64,
839		MaxTx:    512,
840		MaxL1Tx:  16,
841		ChainID:  chainID,
842	}
843	tp := NewTxProcessor(sdb, config)
844	ptOuts := []*ProcessTxOutput{}
845	for _, block := range blocks {
846		for _, batch := range block.Rollup.Batches {
847			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
848			require.NoError(t, err)
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
859	// In the second part we start a fresh statedb and generate a batch
860	// with one force exit for the same account as before.  The txprocessor
861	// output should be a single exitInfo with balance of 40, and the exit
862	// merkle tree proof should be equal to the previous one.
863
864	dir2, err := ioutil.TempDir("", "tmpdb")
865	require.NoError(t, err)
866	defer assert.NoError(t, os.RemoveAll(dir2))
867
868	sdb2, err := statedb.NewStateDB(dir2, 128, statedb.TypeSynchronizer, 32)
869	assert.NoError(t, err)
870
871	tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
872
873	// Single exit with balance of both exits in previous set.  The exit
874	// root should match.
875	set2 := `
876		Type: Blockchain
877
878		CreateAccountDeposit(0) A: 100
879
880		> batchL1 // freeze L1User{1}
881		> batchL1 // forge L1User{1}
882
883		ForceExit(0) A: 40
884
885		> batchL1 // freeze L1User{2}
886		> batchL1 // forge L1User{2}
887		> block
888	`
889	blocks, err = tc.GenerateBlocks(set2)
890	require.NoError(t, err)
891	err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
892	require.NoError(t, err)
893	err = tc.FillBlocksForgedL1UserTxs(blocks)
894	require.NoError(t, err)
895
896	tp = NewTxProcessor(sdb2, config)
897	ptOuts2 := []*ProcessTxOutput{}
898	for _, block := range blocks {
899		for _, batch := range block.Rollup.Batches {
900			ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
901			require.NoError(t, err)
902			ptOuts2 = append(ptOuts2, ptOut)
903		}
904	}
905
906	assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
907}