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