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