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