hermez-node/txselector/txselector_test.go
txselector/txselector_test.goRaw
1package txselector
2
3import (
4 "fmt"
5 "io/ioutil"
6 "os"
7 "strconv"
8 "testing"
9 "time"
10
11 ethCommon "github.com/ethereum/go-ethereum/common"
12 ethCrypto "github.com/ethereum/go-ethereum/crypto"
13 "github.com/hermeznetwork/hermez-node/common"
14 dbUtils "github.com/hermeznetwork/hermez-node/db"
15 "github.com/hermeznetwork/hermez-node/db/historydb"
16 "github.com/hermeznetwork/hermez-node/db/l2db"
17 "github.com/hermeznetwork/hermez-node/db/statedb"
18 "github.com/hermeznetwork/hermez-node/log"
19 "github.com/hermeznetwork/hermez-node/test"
20 "github.com/hermeznetwork/hermez-node/test/til"
21 "github.com/hermeznetwork/hermez-node/test/txsets"
22 "github.com/hermeznetwork/hermez-node/txprocessor"
23 "github.com/jmoiron/sqlx"
24 "github.com/stretchr/testify/assert"
25 "github.com/stretchr/testify/require"
26)
27
28func initTest(t *testing.T, chainID uint16, hermezContractAddr ethCommon.Address,
29 coordUser *til.User) (*TxSelector, *historydb.HistoryDB) {
30 pass := os.Getenv("POSTGRES_PASS")
31 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
32 require.NoError(t, err)
33 l2DB := l2db.NewL2DB(db, db, 10, 100, 0.0, 1000.0, 24*time.Hour, nil)
34
35 historyDB := historydb.NewHistoryDB(db, db, nil)
36
37 dir, err := ioutil.TempDir("", "tmpdb")
38 require.NoError(t, err)
39 defer assert.NoError(t, os.RemoveAll(dir))
40 syncStateDB, err := statedb.NewStateDB(statedb.Config{Path: dir, Keep: 128,
41 Type: statedb.TypeTxSelector, NLevels: 0})
42 require.NoError(t, err)
43
44 txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
45 require.NoError(t, err)
46 defer assert.NoError(t, os.RemoveAll(dir))
47
48 // use Til Coord keys for tests compatibility
49 coordAccount := &CoordAccount{
50 Addr: coordUser.Addr,
51 BJJ: coordUser.BJJ.Public().Compress(),
52 AccountCreationAuth: nil,
53 }
54 // fmt.Printf("%v\n", coordAccount)
55 auth := common.AccountCreationAuth{
56 EthAddr: coordUser.Addr,
57 BJJ: coordUser.BJJ.Public().Compress(),
58 }
59 err = auth.Sign(func(hash []byte) ([]byte, error) {
60 return ethCrypto.Sign(hash, coordUser.EthSk)
61 }, chainID, hermezContractAddr)
62 assert.NoError(t, err)
63 coordAccount.AccountCreationAuth = auth.Signature
64
65 txsel, err := NewTxSelector(coordAccount, txselDir, syncStateDB, l2DB)
66 require.NoError(t, err)
67
68 test.WipeDB(txsel.l2db.DB())
69
70 return txsel, historyDB
71}
72
73func addAccCreationAuth(t *testing.T, tc *til.Context, txsel *TxSelector, chainID uint16,
74 hermezContractAddr ethCommon.Address, username string) []byte {
75 user := tc.Users[username]
76 auth := &common.AccountCreationAuth{
77 EthAddr: user.Addr,
78 BJJ: user.BJJ.Public().Compress(),
79 }
80 err := auth.Sign(func(hash []byte) ([]byte, error) {
81 return ethCrypto.Sign(hash, user.EthSk)
82 }, chainID, hermezContractAddr)
83 assert.NoError(t, err)
84
85 err = txsel.l2db.AddAccountCreationAuth(auth)
86 assert.NoError(t, err)
87 return auth.Signature
88}
89
90func addL2Txs(t *testing.T, txsel *TxSelector, poolL2Txs []common.PoolL2Tx) {
91 for i := 0; i < len(poolL2Txs); i++ {
92 err := txsel.l2db.AddTxTest(&poolL2Txs[i])
93 if err != nil {
94 log.Error(err)
95 }
96 require.NoError(t, err)
97 }
98}
99
100func addTokens(t *testing.T, tc *til.Context, db *sqlx.DB) {
101 var tokens []common.Token
102 for i := 0; i < int(tc.LastRegisteredTokenID); i++ {
103 tokens = append(tokens, common.Token{
104 TokenID: common.TokenID(i + 1),
105 EthBlockNum: 1,
106 EthAddr: ethCommon.BytesToAddress([]byte{byte(i + 1)}),
107 Name: strconv.Itoa(i),
108 Symbol: strconv.Itoa(i),
109 Decimals: 18,
110 })
111 }
112
113 hdb := historydb.NewHistoryDB(db, db, nil)
114 assert.NoError(t, hdb.AddBlock(&common.Block{
115 Num: 1,
116 }))
117 assert.NoError(t, hdb.AddTokens(tokens))
118}
119
120func checkBalance(t *testing.T, tc *til.Context, txsel *TxSelector, username string,
121 tokenid int, expected string) {
122 // Accounts.Idx does not match with the TxSelector tests as we are not
123 // using the Til L1CoordinatorTxs (as are generated by the TxSelector
124 // itself when processing the txs, so the Idxs does not match the Til
125 // idxs). But the Idx is obtained through StateDB.GetIdxByEthAddrBJJ
126 user := tc.Users[username]
127 idx, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(user.Addr, user.BJJ.Public().Compress(),
128 common.TokenID(tokenid))
129 require.NoError(t, err)
130 checkBalanceByIdx(t, txsel, idx, expected)
131}
132
133func checkBalanceByIdx(t *testing.T, txsel *TxSelector, idx common.Idx, expected string) {
134 acc, err := txsel.localAccountsDB.GetAccount(idx)
135 require.NoError(t, err)
136 assert.Equal(t, expected, acc.Balance.String())
137}
138
139// checkSortedByNonce takes as input testAccNonces map, and the array of
140// common.PoolL2Txs, and checks if the nonces correspond to the accumulated
141// values of the map. Also increases the Nonces computed on the map.
142func checkSortedByNonce(t *testing.T, testAccNonces map[common.Idx]common.Nonce,
143 txs []common.PoolL2Tx) {
144 for _, tx := range txs {
145 assert.True(t, testAccNonces[tx.FromIdx] == tx.Nonce,
146 fmt.Sprintf("Idx: %d, expected: %d, tx.Nonce: %d",
147 tx.FromIdx, testAccNonces[tx.FromIdx], tx.Nonce))
148 testAccNonces[tx.FromIdx] = testAccNonces[tx.FromIdx] + 1
149 }
150}
151
152func TestGetL2TxSelectionMinimumFlow0(t *testing.T) {
153 chainID := uint16(0)
154 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
155 // generate test transactions, the L1CoordinatorTxs generated by Til
156 // will be ignored at this test, as will be the TxSelector who
157 // generates them when needed
158 blocks, err := tc.GenerateBlocks(txsets.SetBlockchainMinimumFlow0)
159 assert.NoError(t, err)
160
161 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
162 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
163
164 // restart nonces of TilContext, as will be set by generating directly
165 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
166 tc.RestartNonces()
167 testAccNonces := make(map[common.Idx]common.Nonce)
168
169 // add tokens to HistoryDB to avoid breaking FK constrains
170 addTokens(t, tc, txsel.l2db.DB())
171
172 tpc := txprocessor.Config{
173 NLevels: 16,
174 MaxFeeTx: 10,
175 MaxTx: 20,
176 MaxL1Tx: 10,
177 ChainID: chainID,
178 }
179
180 // coordIdxs, accAuths, l1UserTxs, l1CoordTxs, l2Txs, err
181
182 log.Debug("block:0 batch:1")
183 l1UserTxs := []common.L1Tx{}
184 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err :=
185 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
186 require.NoError(t, err)
187 assert.Equal(t, 0, len(oL1UserTxs))
188 assert.Equal(t, 0, len(oL1CoordTxs))
189 assert.Equal(t, 0, len(oL2Txs))
190 assert.Equal(t, common.BatchNum(1), txsel.localAccountsDB.CurrentBatch())
191 assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
192
193 log.Debug("block:0 batch:2")
194 l1UserTxs = []common.L1Tx{}
195 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
196 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
197 require.NoError(t, err)
198 assert.Equal(t, 0, len(oL1UserTxs))
199 assert.Equal(t, 0, len(oL1CoordTxs))
200 assert.Equal(t, 0, len(oL2Txs))
201 assert.Equal(t, common.BatchNum(2), txsel.localAccountsDB.CurrentBatch())
202 assert.Equal(t, common.Idx(255), txsel.localAccountsDB.CurrentIdx())
203
204 log.Debug("block:0 batch:3")
205 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
206 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
207 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
208 require.NoError(t, err)
209 assert.Equal(t, 2, len(oL1UserTxs))
210 assert.Equal(t, 0, len(oL1CoordTxs))
211 assert.Equal(t, 0, len(oL2Txs))
212 assert.Equal(t, common.BatchNum(3), txsel.localAccountsDB.CurrentBatch())
213 assert.Equal(t, common.Idx(257), txsel.localAccountsDB.CurrentIdx())
214 checkBalance(t, tc, txsel, "A", 0, "500")
215 checkBalance(t, tc, txsel, "C", 1, "0")
216
217 log.Debug("block:0 batch:4")
218 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[3].Batch.ForgeL1TxsNum])
219 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
220 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
221 require.NoError(t, err)
222 assert.Equal(t, 1, len(oL1UserTxs))
223 assert.Equal(t, 0, len(oL1CoordTxs))
224 assert.Equal(t, 0, len(oL2Txs))
225 assert.Equal(t, common.BatchNum(4), txsel.localAccountsDB.CurrentBatch())
226 assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
227 checkBalance(t, tc, txsel, "A", 0, "500")
228 checkBalance(t, tc, txsel, "A", 1, "500")
229 checkBalance(t, tc, txsel, "C", 1, "0")
230
231 log.Debug("block:0 batch:5")
232 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[4].Batch.ForgeL1TxsNum])
233 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
234 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
235 require.NoError(t, err)
236 assert.Equal(t, 0, len(oL1UserTxs))
237 assert.Equal(t, 0, len(oL1CoordTxs))
238 assert.Equal(t, 0, len(oL2Txs))
239 assert.Equal(t, common.BatchNum(5), txsel.localAccountsDB.CurrentBatch())
240 assert.Equal(t, common.Idx(258), txsel.localAccountsDB.CurrentIdx())
241 checkBalance(t, tc, txsel, "A", 0, "500")
242 checkBalance(t, tc, txsel, "A", 1, "500")
243 checkBalance(t, tc, txsel, "C", 1, "0")
244
245 log.Debug("block:0 batch:6")
246 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[5].Batch.ForgeL1TxsNum])
247 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
248 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
249 require.NoError(t, err)
250 assert.Equal(t, 1, len(oL1UserTxs))
251 assert.Equal(t, 0, len(oL1CoordTxs))
252 assert.Equal(t, 0, len(oL2Txs))
253 assert.Equal(t, common.BatchNum(6), txsel.localAccountsDB.CurrentBatch())
254 assert.Equal(t, common.Idx(259), txsel.localAccountsDB.CurrentIdx())
255 checkBalance(t, tc, txsel, "A", 0, "600")
256 checkBalance(t, tc, txsel, "A", 1, "500")
257 checkBalance(t, tc, txsel, "B", 0, "400")
258 checkBalance(t, tc, txsel, "C", 1, "0")
259
260 log.Debug("block:0 batch:7")
261 // simulate the PoolL2Txs of the batch7
262 batchPoolL2 := `
263 Type: PoolL2
264 PoolTransferToEthAddr(1) A-B: 200 (126)
265 PoolTransferToEthAddr(0) B-C: 100 (126)`
266 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
267 require.NoError(t, err)
268 // add AccountCreationAuths that will be used at the next batch
269 accAuthSig0 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "B")
270 accAuthSig1 := addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
271 // add the PoolL2Txs to the l2DB
272 addL2Txs(t, txsel, poolL2Txs)
273 // check signatures of L2Txs from the L2DB (to check that the
274 // parameters of the PoolL2Tx match the original parameters signed
275 // before inserting it to the L2DB)
276 l2TxsFromDB, err := txsel.l2db.GetPendingTxs()
277 require.NoError(t, err)
278 assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
279 assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
280 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[6].Batch.ForgeL1TxsNum])
281 coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
282 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
283 require.NoError(t, err)
284 assert.Equal(t, []common.Idx{261, 263}, coordIdxs)
285 assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[0])
286 assert.Equal(t, txsel.coordAccount.AccountCreationAuth, accAuths[2])
287 assert.Equal(t, accAuthSig0, accAuths[1])
288 assert.Equal(t, accAuthSig1, accAuths[3])
289 assert.Equal(t, 1, len(oL1UserTxs))
290 assert.Equal(t, 4, len(oL1CoordTxs))
291 assert.Equal(t, 2, len(oL2Txs))
292 assert.Equal(t, 0, len(discardedL2Txs))
293 assert.Equal(t, len(oL1CoordTxs), len(accAuths))
294 assert.Equal(t, common.BatchNum(7), txsel.localAccountsDB.CurrentBatch())
295 assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
296 checkBalance(t, tc, txsel, "Coord", 1, "20") // CoordIdx for TokenID=1
297 checkBalance(t, tc, txsel, "Coord", 0, "10") // CoordIdx for TokenID=1
298 checkBalance(t, tc, txsel, "A", 0, "600")
299 checkBalance(t, tc, txsel, "A", 1, "280")
300 checkBalance(t, tc, txsel, "B", 0, "290")
301 checkBalance(t, tc, txsel, "B", 1, "200")
302 checkBalance(t, tc, txsel, "C", 0, "100")
303 checkBalance(t, tc, txsel, "D", 0, "800")
304 checkSortedByNonce(t, testAccNonces, oL2Txs)
305 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
306 txsel.localAccountsDB.CurrentBatch())
307 require.NoError(t, err)
308
309 log.Debug("block:0 batch:8")
310 // simulate the PoolL2Txs of the batch8
311 batchPoolL2 = `
312 Type: PoolL2
313 PoolTransfer(0) A-B: 100 (126)
314 PoolTransfer(0) C-A: 50 (126)
315 PoolTransfer(1) B-C: 100 (126)
316 PoolExit(0) A: 100 (126)`
317 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
318 require.NoError(t, err)
319 addL2Txs(t, txsel, poolL2Txs)
320 // check signatures of L2Txs from the L2DB (to check that the
321 // parameters of the PoolL2Tx match the original parameters signed
322 // before inserting it to the L2DB)
323 l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
324 require.NoError(t, err)
325 assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
326 assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["C"].BJJ.Public().Compress()))
327 assert.True(t, l2TxsFromDB[2].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
328 assert.True(t, l2TxsFromDB[3].VerifySignature(chainID, tc.Users["A"].BJJ.Public().Compress()))
329 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[7].Batch.ForgeL1TxsNum])
330 coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
331 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
332 require.NoError(t, err)
333 assert.Equal(t, []common.Idx{261, 263}, coordIdxs)
334 assert.Equal(t, 0, len(accAuths))
335 assert.Equal(t, 0, len(oL1UserTxs))
336 assert.Equal(t, 0, len(oL1CoordTxs))
337 assert.Equal(t, 4, len(oL2Txs))
338 assert.Equal(t, 0, len(discardedL2Txs))
339 assert.Equal(t, len(oL1CoordTxs), len(accAuths))
340 assert.Equal(t, common.BatchNum(8), txsel.localAccountsDB.CurrentBatch())
341 assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
342 checkBalance(t, tc, txsel, "Coord", 1, "30") // CoordIdx for TokenID=1
343 checkBalance(t, tc, txsel, "Coord", 0, "35") // CoordIdx for TokenID=1
344 checkBalance(t, tc, txsel, "A", 0, "430")
345 checkBalance(t, tc, txsel, "A", 1, "280")
346 checkBalance(t, tc, txsel, "B", 0, "390")
347 checkBalance(t, tc, txsel, "B", 1, "90")
348 checkBalance(t, tc, txsel, "C", 0, "45")
349 checkBalance(t, tc, txsel, "C", 1, "100")
350 checkBalance(t, tc, txsel, "D", 0, "800")
351 checkSortedByNonce(t, testAccNonces, oL2Txs)
352 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
353 txsel.localAccountsDB.CurrentBatch())
354 require.NoError(t, err)
355
356 log.Debug("(batch9)block:1 batch:1")
357 // simulate the PoolL2Txs of the batch9
358 batchPoolL2 = `
359 Type: PoolL2
360 PoolTransfer(0) D-A: 300 (126)
361 PoolTransfer(0) B-D: 100 (126)
362 `
363 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
364 require.NoError(t, err)
365 addL2Txs(t, txsel, poolL2Txs)
366 // check signatures of L2Txs from the L2DB (to check that the
367 // parameters of the PoolL2Tx match the original parameters signed
368 // before inserting it to the L2DB)
369 l2TxsFromDB, err = txsel.l2db.GetPendingTxs()
370 require.NoError(t, err)
371 assert.True(t, l2TxsFromDB[0].VerifySignature(chainID, tc.Users["D"].BJJ.Public().Compress()))
372 assert.True(t, l2TxsFromDB[1].VerifySignature(chainID, tc.Users["B"].BJJ.Public().Compress()))
373 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Rollup.Batches[0].Batch.ForgeL1TxsNum])
374 coordIdxs, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, _, err =
375 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
376 require.NoError(t, err)
377 assert.Equal(t, []common.Idx{263}, coordIdxs)
378 assert.Equal(t, 0, len(accAuths))
379 assert.Equal(t, 4, len(oL1UserTxs))
380 assert.Equal(t, 0, len(oL1CoordTxs))
381 assert.Equal(t, 2, len(oL2Txs))
382 assert.Equal(t, len(oL1CoordTxs), len(accAuths))
383 assert.Equal(t, common.BatchNum(9), txsel.localAccountsDB.CurrentBatch())
384 assert.Equal(t, common.Idx(264), txsel.localAccountsDB.CurrentIdx())
385 checkBalanceByIdx(t, txsel, 261, "30")
386 checkBalanceByIdx(t, txsel, 263, "75")
387 checkBalance(t, tc, txsel, "A", 0, "730")
388 checkBalance(t, tc, txsel, "A", 1, "280")
389 checkBalance(t, tc, txsel, "B", 0, "380")
390 checkBalance(t, tc, txsel, "B", 1, "90")
391 checkBalance(t, tc, txsel, "C", 0, "845")
392 checkBalance(t, tc, txsel, "C", 1, "100")
393 checkBalance(t, tc, txsel, "D", 0, "470")
394 checkSortedByNonce(t, testAccNonces, oL2Txs)
395 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(poolL2Txs),
396 txsel.localAccountsDB.CurrentBatch())
397 require.NoError(t, err)
398}
399
400func TestPoolL2TxsWithoutEnoughBalance(t *testing.T) {
401 set := `
402 Type: Blockchain
403
404 CreateAccountDeposit(0) Coord: 0
405 CreateAccountDeposit(0) A: 100
406 CreateAccountDeposit(0) B: 100
407
408 > batchL1 // freeze L1User{3}
409 > batchL1 // forge L1User{3}
410 > block
411 `
412
413 chainID := uint16(0)
414 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
415 // generate test transactions, the L1CoordinatorTxs generated by Til
416 // will be ignored at this test, as will be the TxSelector who
417 // generates them when needed
418 blocks, err := tc.GenerateBlocks(set)
419 assert.NoError(t, err)
420
421 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
422 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
423
424 // restart nonces of TilContext, as will be set by generating directly
425 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
426 tc.RestartNonces()
427
428 tpc := txprocessor.Config{
429 NLevels: 16,
430 MaxFeeTx: 10,
431 MaxTx: 20,
432 MaxL1Tx: 10,
433 ChainID: chainID,
434 }
435 // batch1
436 l1UserTxs := []common.L1Tx{}
437 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
438 require.NoError(t, err)
439 // 1st TransferToEthAddr
440 expectedTxID0 := "0x028847b86613c0b70be18c8622119ed045b42e4e47d7938fa90bb3d1dc14928965"
441 // 1st Exit
442 expectedTxID1 := "0x0200b18773dcf56f770d65870fb02041cb59a088fd35b7c3f3df69f8a250b99a42"
443 // 2nd TransferToEthAddr
444 expectedTxID2 := "0x029720ff506153f970f120ac638cd7ee759eeff2c2012e7634a78e4fdc05c04a90"
445
446 // batch2
447 // prepare the PoolL2Txs
448 batchPoolL2 := `
449 Type: PoolL2
450 PoolTransferToEthAddr(0) A-B: 100 (126)
451 PoolExit(0) B: 100 (126)`
452 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
453 require.NoError(t, err)
454 // add the PoolL2Txs to the l2DB
455 addL2Txs(t, txsel, poolL2Txs)
456
457 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
458 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
459 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
460 require.NoError(t, err)
461 assert.Equal(t, 3, len(oL1UserTxs))
462 assert.Equal(t, 0, len(oL1CoordTxs))
463 assert.Equal(t, 0, len(oL2Txs)) // should be 0 as the 2 PoolL2Txs does not have enough funds
464 assert.Equal(t, 2, len(discardedL2Txs))
465 assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
466 assert.Equal(t, expectedTxID1, discardedL2Txs[1].TxID.String())
467 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
468 txsel.localAccountsDB.CurrentBatch())
469 require.NoError(t, err)
470
471 // as the PoolL2Txs have not been really processed, restart nonces
472 tc.RestartNonces()
473
474 // batch3
475 batchPoolL2 = `
476 Type: PoolL2
477 PoolTransferToEthAddr(0) A-B: 50 (126)`
478 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
479 require.NoError(t, err)
480 addL2Txs(t, txsel, poolL2Txs)
481
482 l1UserTxs = []common.L1Tx{}
483 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
484 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
485 require.NoError(t, err)
486 assert.Equal(t, 0, len(oL1UserTxs))
487 assert.Equal(t, 0, len(oL1CoordTxs))
488 assert.Equal(t, 2, len(oL2Txs))
489 assert.Equal(t, 1, len(discardedL2Txs))
490 assert.Equal(t, expectedTxID2, oL2Txs[0].TxID.String())
491 assert.Equal(t, expectedTxID1, oL2Txs[1].TxID.String())
492 assert.Equal(t, expectedTxID0, discardedL2Txs[0].TxID.String())
493 assert.Equal(t, common.TxTypeTransferToEthAddr, oL2Txs[0].Type)
494 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
495 txsel.localAccountsDB.CurrentBatch())
496 require.NoError(t, err)
497
498 // batch4
499 // make the selection of another batch, which should include the
500 // initial PoolExit, which now is valid as B has enough Balance
501 l1UserTxs = []common.L1Tx{}
502 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
503 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
504 require.NoError(t, err)
505 assert.Equal(t, 0, len(oL1UserTxs))
506 assert.Equal(t, 0, len(oL1CoordTxs))
507 assert.Equal(t, 0, len(oL2Txs))
508 assert.Equal(t, 1, len(discardedL2Txs))
509 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
510 txsel.localAccountsDB.CurrentBatch())
511 require.NoError(t, err)
512}
513
514func TestTransferToBjj(t *testing.T) {
515 set := `
516 Type: Blockchain
517 AddToken(1)
518
519 CreateAccountDeposit(0) Coord: 0
520 CreateAccountDeposit(0) A: 1000
521 CreateAccountDeposit(0) B: 1000
522 CreateAccountDeposit(1) B: 1000
523
524 > batchL1 // freeze L1User{4}
525 > batchL1 // forge L1User{4}
526 > block
527 `
528
529 chainID := uint16(0)
530 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
531 blocks, err := tc.GenerateBlocks(set)
532 assert.NoError(t, err)
533
534 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
535 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
536
537 // restart nonces of TilContext, as will be set by generating directly
538 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
539 tc.RestartNonces()
540
541 addTokens(t, tc, txsel.l2db.DB())
542
543 tpc := txprocessor.Config{
544 NLevels: 16,
545 MaxFeeTx: 10,
546 MaxTx: 20,
547 MaxL1Tx: 10,
548 ChainID: chainID,
549 }
550 // batch1 to freeze L1UserTxs that will create some accounts with
551 // positive balance
552 l1UserTxs := []common.L1Tx{}
553 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
554 require.NoError(t, err)
555
556 // Transfer is ToBJJ to a BJJ-only account that doesn't exist
557 // and the coordinator will create it via L1CoordTx.
558
559 batchPoolL2 := `
560 Type: PoolL2
561 PoolTransferToBJJ(0) A-B: 50 (126)
562 `
563 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
564 require.NoError(t, err)
565
566 // add the PoolL2Txs to the l2DB
567 addL2Txs(t, txsel, poolL2Txs)
568
569 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
570 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
571 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
572 require.NoError(t, err)
573 assert.Equal(t, 4, len(oL1UserTxs))
574 // We expect the coordinator to add an L1CoordTx to create an account for the recipient of the l2tx
575 require.Equal(t, 1, len(oL1CoordTxs))
576 assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[0].FromEthAddr)
577 assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[0].FromBJJ)
578 assert.Equal(t, 1, len(oL2Txs))
579 assert.Equal(t, 0, len(discardedL2Txs))
580 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
581 txsel.localAccountsDB.CurrentBatch())
582 require.NoError(t, err)
583
584 // Now the BJJ-only account for B is already created, so the transfer
585 // happens without an L1CoordTx that creates the user account.
586
587 batchPoolL2 = `
588 Type: PoolL2
589 PoolTransferToBJJ(0) A-B: 50 (126)
590 `
591
592 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
593 require.NoError(t, err)
594 addL2Txs(t, txsel, poolL2Txs)
595
596 l1UserTxs = []common.L1Tx{}
597 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
598 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
599 require.NoError(t, err)
600 assert.Equal(t, 0, len(oL1UserTxs))
601 // Since the BJJ-only account B already exists, the coordinator doesn't add any L1CoordTxs
602 assert.Equal(t, 0, len(oL1CoordTxs))
603 assert.Equal(t, 1, len(oL2Txs))
604 assert.Equal(t, 0, len(discardedL2Txs))
605 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
606 txsel.localAccountsDB.CurrentBatch())
607 require.NoError(t, err)
608
609 // The transfer now is ToBJJ to a BJJ-only account that doesn't exist
610 // and the coordinator will create it via L1CoordTx. Since it's a
611 // transfer of a token for which the coordinator doesn't have a fee
612 // account, another L1CoordTx will be created for the coordinator to
613 // receive the fees.
614
615 batchPoolL2 = `
616 Type: PoolL2
617 PoolTransferToBJJ(1) B-A: 50 (126)
618 `
619
620 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
621 require.NoError(t, err)
622 addL2Txs(t, txsel, poolL2Txs)
623
624 l1UserTxs = []common.L1Tx{}
625 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
626 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
627 require.NoError(t, err)
628 assert.Equal(t, 0, len(oL1UserTxs))
629 // We expect the coordinator to add an L1CoordTx to create an account
630 // to receive the fees by the coordinator and another one for the
631 // recipient of the l2tx
632 assert.Equal(t, 2, len(oL1CoordTxs))
633 // [0] Coordinator account cration for token 1
634 assert.Equal(t, tc.Users["Coord"].Addr, oL1CoordTxs[0].FromEthAddr)
635 // [1] User A BJJ-only account creation for token 1
636 assert.Equal(t, poolL2Txs[0].ToEthAddr, oL1CoordTxs[1].FromEthAddr)
637 assert.Equal(t, poolL2Txs[0].ToBJJ, oL1CoordTxs[1].FromBJJ)
638 assert.Equal(t, common.TokenID(1), oL1CoordTxs[1].TokenID)
639
640 assert.Equal(t, 1, len(oL2Txs))
641 assert.Equal(t, 0, len(discardedL2Txs))
642 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
643 txsel.localAccountsDB.CurrentBatch())
644 require.NoError(t, err)
645}
646
647func TestTransferManyFromSameAccount(t *testing.T) {
648 set := `
649 Type: Blockchain
650
651 CreateAccountDeposit(0) Coord: 0
652 CreateAccountDeposit(0) A: 1000
653 CreateAccountDeposit(0) B: 1000
654
655 > batchL1 // freeze L1User{3}
656 > batchL1 // forge L1User{3}
657 > block
658 `
659
660 chainID := uint16(0)
661 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
662 blocks, err := tc.GenerateBlocks(set)
663 assert.NoError(t, err)
664
665 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
666 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
667
668 // restart nonces of TilContext, as will be set by generating directly
669 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
670 tc.RestartNonces()
671
672 tpc := txprocessor.Config{
673 NLevels: 16,
674 MaxFeeTx: 10,
675 MaxTx: 10,
676 MaxL1Tx: 10,
677 ChainID: chainID,
678 }
679 // batch1 to freeze L1UserTxs
680 l1UserTxs := []common.L1Tx{}
681 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
682 require.NoError(t, err)
683
684 // 8 transfers from the same account
685 batchPoolL2 := `
686 Type: PoolL2
687 PoolTransfer(0) A-B: 10 (126) // 1
688 PoolTransfer(0) A-B: 10 (126) // 2
689 PoolTransfer(0) A-B: 10 (126) // 3
690 PoolTransfer(0) A-B: 10 (126) // 4
691 PoolTransfer(0) A-B: 10 (126) // 5
692 PoolTransfer(0) A-B: 10 (126) // 6
693 PoolTransfer(0) A-B: 10 (126) // 7
694 PoolTransfer(0) A-B: 10 (126) // 8
695 PoolTransfer(0) A-B: 10 (126) // 9
696 PoolTransfer(0) A-B: 10 (126) // 10
697 PoolTransfer(0) A-B: 10 (126) // 11
698 `
699 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
700 require.NoError(t, err)
701 require.Equal(t, 11, len(poolL2Txs))
702
703 // reorder poolL2Txs so that nonces are not sorted
704 poolL2Txs[0], poolL2Txs[7] = poolL2Txs[7], poolL2Txs[0]
705 poolL2Txs[1], poolL2Txs[10] = poolL2Txs[10], poolL2Txs[1]
706
707 // add the PoolL2Txs to the l2DB
708 addL2Txs(t, txsel, poolL2Txs)
709 // batch 2 to crate some accounts with positive balance, and do 8 L2Tx
710 // transfers from account A
711 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
712 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
713 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
714 require.NoError(t, err)
715 assert.Equal(t, 3, len(oL1UserTxs))
716 require.Equal(t, 0, len(oL1CoordTxs))
717 assert.Equal(t, 7, len(oL2Txs))
718 assert.Equal(t, 4, len(discardedL2Txs))
719
720 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
721 txsel.localAccountsDB.CurrentBatch())
722 require.NoError(t, err)
723}
724
725func TestPoolL2TxInvalidNonces(t *testing.T) {
726 // This test recreates the case where L2Txs of type TransferToEthAddr
727 // for non existing accounts are not selected due not enough space for
728 // the needed L1CoordinatorTxs (of account creation).
729
730 set := `
731 Type: Blockchain
732
733 CreateAccountDeposit(0) Coord: 0
734 CreateAccountDeposit(0) A: 100000
735 CreateAccountDeposit(0) B: 10000
736
737 > batchL1 // Batch1: freeze L1User{3}
738 > batchL1 // Batch2: forge L1User{3}
739 > block
740 `
741
742 chainID := uint16(0)
743 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
744 blocks, err := tc.GenerateBlocks(set)
745 assert.NoError(t, err)
746
747 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
748 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
749
750 // restart nonces of TilContext, as will be set by generating directly
751 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
752 tc.RestartNonces()
753
754 tpc := txprocessor.Config{
755 NLevels: 16,
756 MaxFeeTx: 10,
757 MaxTx: 20,
758 MaxL1Tx: 3,
759 ChainID: chainID,
760 }
761 // batch1 to freeze L1UserTxs
762 l1UserTxs := []common.L1Tx{}
763 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
764 require.NoError(t, err)
765
766 batchPoolL2 := `
767 Type: PoolL2
768 PoolTransferToEthAddr(0) B-C: 10 (126)
769 PoolTransfer(0) B-A: 10 (126)
770 PoolTransferToEthAddr(0) B-D: 10 (126)
771 PoolTransfer(0) B-A: 10 (126)
772 PoolTransferToEthAddr(0) B-E: 10 (126)
773 PoolTransfer(0) B-A: 10 (126)
774 PoolTransferToEthAddr(0) B-F: 10 (126)
775 PoolTransfer(0) B-A: 10 (126)
776 PoolTransferToEthAddr(0) B-G: 10 (126)
777 PoolTransfer(0) B-A: 10 (126)
778 `
779 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
780 require.NoError(t, err)
781 require.Equal(t, 10, len(poolL2Txs))
782
783 // add AccountCreationAuths that will be used at the next batch
784 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "C")
785 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "D")
786 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "E")
787 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "F")
788 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "G")
789
790 // add the PoolL2Txs to the l2DB
791 addL2Txs(t, txsel, poolL2Txs)
792 // batch 2 to crate the accounts (from L1UserTxs)
793 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
794
795 // select L1 & L2 txs
796 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
797 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
798 require.NoError(t, err)
799 require.Equal(t, 3, len(oL1UserTxs))
800 require.Equal(t, 0, len(oL1CoordTxs))
801 require.Equal(t, 0, len(oL2Txs))
802 require.Equal(t, 10, len(discardedL2Txs))
803 require.Equal(t, 0, len(accAuths))
804
805 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
806 txsel.localAccountsDB.CurrentBatch())
807 require.NoError(t, err)
808
809 // batch 3
810 l1UserTxs = []common.L1Tx{}
811 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
812 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
813 require.NoError(t, err)
814
815 require.Equal(t, 0, len(oL1UserTxs))
816 require.Equal(t, 3, len(oL1CoordTxs))
817 require.Equal(t, 8, len(oL2Txs))
818 require.Equal(t, 2, len(discardedL2Txs))
819 require.Equal(t, 3, len(accAuths))
820
821 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
822 txsel.localAccountsDB.CurrentBatch())
823 require.NoError(t, err)
824
825 // batch 4
826 l1UserTxs = []common.L1Tx{}
827 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
828 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
829 require.NoError(t, err)
830
831 require.Equal(t, 0, len(oL1UserTxs))
832 require.Equal(t, 1, len(oL1CoordTxs))
833 require.Equal(t, 2, len(oL2Txs))
834 require.Equal(t, 0, len(discardedL2Txs))
835 require.Equal(t, 1, len(accAuths))
836
837 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
838 txsel.localAccountsDB.CurrentBatch())
839 require.NoError(t, err)
840}
841
842func TestProcessL2Selection(t *testing.T) {
843 set := `
844 Type: Blockchain
845
846 CreateAccountDeposit(0) Coord: 0
847 CreateAccountDeposit(0) A: 18
848 CreateAccountDeposit(0) B: 0
849
850 > batchL1 // freeze L1User{3}
851 > batchL1 // forge L1User{3}
852 > block
853 `
854
855 chainID := uint16(0)
856 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
857 blocks, err := tc.GenerateBlocks(set)
858 assert.NoError(t, err)
859
860 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
861 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
862
863 // restart nonces of TilContext, as will be set by generating directly
864 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
865 tc.RestartNonces()
866
867 tpc := txprocessor.Config{
868 NLevels: 16,
869 MaxFeeTx: 10,
870 MaxTx: 10,
871 MaxL1Tx: 10,
872 ChainID: chainID,
873 }
874 // batch1 to freeze L1UserTxs
875 l1UserTxs := []common.L1Tx{}
876 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
877 require.NoError(t, err)
878
879 // 3 transfers from the same account
880 batchPoolL2 := `
881 Type: PoolL2
882 PoolTransfer(0) A-B: 10 (126)
883 PoolTransfer(0) A-B: 10 (126) // not enough funds
884 PoolTransfer(0) A-B: 5 (126) // enough funds
885 `
886 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
887 require.NoError(t, err)
888 require.Equal(t, 3, len(poolL2Txs))
889
890 // add the PoolL2Txs to the l2DB
891 addL2Txs(t, txsel, poolL2Txs)
892 // batch 2 to crate some accounts with positive balance, and do 3 L2Tx transfers from account A
893 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
894 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
895 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
896 require.NoError(t, err)
897 assert.Equal(t, 3, len(oL1UserTxs))
898 require.Equal(t, 0, len(oL1CoordTxs))
899 // only 1st L2Tx should be accepted, as:
900 // - 2nd will not be selected as has not enough funds
901 // - 3rd will not be selected as has Nonce=2, and the account Nonce==1
902 // (due the 2nd txs not being accepted)
903 assert.Equal(t, 1, len(oL2Txs))
904 assert.Equal(t, 2, len(discardedL2Txs))
905 assert.Equal(t, common.Nonce(0), oL2Txs[0].Nonce)
906 assert.Equal(t, common.Nonce(1), discardedL2Txs[0].Nonce)
907 assert.Equal(t, common.Nonce(2), discardedL2Txs[1].Nonce)
908 assert.Equal(t, "Tx not selected due to not enough Balance at the sender. "+
909 "Current sender account Balance: 7, Amount+Fee: 11", discardedL2Txs[0].Info)
910 assert.Equal(t, "Tx not selected due to not current Nonce. Tx.Nonce: 2, "+
911 "Account.Nonce: 1", discardedL2Txs[1].Info)
912
913 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
914 txsel.localAccountsDB.CurrentBatch())
915 require.NoError(t, err)
916}
917
918func TestValidTxsWithLowFeeAndInvalidTxsWithHighFee(t *testing.T) {
919 // This test recreates the case where there are
920
921 set := `
922 Type: Blockchain
923
924 CreateAccountDeposit(0) Coord: 0
925 CreateAccountDeposit(0) A: 100
926 CreateAccountDeposit(0) B: 0
927
928 > batchL1 // Batch1: freeze L1User{3}
929 > batchL1 // Batch2: forge L1User{3}
930 > block
931 `
932
933 chainID := uint16(0)
934 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
935 tilCfgExtra := til.ConfigExtra{
936 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
937 CoordUser: "Coord",
938 }
939 blocks, err := tc.GenerateBlocks(set)
940 require.NoError(t, err)
941 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
942 require.NoError(t, err)
943 err = tc.FillBlocksForgedL1UserTxs(blocks)
944 require.NoError(t, err)
945
946 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
947 txsel, historyDB := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
948
949 // Insert blocks into DB
950 for i := range blocks {
951 err = historyDB.AddBlockSCData(&blocks[i])
952 assert.NoError(t, err)
953 }
954
955 err = historyDB.UpdateTokenValue(common.EmptyAddr, 1000)
956 require.NoError(t, err)
957
958 // restart nonces of TilContext, as will be set by generating directly
959 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
960 tc.RestartNonces()
961
962 tpc := txprocessor.Config{
963 NLevels: 16,
964 MaxFeeTx: 5,
965 MaxTx: 5,
966 MaxL1Tx: 3,
967 ChainID: chainID,
968 }
969 // batch1 to freeze L1UserTxs
970 l1UserTxs := []common.L1Tx{}
971 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
972 require.NoError(t, err)
973
974 // batch 2 to crate the accounts (from L1UserTxs)
975 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
976
977 // select L1 & L2 txs
978 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
979 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
980 require.NoError(t, err)
981 require.Equal(t, 3, len(oL1UserTxs))
982 require.Equal(t, 0, len(oL1CoordTxs))
983 require.Equal(t, 0, len(oL2Txs))
984 require.Equal(t, 0, len(discardedL2Txs))
985 require.Equal(t, 0, len(accAuths))
986
987 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
988 txsel.localAccountsDB.CurrentBatch())
989 require.NoError(t, err)
990
991 // batch 3. The A-B txs have lower fee, but are the only ones possible
992 // with the current Accounts Balances, as the B-A tx of amount 40 will
993 // not be included as will be processed first when there is not enough
994 // balance at B (processed first as the TxSelector sorts by Fee and then
995 // by Nonce).
996 batchPoolL2 := `
997 Type: PoolL2
998 PoolTransfer(0) B-A: 40 (130) // B-A txs are only possible once A-B txs are processed
999 PoolTransfer(0) B-A: 1 (126)
1000 PoolTransfer(0) B-A: 1 (126)
1001 PoolTransfer(0) B-A: 1 (126)
1002 PoolTransfer(0) B-A: 1 (126)
1003 PoolTransfer(0) B-A: 1 (126)
1004 PoolTransfer(0) B-A: 1 (126)
1005 PoolTransfer(0) B-A: 1 (126)
1006 PoolTransfer(0) A-B: 20 (20)
1007 PoolTransfer(0) A-B: 25 (150)
1008 PoolTransfer(0) A-B: 20 (20)
1009 `
1010 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
1011 require.NoError(t, err)
1012 require.Equal(t, 11, len(poolL2Txs))
1013 // add the PoolL2Txs to the l2DB
1014 addL2Txs(t, txsel, poolL2Txs)
1015 l1UserTxs = []common.L1Tx{}
1016 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
1017 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
1018 require.NoError(t, err)
1019
1020 require.Equal(t, 0, len(oL1UserTxs))
1021 require.Equal(t, 0, len(oL1CoordTxs))
1022 require.Equal(t, 3, len(oL2Txs)) // the 3 txs A-B
1023 require.Equal(t, 8, len(discardedL2Txs)) // the 8 txs B-A
1024 require.Equal(t, 0, len(accAuths))
1025
1026 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
1027 txsel.localAccountsDB.CurrentBatch())
1028 require.NoError(t, err)
1029
1030 // batch 4. In this Batch, account B has enough balance to send the txs
1031 _, accAuths, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
1032 txsel.GetL1L2TxSelection(tpc, l1UserTxs, nil)
1033 require.NoError(t, err)
1034
1035 require.Equal(t, 0, len(oL1UserTxs))
1036 require.Equal(t, 0, len(oL1CoordTxs))
1037 require.Equal(t, 5, len(oL2Txs))
1038 require.Equal(t, 3, len(discardedL2Txs))
1039 require.Equal(t, 0, len(accAuths))
1040}
1041
1042func TestL1UserFutureTxs(t *testing.T) {
1043 set := `
1044 Type: Blockchain
1045
1046 CreateAccountDeposit(0) Coord: 0
1047 CreateAccountDeposit(0) A: 100
1048
1049 > batchL1 // freeze L1User{2}
1050 CreateAccountDeposit(0) B: 18
1051 > batchL1 // forge L1User{2}, freeze L1User{1}
1052 > batchL1 // forge L1User{1}
1053 > block
1054 `
1055
1056 chainID := uint16(0)
1057 tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
1058 blocks, err := tc.GenerateBlocks(set)
1059 assert.NoError(t, err)
1060
1061 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
1062 txsel, _ := initTest(t, chainID, hermezContractAddr, tc.Users["Coord"])
1063
1064 // restart nonces of TilContext, as will be set by generating directly
1065 // the PoolL2Txs for each specific batch with tc.GeneratePoolL2Txs
1066 tc.RestartNonces()
1067
1068 tpc := txprocessor.Config{
1069 NLevels: 16,
1070 MaxFeeTx: 10,
1071 MaxTx: 10,
1072 MaxL1Tx: 10,
1073 ChainID: chainID,
1074 }
1075 // batch1 to freeze L1UserTxs
1076 l1UserTxs := []common.L1Tx{}
1077 l1UserFutureTxs := []common.L1Tx{}
1078 _, _, _, _, _, _, err = txsel.GetL1L2TxSelection(tpc, l1UserTxs, l1UserFutureTxs)
1079 require.NoError(t, err)
1080
1081 batchPoolL2 := `
1082 Type: PoolL2
1083 PoolTransferToEthAddr(0) A-B: 10 (126)
1084 `
1085 poolL2Txs, err := tc.GeneratePoolL2Txs(batchPoolL2)
1086 require.NoError(t, err)
1087 require.Equal(t, 1, len(poolL2Txs))
1088
1089 // add AccountCreationAuth for B
1090 _ = addAccCreationAuth(t, tc, txsel, chainID, hermezContractAddr, "B")
1091 // add the PoolL2Txs to the l2DB
1092 addL2Txs(t, txsel, poolL2Txs)
1093 // batch 2 to crate some accounts with positive balance, and do 1 L2Tx transfer from account A
1094 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[1].Batch.ForgeL1TxsNum])
1095 l1UserFutureTxs =
1096 til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
1097 require.Equal(t, 2, len(l1UserTxs))
1098 require.Equal(t, 1, len(l1UserFutureTxs))
1099 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err :=
1100 txsel.GetL1L2TxSelection(tpc, l1UserTxs, l1UserFutureTxs)
1101 require.NoError(t, err)
1102 assert.Equal(t, 2, len(oL1UserTxs))
1103 require.Equal(t, 0, len(oL1CoordTxs))
1104 // no L2Tx selected due the L1UserFutureTx, the L2Tx will be processed
1105 // at the next batch once the L1UserTx of CreateAccount B is processed,
1106 // despite that there is an AccountCreationAuth for Account B.
1107 assert.Equal(t, 0, len(oL2Txs))
1108 assert.Equal(t, 1, len(discardedL2Txs))
1109 assert.Equal(t, "Tx not selected (in processTxToEthAddrBJJ) due to L2Tx"+
1110 " discarded at the current batch, as the receiver account does"+
1111 " not exist yet, and there is a L1UserTx that will create that"+
1112 " account in a future batch.",
1113 discardedL2Txs[0].Info)
1114
1115 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
1116 txsel.localAccountsDB.CurrentBatch())
1117 require.NoError(t, err)
1118
1119 l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Rollup.Batches[2].Batch.ForgeL1TxsNum])
1120 l1UserFutureTxs = []common.L1Tx{}
1121 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
1122 txsel.GetL1L2TxSelection(tpc, l1UserTxs, l1UserFutureTxs)
1123 require.NoError(t, err)
1124 assert.Equal(t, 1, len(oL1UserTxs))
1125 require.Equal(t, 0, len(oL1CoordTxs))
1126 // L2Tx selected as now the L1UserTx of CreateAccount B is processed
1127 assert.Equal(t, 1, len(oL2Txs))
1128 assert.Equal(t, 0, len(discardedL2Txs))
1129 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
1130 txsel.localAccountsDB.CurrentBatch())
1131 require.NoError(t, err)
1132
1133 // generate a new L2Tx A-B and check that is processed
1134 poolL2Txs, err = tc.GeneratePoolL2Txs(batchPoolL2)
1135 require.NoError(t, err)
1136 require.Equal(t, 1, len(poolL2Txs))
1137 // add the PoolL2Txs to the l2DB
1138 addL2Txs(t, txsel, poolL2Txs)
1139 _, _, oL1UserTxs, oL1CoordTxs, oL2Txs, discardedL2Txs, err =
1140 txsel.GetL1L2TxSelection(tpc, nil, nil)
1141 require.NoError(t, err)
1142 assert.Equal(t, 0, len(oL1UserTxs))
1143 require.Equal(t, 0, len(oL1CoordTxs))
1144 assert.Equal(t, 1, len(oL2Txs))
1145 assert.Equal(t, 0, len(discardedL2Txs))
1146 err = txsel.l2db.StartForging(common.TxIDsFromPoolL2Txs(oL2Txs),
1147 txsel.localAccountsDB.CurrentBatch())
1148 require.NoError(t, err)
1149}