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,
21 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.SetBlockchainMinimumFlow0 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,
254 "10303926118213025243660668481827257778714122989909761705455084995854999537039",
255 tp.s.MT.Root().BigInt().String())
256
257 log.Debug("block:0 batch:4")
258 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
259 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[3].L2Txs)
260 _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[3].L1CoordinatorTxs, l2Txs)
261 require.NoError(t, err)
262 checkBalance(t, tc, sdb, "A", 0, "500")
263 checkBalance(t, tc, sdb, "A", 1, "500")
264 assert.Equal(t,
265 "8530501758307821623834726627056947648600328521261384179220598288701741436285",
266 tp.s.MT.Root().BigInt().String())
267
268 log.Debug("block:0 batch:5")
269 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
270 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[4].L2Txs)
271 _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[4].L1CoordinatorTxs, l2Txs)
272 require.NoError(t, err)
273 checkBalance(t, tc, sdb, "A", 0, "500")
274 checkBalance(t, tc, sdb, "A", 1, "500")
275 assert.Equal(t,
276 "8530501758307821623834726627056947648600328521261384179220598288701741436285",
277 tp.s.MT.Root().BigInt().String())
278
279 log.Debug("block:0 batch:6")
280 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
281 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[5].L2Txs)
282 _, err = tp.ProcessTxs(nil, l1UserTxs, blocks[0].Rollup.Batches[5].L1CoordinatorTxs, l2Txs)
283 require.NoError(t, err)
284 checkBalance(t, tc, sdb, "A", 0, "600")
285 checkBalance(t, tc, sdb, "A", 1, "500")
286 checkBalance(t, tc, sdb, "B", 0, "400")
287 assert.Equal(t,
288 "9061858435528794221929846392270405504056106238451760714188625065949729889651",
289 tp.s.MT.Root().BigInt().String())
290
291 coordIdxs := []common.Idx{261, 263}
292 log.Debug("block:0 batch:7")
293 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
294 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[6].L2Txs)
295 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[6].L1CoordinatorTxs, l2Txs)
296 require.NoError(t, err)
297 checkBalance(t, tc, sdb, "Coord", 0, "10")
298 checkBalance(t, tc, sdb, "Coord", 1, "20")
299 checkBalance(t, tc, sdb, "A", 0, "600")
300 checkBalance(t, tc, sdb, "A", 1, "280")
301 checkBalance(t, tc, sdb, "B", 0, "290")
302 checkBalance(t, tc, sdb, "B", 1, "200")
303 checkBalance(t, tc, sdb, "C", 0, "100")
304 checkBalance(t, tc, sdb, "D", 0, "800")
305 assert.Equal(t,
306 "4392049343656836675348565048374261353937130287163762821533580216441778455298",
307 tp.s.MT.Root().BigInt().String())
308
309 log.Debug("block:0 batch:8")
310 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
311 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[7].L2Txs)
312 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Rollup.Batches[7].L1CoordinatorTxs, l2Txs)
313 require.NoError(t, err)
314 checkBalance(t, tc, sdb, "Coord", 0, "35")
315 checkBalance(t, tc, sdb, "Coord", 1, "30")
316 checkBalance(t, tc, sdb, "A", 0, "430")
317 checkBalance(t, tc, sdb, "A", 1, "280")
318 checkBalance(t, tc, sdb, "B", 0, "390")
319 checkBalance(t, tc, sdb, "B", 1, "90")
320 checkBalance(t, tc, sdb, "C", 0, "45")
321 checkBalance(t, tc, sdb, "C", 1, "100")
322 checkBalance(t, tc, sdb, "D", 0, "800")
323 assert.Equal(t,
324 "8905191229562583213069132470917469035834300549892959854483573322676101624713",
325 tp.s.MT.Root().BigInt().String())
326
327 coordIdxs = []common.Idx{262}
328 log.Debug("block:1 batch:1")
329 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
330 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
331 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
332 require.NoError(t, err)
333 checkBalance(t, tc, sdb, "Coord", 1, "30")
334 checkBalance(t, tc, sdb, "Coord", 0, "35")
335 checkBalance(t, tc, sdb, "A", 0, "730")
336 checkBalance(t, tc, sdb, "A", 1, "280")
337 checkBalance(t, tc, sdb, "B", 0, "380")
338 checkBalance(t, tc, sdb, "B", 1, "90")
339 checkBalance(t, tc, sdb, "C", 0, "845")
340 checkBalance(t, tc, sdb, "C", 1, "100")
341 checkBalance(t, tc, sdb, "D", 0, "470")
342 assert.Equal(t,
343 "12063160053709941400160547588624831667157042937323422396363359123696668555050",
344 tp.s.MT.Root().BigInt().String())
345
346 coordIdxs = []common.Idx{}
347 log.Debug("block:1 batch:2")
348 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[1].Batch.ForgeL1TxsNum])
349 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
350 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
351 require.NoError(t, err)
352 assert.Equal(t,
353 "20375835796927052406196249140510136992262283055544831070430919054949353249481",
354 tp.s.MT.Root().BigInt().String())
355
356 // use Set of PoolL2 txs
357 poolL2Txs, err := tc.GeneratePoolL2Txs(txsets.SetPoolL2MinimumFlow1)
358 assert.NoError(t, err)
359
360 _, err = tp.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
361 require.NoError(t, err)
362 checkBalance(t, tc, sdb, "Coord", 1, "30")
363 checkBalance(t, tc, sdb, "Coord", 0, "35")
364 checkBalance(t, tc, sdb, "A", 0, "510")
365 checkBalance(t, tc, sdb, "A", 1, "170")
366 checkBalance(t, tc, sdb, "B", 0, "480")
367 checkBalance(t, tc, sdb, "B", 1, "190")
368 checkBalance(t, tc, sdb, "C", 0, "845")
369 checkBalance(t, tc, sdb, "C", 1, "100")
370 checkBalance(t, tc, sdb, "D", 0, "360")
371 checkBalance(t, tc, sdb, "F", 0, "100")
372}
373
374func TestProcessTxsSynchronizer(t *testing.T) {
375 dir, err := ioutil.TempDir("", "tmpdb")
376 require.NoError(t, err)
377 defer assert.NoError(t, os.RemoveAll(dir))
378
379 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
380 Type: statedb.TypeSynchronizer, NLevels: 32})
381 assert.NoError(t, err)
382
383 chainID := uint16(0)
384 // generate test transactions from test.SetBlockchain0 code
385 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
386 blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
387 require.NoError(t, err)
388
389 assert.Equal(t, 31, len(blocks[0].Rollup.L1UserTxs))
390 assert.Equal(t, 4, len(blocks[0].Rollup.Batches[0].L1CoordinatorTxs))
391 assert.Equal(t, 0, len(blocks[0].Rollup.Batches[1].L1CoordinatorTxs))
392 assert.Equal(t, 22, len(blocks[0].Rollup.Batches[2].L2Txs))
393 assert.Equal(t, 1, len(blocks[1].Rollup.Batches[0].L1CoordinatorTxs))
394 assert.Equal(t, 62, len(blocks[1].Rollup.Batches[0].L2Txs))
395 assert.Equal(t, 1, len(blocks[1].Rollup.Batches[1].L1CoordinatorTxs))
396 assert.Equal(t, 8, len(blocks[1].Rollup.Batches[1].L2Txs))
397
398 // Coordinator Idx where to send the fees
399 coordIdxs := []common.Idx{256, 257, 258, 259}
400
401 // Idx of user 'A'
402 idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
403
404 config := Config{
405 NLevels: 32,
406 MaxFeeTx: 64,
407 MaxTx: 512,
408 MaxL1Tx: 32,
409 ChainID: chainID,
410 }
411 tp := NewTxProcessor(sdb, config)
412
413 // Process the 1st batch, which contains the L1CoordinatorTxs necessary
414 // to create the Coordinator accounts to receive the fees
415 log.Debug("block:0 batch:1, only L1CoordinatorTxs")
416 ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
417 require.NoError(t, err)
418 assert.Equal(t, 4, len(ptOut.CreatedAccounts))
419 assert.Equal(t, 0, len(ptOut.CollectedFees))
420
421 log.Debug("block:0 batch:2")
422 l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
423 ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
424 blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
425 require.NoError(t, err)
426 assert.Equal(t, 0, len(ptOut.ExitInfos))
427 assert.Equal(t, 31, len(ptOut.CreatedAccounts))
428 assert.Equal(t, 4, len(ptOut.CollectedFees))
429 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
430 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
431 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
432 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
433 acc, err := sdb.GetAccount(idxA1)
434 require.NoError(t, err)
435 assert.Equal(t, "50", acc.Balance.String())
436
437 log.Debug("block:0 batch:3")
438 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
439 ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
440 require.NoError(t, err)
441 assert.Equal(t, 0, len(ptOut.ExitInfos))
442 assert.Equal(t, 0, len(ptOut.CreatedAccounts))
443 assert.Equal(t, 4, len(ptOut.CollectedFees))
444 assert.Equal(t, "2", ptOut.CollectedFees[common.TokenID(0)].String())
445 assert.Equal(t, "1", ptOut.CollectedFees[common.TokenID(1)].String())
446 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
447 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
448 acc, err = sdb.GetAccount(idxA1)
449 require.NoError(t, err)
450 assert.Equal(t, "35", acc.Balance.String())
451
452 log.Debug("block:1 batch:1")
453 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
454 // before processing expect l2Txs[0:2].Nonce==0
455 assert.Equal(t, common.Nonce(0), l2Txs[0].Nonce)
456 assert.Equal(t, common.Nonce(0), l2Txs[1].Nonce)
457 assert.Equal(t, common.Nonce(0), l2Txs[2].Nonce)
458
459 ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
460 require.NoError(t, err)
461
462 // after processing expect l2Txs[0:2].Nonce!=0 and has expected value
463 assert.Equal(t, common.Nonce(5), l2Txs[0].Nonce)
464 assert.Equal(t, common.Nonce(6), l2Txs[1].Nonce)
465 assert.Equal(t, common.Nonce(7), l2Txs[2].Nonce)
466 // the 'ForceExit(1)' is not computed yet, as the batch is without L1UserTxs
467 assert.Equal(t, 4, len(ptOut.ExitInfos))
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, "1", 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 require.NoError(t, err)
476 assert.Equal(t, "57", acc.Balance.String())
477
478 log.Debug("block:1 batch:2")
479 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
480 ptOut, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
481 blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
482 require.NoError(t, err)
483 // 1, as previous batch was without L1UserTxs, and has pending the
484 // 'ForceExit(1) A: 5', and the 2 exit transactions get grouped under 1
485 // ExitInfo
486 assert.Equal(t, 1, len(ptOut.ExitInfos))
487 assert.Equal(t, 1, len(ptOut.CreatedAccounts))
488 assert.Equal(t, 4, len(ptOut.CollectedFees))
489 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(0)].String())
490 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(1)].String())
491 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(2)].String())
492 assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
493 acc, err = sdb.GetAccount(idxA1)
494 assert.NoError(t, err)
495 assert.Equal(t, "77", acc.Balance.String())
496
497 idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
498 acc, err = sdb.GetAccount(idxB0)
499 require.NoError(t, err)
500 assert.Equal(t, "51", acc.Balance.String())
501
502 // get balance of Coordinator account for TokenID==0
503 acc, err = sdb.GetAccount(common.Idx(256))
504 require.NoError(t, err)
505 assert.Equal(t, "2", acc.Balance.String())
506}
507
508func TestProcessTxsBatchBuilder(t *testing.T) {
509 dir, err := ioutil.TempDir("", "tmpdb")
510 require.NoError(t, err)
511 defer assert.NoError(t, os.RemoveAll(dir))
512
513 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
514 Type: statedb.TypeBatchBuilder, NLevels: 32})
515 assert.NoError(t, err)
516
517 chainID := uint16(0)
518 // generate test transactions from test.SetBlockchain0 code
519 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
520 blocks, err := tc.GenerateBlocks(txsets.SetBlockchain0)
521 require.NoError(t, err)
522
523 // Coordinator Idx where to send the fees
524 coordIdxs := []common.Idx{256, 257, 258, 259}
525
526 // Idx of user 'A'
527 idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
528
529 config := Config{
530 NLevels: 32,
531 MaxFeeTx: 64,
532 MaxTx: 512,
533 MaxL1Tx: 32,
534 ChainID: chainID,
535 }
536 tp := NewTxProcessor(sdb, config)
537
538 // Process the 1st batch, which contains the L1CoordinatorTxs necessary
539 // to create the Coordinator accounts to receive the fees
540 log.Debug("block:0 batch:1, only L1CoordinatorTxs")
541 ptOut, err := tp.ProcessTxs(nil, nil, blocks[0].Rollup.Batches[0].L1CoordinatorTxs, nil)
542 require.NoError(t, err)
543 // expect 0 at CreatedAccount, as is only computed when StateDB.Type==TypeSynchronizer
544 assert.Equal(t, 0, len(ptOut.CreatedAccounts))
545
546 log.Debug("block:0 batch:2")
547 l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
548 ptOut, err = tp.ProcessTxs(coordIdxs, blocks[0].Rollup.L1UserTxs,
549 blocks[0].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
550 require.NoError(t, err)
551 assert.Equal(t, 0, len(ptOut.ExitInfos))
552 assert.Equal(t, 0, len(ptOut.CreatedAccounts))
553 acc, err := sdb.GetAccount(idxA1)
554 require.NoError(t, err)
555 assert.Equal(t, "50", acc.Balance.String())
556
557 log.Debug("block:0 batch:3")
558 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[2].L2Txs)
559 ptOut, err = tp.ProcessTxs(coordIdxs, nil, blocks[0].Rollup.Batches[2].L1CoordinatorTxs, l2Txs)
560 require.NoError(t, err)
561 assert.Equal(t, 0, len(ptOut.ExitInfos))
562 assert.Equal(t, 0, len(ptOut.CreatedAccounts))
563 acc, err = sdb.GetAccount(idxA1)
564 require.NoError(t, err)
565 assert.Equal(t, "35", acc.Balance.String())
566
567 log.Debug("block:1 batch:1")
568 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[0].L2Txs)
569 _, err = tp.ProcessTxs(coordIdxs, nil, blocks[1].Rollup.Batches[0].L1CoordinatorTxs, l2Txs)
570 require.NoError(t, err)
571 acc, err = sdb.GetAccount(idxA1)
572 require.NoError(t, err)
573 assert.Equal(t, "57", acc.Balance.String())
574
575 log.Debug("block:1 batch:2")
576 l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Rollup.Batches[1].L2Txs)
577 _, err = tp.ProcessTxs(coordIdxs, blocks[1].Rollup.L1UserTxs,
578 blocks[1].Rollup.Batches[1].L1CoordinatorTxs, l2Txs)
579 require.NoError(t, err)
580 acc, err = sdb.GetAccount(idxA1)
581 assert.NoError(t, err)
582 assert.Equal(t, "77", acc.Balance.String())
583
584 idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
585 acc, err = sdb.GetAccount(idxB0)
586 require.NoError(t, err)
587 assert.Equal(t, "51", acc.Balance.String())
588
589 // get balance of Coordinator account for TokenID==0
590 acc, err = sdb.GetAccount(common.Idx(256))
591 require.NoError(t, err)
592 assert.Equal(t, common.TokenID(0), acc.TokenID)
593 assert.Equal(t, "2", acc.Balance.String())
594 acc, err = sdb.GetAccount(common.Idx(257))
595 require.NoError(t, err)
596 assert.Equal(t, common.TokenID(1), acc.TokenID)
597 assert.Equal(t, "2", acc.Balance.String())
598
599 assert.Equal(t,
600 "18702154359941252155463263732782081721632595649781775986280568467618682348921",
601 sdb.MT.Root().BigInt().String())
602}
603
604func TestProcessTxsRootTestVectors(t *testing.T) {
605 dir, err := ioutil.TempDir("", "tmpdb")
606 require.NoError(t, err)
607 defer assert.NoError(t, os.RemoveAll(dir))
608
609 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
610 Type: statedb.TypeBatchBuilder, NLevels: 32})
611 assert.NoError(t, err)
612
613 // same values than in the js test
614 bjj0, err := common.BJJFromStringWithChecksum(
615 "21b0a1688b37f77b1d1d5539ec3b826db5ac78b2513f574a04c50a7d4f8246d7")
616 assert.NoError(t, err)
617 l1Txs := []common.L1Tx{
618 {
619 FromIdx: 0,
620 DepositAmount: big.NewInt(16000000),
621 Amount: big.NewInt(0),
622 TokenID: 1,
623 FromBJJ: bjj0,
624 FromEthAddr: ethCommon.HexToAddress("0x7e5f4552091a69125d5dfcb7b8c2659029395bdf"),
625 ToIdx: 0,
626 Type: common.TxTypeCreateAccountDeposit,
627 UserOrigin: true,
628 },
629 }
630 l2Txs := []common.PoolL2Tx{
631 {
632 FromIdx: 256,
633 ToIdx: 256,
634 TokenID: 1,
635 Amount: big.NewInt(1000),
636 Nonce: 0,
637 Fee: 126,
638 Type: common.TxTypeTransfer,
639 },
640 }
641
642 chainID := uint16(0)
643 config := Config{
644 NLevels: 32,
645 MaxFeeTx: 8,
646 MaxTx: 32,
647 MaxL1Tx: 16,
648 ChainID: chainID,
649 }
650 tp := NewTxProcessor(sdb, config)
651 _, err = tp.ProcessTxs(nil, l1Txs, nil, l2Txs)
652 require.NoError(t, err)
653 assert.Equal(t,
654 "16181420716631932805604732887923905079487577323947343079740042260791593140221",
655 sdb.MT.Root().BigInt().String())
656}
657
658func TestCreateAccountDepositMaxValue(t *testing.T) {
659 dir, err := ioutil.TempDir("", "tmpdb")
660 require.NoError(t, err)
661 defer assert.NoError(t, os.RemoveAll(dir))
662
663 nLevels := 16
664 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
665 Type: statedb.TypeBatchBuilder, NLevels: nLevels})
666 assert.NoError(t, err)
667
668 users := txsets.GenerateJsUsers(t)
669
670 daMaxF40 := common.Float40(0xFFFFFFFFFF)
671 daMaxBI, err := daMaxF40.BigInt()
672 require.NoError(t, err)
673 assert.Equal(t, "343597383670000000000000000000000000000000", daMaxBI.String())
674
675 daMax1F40 := common.Float40(0xFFFFFFFFFE)
676 require.NoError(t, err)
677 daMax1BI, err := daMax1F40.BigInt()
678 require.NoError(t, err)
679 assert.Equal(t, "343597383660000000000000000000000000000000", daMax1BI.String())
680
681 l1Txs := []common.L1Tx{
682 {
683 FromIdx: 0,
684 DepositAmount: daMaxBI,
685 Amount: big.NewInt(0),
686 TokenID: 1,
687 FromBJJ: users[0].BJJ.Public().Compress(),
688 FromEthAddr: users[0].Addr,
689 ToIdx: 0,
690 Type: common.TxTypeCreateAccountDeposit,
691 UserOrigin: true,
692 },
693 {
694 FromIdx: 0,
695 DepositAmount: daMax1BI,
696 Amount: big.NewInt(0),
697 TokenID: 1,
698 FromBJJ: users[1].BJJ.Public().Compress(),
699 FromEthAddr: users[1].Addr,
700 ToIdx: 0,
701 Type: common.TxTypeCreateAccountDeposit,
702 UserOrigin: true,
703 },
704 }
705
706 chainID := uint16(0)
707 config := Config{
708 NLevels: uint32(nLevels),
709 MaxTx: 3,
710 MaxL1Tx: 2,
711 MaxFeeTx: 2,
712 ChainID: chainID,
713 }
714 tp := NewTxProcessor(sdb, config)
715
716 _, err = tp.ProcessTxs(nil, l1Txs, nil, nil)
717 require.NoError(t, err)
718
719 // check balances
720 acc, err := sdb.GetAccount(common.Idx(256))
721 require.NoError(t, err)
722 assert.Equal(t, daMaxBI, acc.Balance)
723 acc, err = sdb.GetAccount(common.Idx(257))
724 require.NoError(t, err)
725 assert.Equal(t, daMax1BI, acc.Balance)
726}
727
728func initTestMultipleCoordIdxForTokenID(t *testing.T) (*TxProcessor, *til.Context,
729 []common.BlockData) {
730 dir, err := ioutil.TempDir("", "tmpdb")
731 require.NoError(t, err)
732 defer assert.NoError(t, os.RemoveAll(dir))
733
734 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
735 Type: statedb.TypeBatchBuilder, NLevels: 32})
736 assert.NoError(t, err)
737
738 chainID := uint16(1)
739
740 // generate test transactions from test.SetBlockchain0 code
741 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
742
743 set := `
744 Type: Blockchain
745
746 CreateAccountDeposit(0) A: 200
747
748 > batchL1 // freeze L1User{1}
749
750 CreateAccountCoordinator(0) Coord
751 CreateAccountCoordinator(0) B
752
753 Transfer(0) A-B: 100 (126)
754
755 > batchL1 // forge L1User{1}, forge L1Coord{4}, forge L2{2}
756 > block
757 `
758 blocks, err := tc.GenerateBlocks(set)
759 require.NoError(t, err)
760
761 config := Config{
762 NLevels: 32,
763 MaxFeeTx: 64,
764 MaxTx: 512,
765 MaxL1Tx: 16,
766 ChainID: chainID,
767 }
768 tp := NewTxProcessor(sdb, config)
769 // batch1
770 _, err = tp.ProcessTxs(nil, nil, nil, nil) // to simulate the first batch from the Til set
771 require.NoError(t, err)
772
773 return tp, tc, blocks
774}
775
776func TestMultipleCoordIdxForTokenID(t *testing.T) {
777 // Check that ProcessTxs always uses the first occurrence of the
778 // CoordIdx for each TokenID
779
780 coordIdxs := []common.Idx{257, 257, 257}
781 tp, tc, blocks := initTestMultipleCoordIdxForTokenID(t)
782 l1UserTxs := til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
783 l1CoordTxs := blocks[0].Rollup.Batches[1].L1CoordinatorTxs
784 l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
785 l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
786 _, err := tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
787 require.NoError(t, err)
788
789 checkBalanceByIdx(t, tp.s, 256, "90") // A
790 checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
791 checkBalanceByIdx(t, tp.s, 258, "100") // B
792 checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
793
794 // reset StateDB values
795 coordIdxs = []common.Idx{259, 257}
796 tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
797 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
798 l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
799 l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
800 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
801 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
802 require.NoError(t, err)
803
804 checkBalanceByIdx(t, tp.s, 256, "90") // A
805 checkBalanceByIdx(t, tp.s, 257, "0") // Coord0
806 checkBalanceByIdx(t, tp.s, 258, "100") // B
807 checkBalanceByIdx(t, tp.s, 259, "10") // Coord0
808
809 // reset StateDB values
810 coordIdxs = []common.Idx{257, 259}
811 tp, tc, blocks = initTestMultipleCoordIdxForTokenID(t)
812 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
813 l1CoordTxs = blocks[0].Rollup.Batches[1].L1CoordinatorTxs
814 l1CoordTxs = append(l1CoordTxs, l1CoordTxs[0]) // duplicate the CoordAccount for TokenID=0
815 l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Rollup.Batches[1].L2Txs)
816 _, err = tp.ProcessTxs(coordIdxs, l1UserTxs, l1CoordTxs, l2Txs)
817 require.NoError(t, err)
818
819 checkBalanceByIdx(t, tp.s, 256, "90") // A
820 checkBalanceByIdx(t, tp.s, 257, "10") // Coord0
821 checkBalanceByIdx(t, tp.s, 258, "100") // B
822 checkBalanceByIdx(t, tp.s, 259, "0") // Coord0
823}
824
825func testTwoExits(t *testing.T, stateDBType statedb.TypeStateDB) ([]*ProcessTxOutput,
826 []*ProcessTxOutput, []*ProcessTxOutput) {
827 // In the first part we generate a batch with two force exits for the
828 // same account of 20 each. The txprocessor output should be a single
829 // exitInfo with balance of 40.
830 dir, err := ioutil.TempDir("", "tmpdb")
831 require.NoError(t, err)
832 defer assert.NoError(t, os.RemoveAll(dir))
833
834 nLevels := 16
835 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
836 Type: stateDBType, NLevels: nLevels})
837 assert.NoError(t, err)
838
839 chainID := uint16(1)
840
841 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
842
843 // Two exits for the same account. The tx processor should output a
844 // single exit with the accumulated exit balance
845 set := `
846 Type: Blockchain
847
848 CreateAccountDeposit(0) A: 100
849
850 > batchL1 // freeze L1User{1}
851 > batchL1 // forge L1User{1}
852
853 ForceExit(0) A: 20
854 ForceExit(0) A: 20
855
856 > batchL1 // freeze L1User{2}
857 > batchL1 // forge L1User{2}
858 > block
859 `
860 blocks, err := tc.GenerateBlocks(set)
861 require.NoError(t, err)
862 err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
863 require.NoError(t, err)
864 err = tc.FillBlocksForgedL1UserTxs(blocks)
865 require.NoError(t, err)
866
867 // Sanity check
868 require.Equal(t, 1, len(blocks[0].Rollup.Batches[1].L1UserTxs))
869 require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
870
871 config := Config{
872 NLevels: uint32(nLevels),
873 MaxTx: 3,
874 MaxL1Tx: 2,
875 MaxFeeTx: 2,
876 ChainID: chainID,
877 }
878 tp := NewTxProcessor(sdb, config)
879 ptOuts := []*ProcessTxOutput{}
880 for _, block := range blocks {
881 for _, batch := range block.Rollup.Batches {
882 ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
883 require.NoError(t, err)
884 ptOuts = append(ptOuts, ptOut)
885 }
886 }
887
888 acc, err := sdb.GetAccount(256)
889 require.NoError(t, err)
890 assert.Equal(t, big.NewInt(60), acc.Balance)
891
892 // In the second part we start a fresh statedb and generate a batch
893 // with one force exit for the same account as before. The txprocessor
894 // output should be a single exitInfo with balance of 40, and the exit
895 // merkle tree proof should be equal to the previous one.
896
897 dir2, err := ioutil.TempDir("", "tmpdb")
898 require.NoError(t, err)
899 defer assert.NoError(t, os.RemoveAll(dir2))
900
901 sdb2, err := statedb.NewStateDB(statedb.Config{Path: dir2, Keep: 128,
902 Type: stateDBType, NLevels: nLevels})
903 assert.NoError(t, err)
904
905 tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
906
907 // Single exit with balance of both exits in previous set. The exit
908 // root should match.
909 set2 := `
910 Type: Blockchain
911
912 CreateAccountDeposit(0) A: 100
913
914 > batchL1 // freeze L1User{1}
915 > batchL1 // forge L1User{1}
916
917 ForceExit(0) A: 40
918
919 > batchL1 // freeze L1User{2}
920 > batchL1 // forge L1User{2}
921 > block
922 `
923 blocks, err = tc.GenerateBlocks(set2)
924 require.NoError(t, err)
925 err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
926 require.NoError(t, err)
927 err = tc.FillBlocksForgedL1UserTxs(blocks)
928 require.NoError(t, err)
929
930 tp = NewTxProcessor(sdb2, config)
931 ptOuts2 := []*ProcessTxOutput{}
932 for _, block := range blocks {
933 for _, batch := range block.Rollup.Batches {
934 ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
935 require.NoError(t, err)
936 ptOuts2 = append(ptOuts2, ptOut)
937 }
938 }
939
940 // In the third part we start a fresh statedb and generate a batch with
941 // two force exit for the same account as before but where the 1st Exit
942 // is with all the amount, and the 2nd Exit is with more amount than
943 // the available balance. The txprocessor output should be a single
944 // exitInfo with balance of 40, and the exit merkle tree proof should
945 // be equal to the previous ones.
946
947 dir3, err := ioutil.TempDir("", "tmpdb")
948 require.NoError(t, err)
949 defer assert.NoError(t, os.RemoveAll(dir3))
950
951 sdb3, err := statedb.NewStateDB(statedb.Config{Path: dir3, Keep: 128,
952 Type: stateDBType, NLevels: nLevels})
953 assert.NoError(t, err)
954
955 tc = til.NewContext(chainID, common.RollupConstMaxL1UserTx)
956
957 // Single exit with balance of both exits in previous set. The exit
958 // root should match.
959 set3 := `
960 Type: Blockchain
961
962 CreateAccountDeposit(0) A: 100
963
964 > batchL1 // freeze L1User{1}
965 > batchL1 // forge L1User{1}
966
967 ForceExit(0) A: 40
968 ForceExit(0) A: 100
969
970 > batchL1 // freeze L1User{2}
971 > batchL1 // forge L1User{2}
972 > block
973 `
974 blocks, err = tc.GenerateBlocks(set3)
975 require.NoError(t, err)
976 err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
977 require.NoError(t, err)
978 err = tc.FillBlocksForgedL1UserTxs(blocks)
979 require.NoError(t, err)
980
981 tp = NewTxProcessor(sdb3, config)
982 ptOuts3 := []*ProcessTxOutput{}
983 for _, block := range blocks {
984 for _, batch := range block.Rollup.Batches {
985 ptOut, err := tp.ProcessTxs(nil, batch.L1UserTxs, nil, nil)
986 require.NoError(t, err)
987 ptOuts3 = append(ptOuts3, ptOut)
988 }
989 }
990
991 return ptOuts, ptOuts2, ptOuts3
992}
993
994func TestTwoExitsSynchronizer(t *testing.T) {
995 ptOuts, ptOuts2, ptOuts3 := testTwoExits(t, statedb.TypeSynchronizer)
996
997 assert.Equal(t, 1, len(ptOuts[3].ExitInfos))
998 assert.Equal(t, big.NewInt(40), ptOuts[3].ExitInfos[0].Balance)
999
1000 assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts2[3].ExitInfos[0].MerkleProof)
1001 assert.Equal(t, ptOuts[3].ExitInfos[0].MerkleProof, ptOuts3[3].ExitInfos[0].MerkleProof)
1002}
1003
1004func TestExitOf0Amount(t *testing.T) {
1005 // Test to check that when doing an Exit with amount 0 the Exit Root
1006 // does not change (as there is no new Exit Leaf created)
1007
1008 dir, err := ioutil.TempDir("", "tmpdb")
1009 require.NoError(t, err)
1010 defer assert.NoError(t, os.RemoveAll(dir))
1011
1012 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
1013 Type: statedb.TypeBatchBuilder, NLevels: 32})
1014 assert.NoError(t, err)
1015
1016 chainID := uint16(1)
1017
1018 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1019
1020 set := `
1021 Type: Blockchain
1022
1023 CreateAccountDeposit(0) A: 100
1024 CreateAccountDeposit(0) B: 100
1025
1026 > batchL1 // batch1: freeze L1User{2}
1027 > batchL1 // batch2: forge L1User{2}
1028
1029 ForceExit(0) A: 10
1030 ForceExit(0) B: 0
1031
1032 > batchL1 // batch3: freeze L1User{2}
1033 > batchL1 // batch4: forge L1User{2}
1034
1035 ForceExit(0) A: 10
1036
1037 > batchL1 // batch5: freeze L1User{1}
1038 > batchL1 // batch6: forge L1User{1}
1039
1040 ForceExit(0) A: 0
1041 > batchL1 // batch7: freeze L1User{1}
1042 > batchL1 // batch8: forge L1User{1}
1043 > block
1044 `
1045 blocks, err := tc.GenerateBlocks(set)
1046 require.NoError(t, err)
1047 err = tc.FillBlocksExtra(blocks, &til.ConfigExtra{})
1048 require.NoError(t, err)
1049 err = tc.FillBlocksForgedL1UserTxs(blocks)
1050 require.NoError(t, err)
1051
1052 // Sanity check
1053 require.Equal(t, 2, len(blocks[0].Rollup.Batches[1].L1UserTxs))
1054 require.Equal(t, 2, len(blocks[0].Rollup.Batches[3].L1UserTxs))
1055 require.Equal(t, big.NewInt(10), blocks[0].Rollup.Batches[3].L1UserTxs[0].Amount)
1056 require.Equal(t, big.NewInt(0), blocks[0].Rollup.Batches[3].L1UserTxs[1].Amount)
1057
1058 config := Config{
1059 NLevels: 32,
1060 MaxFeeTx: 64,
1061 MaxTx: 512,
1062 MaxL1Tx: 16,
1063 ChainID: chainID,
1064 }
1065 tp := NewTxProcessor(sdb, config)
1066
1067 // For this test are only processed the batches with transactions:
1068 // - Batch2, equivalent to Batches[1]
1069 // - Batch4, equivalent to Batches[3]
1070 // - Batch6, equivalent to Batches[5]
1071 // - Batch8, equivalent to Batches[7]
1072
1073 // process Batch2:
1074 _, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[1].L1UserTxs, nil, nil)
1075 require.NoError(t, err)
1076 // process Batch4:
1077 ptOut, err := tp.ProcessTxs(nil, blocks[0].Rollup.Batches[3].L1UserTxs, nil, nil)
1078 require.NoError(t, err)
1079 assert.Equal(t,
1080 "17688031540912620894848983912708704736922099609001460827147265569563156468242",
1081 ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1082 exitRootBatch4 := ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String()
1083
1084 // process Batch6:
1085 ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[5].L1UserTxs, nil, nil)
1086 require.NoError(t, err)
1087 assert.Equal(t,
1088 "17688031540912620894848983912708704736922099609001460827147265569563156468242",
1089 ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1090 // Expect that the ExitRoot for the Batch6 will be equal than for the
1091 // Batch4, as the Batch4 & Batch6 have the same tx with Exit Amount=10,
1092 // and Batch4 has a 2nd tx with Exit Amount=0.
1093 assert.Equal(t, exitRootBatch4, ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1094
1095 // For the Batch8, as there is only 1 exit with Amount=0, the ExitRoot
1096 // should be 0.
1097 // process Batch8:
1098 ptOut, err = tp.ProcessTxs(nil, blocks[0].Rollup.Batches[7].L1UserTxs, nil, nil)
1099 require.NoError(t, err)
1100 assert.Equal(t, "0", ptOut.ZKInputs.Metadata.NewExitRootRaw.BigInt().String())
1101}
1102
1103func TestUpdatedAccounts(t *testing.T) {
1104 dir, err := ioutil.TempDir("", "tmpdb")
1105 require.NoError(t, err)
1106 defer assert.NoError(t, os.RemoveAll(dir))
1107
1108 sdb, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
1109 Type: statedb.TypeSynchronizer, NLevels: 32})
1110 assert.NoError(t, err)
1111
1112 set := `
1113 Type: Blockchain
1114 AddToken(1)
1115 CreateAccountCoordinator(0) Coord // 256
1116 CreateAccountCoordinator(1) Coord // 257
1117 > batch // 1
1118 CreateAccountDeposit(0) A: 50 // 258
1119 CreateAccountDeposit(0) B: 60 // 259
1120 CreateAccountDeposit(1) A: 70 // 260
1121 CreateAccountDeposit(1) B: 80 // 261
1122 > batchL1 // 2
1123 > batchL1 // 3
1124 Transfer(0) A-B: 5 (126)
1125 > batch // 4
1126 Exit(1) B: 5 (126)
1127 > batch // 5
1128 > block
1129 `
1130
1131 chainID := uint16(0)
1132 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1133 blocks, err := tc.GenerateBlocks(set)
1134 require.NoError(t, err)
1135 tilCfgExtra := til.ConfigExtra{
1136 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
1137 CoordUser: "Coord",
1138 }
1139 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
1140 require.NoError(t, err)
1141 tc.FillBlocksL1UserTxsBatchNum(blocks)
1142 err = tc.FillBlocksForgedL1UserTxs(blocks)
1143 require.NoError(t, err)
1144
1145 require.Equal(t, 5, len(blocks[0].Rollup.Batches))
1146
1147 config := Config{
1148 NLevels: 32,
1149 MaxFeeTx: 64,
1150 MaxTx: 512,
1151 MaxL1Tx: 16,
1152 ChainID: chainID,
1153 }
1154 tp := NewTxProcessor(sdb, config)
1155
1156 sortedKeys := func(m map[common.Idx]*common.Account) []int {
1157 keys := make([]int, 0)
1158 for k := range m {
1159 keys = append(keys, int(k))
1160 }
1161 sort.Ints(keys)
1162 return keys
1163 }
1164
1165 for _, batch := range blocks[0].Rollup.Batches {
1166 l2Txs := common.L2TxsToPoolL2Txs(batch.L2Txs)
1167 ptOut, err := tp.ProcessTxs(batch.Batch.FeeIdxsCoordinator, batch.L1UserTxs,
1168 batch.L1CoordinatorTxs, l2Txs)
1169 require.NoError(t, err)
1170 switch batch.Batch.BatchNum {
1171 case 1:
1172 assert.Equal(t, 2, len(ptOut.UpdatedAccounts))
1173 assert.Equal(t, []int{256, 257}, sortedKeys(ptOut.UpdatedAccounts))
1174 case 2:
1175 assert.Equal(t, 0, len(ptOut.UpdatedAccounts))
1176 assert.Equal(t, []int{}, sortedKeys(ptOut.UpdatedAccounts))
1177 case 3:
1178 assert.Equal(t, 4, len(ptOut.UpdatedAccounts))
1179 assert.Equal(t, []int{258, 259, 260, 261}, sortedKeys(ptOut.UpdatedAccounts))
1180 case 4:
1181 assert.Equal(t, 2+1, len(ptOut.UpdatedAccounts))
1182 assert.Equal(t, []int{256, 258, 259}, sortedKeys(ptOut.UpdatedAccounts))
1183 case 5:
1184 assert.Equal(t, 1+1, len(ptOut.UpdatedAccounts))
1185 assert.Equal(t, []int{257, 261}, sortedKeys(ptOut.UpdatedAccounts))
1186 }
1187 for idx, updAcc := range ptOut.UpdatedAccounts {
1188 acc, err := sdb.GetAccount(idx)
1189 require.NoError(t, err)
1190 // If acc.Balance is 0, set it to 0 with big.NewInt so
1191 // that the comparison succeeds. Without this, the
1192 // comparison will not succeed because acc.Balance is
1193 // set from a slice, and thus the internal big.Int
1194 // buffer is not nil (big.Int.abs)
1195 if acc.Balance.BitLen() == 0 {
1196 acc.Balance = big.NewInt(0)
1197 }
1198 assert.Equal(t, acc, updAcc)
1199 }
1200 }
1201}