hermez-node/coordinator/coordinator_test.go
coordinator/coordinator_test.goRaw
1package coordinator
2
3import (
4 "context"
5 "fmt"
6 "io/ioutil"
7 "math/big"
8 "os"
9 "testing"
10 "time"
11
12 ethCommon "github.com/ethereum/go-ethereum/common"
13 "github.com/hermeznetwork/hermez-node/batchbuilder"
14 "github.com/hermeznetwork/hermez-node/common"
15 dbUtils "github.com/hermeznetwork/hermez-node/db"
16 "github.com/hermeznetwork/hermez-node/db/historydb"
17 "github.com/hermeznetwork/hermez-node/db/l2db"
18 "github.com/hermeznetwork/hermez-node/db/statedb"
19 "github.com/hermeznetwork/hermez-node/eth"
20 "github.com/hermeznetwork/hermez-node/log"
21 "github.com/hermeznetwork/hermez-node/prover"
22 "github.com/hermeznetwork/hermez-node/synchronizer"
23 "github.com/hermeznetwork/hermez-node/test"
24 "github.com/hermeznetwork/hermez-node/test/til"
25 "github.com/hermeznetwork/hermez-node/txselector"
26 "github.com/hermeznetwork/tracerr"
27 "github.com/iden3/go-merkletree/db/pebble"
28 "github.com/stretchr/testify/assert"
29 "github.com/stretchr/testify/require"
30)
31
32var deleteme = []string{}
33
34func pebbleMakeCheckpoint(source, dest string) error {
35 // Remove dest folder (if it exists) before doing the checkpoint
36 if _, err := os.Stat(dest); !os.IsNotExist(err) {
37 err := os.RemoveAll(dest)
38 if err != nil {
39 return tracerr.Wrap(err)
40 }
41 } else if err != nil && !os.IsNotExist(err) {
42 return tracerr.Wrap(err)
43 }
44
45 sto, err := pebble.NewPebbleStorage(source, false)
46 if err != nil {
47 return tracerr.Wrap(err)
48 }
49 defer func() {
50 errClose := sto.Pebble().Close()
51 if errClose != nil {
52 log.Errorw("Pebble.Close", "err", errClose)
53 }
54 }()
55
56 // execute Checkpoint
57 err = sto.Pebble().Checkpoint(dest)
58 if err != nil {
59 return tracerr.Wrap(err)
60 }
61
62 return nil
63}
64
65func TestMain(m *testing.M) {
66 exitVal := m.Run()
67 for _, dir := range deleteme {
68 if err := os.RemoveAll(dir); err != nil {
69 panic(err)
70 }
71 }
72 os.Exit(exitVal)
73}
74
75var syncDBPath string
76var txSelDBPath string
77var batchBuilderDBPath string
78
79type modules struct {
80 historyDB *historydb.HistoryDB
81 l2DB *l2db.L2DB
82 txSelector *txselector.TxSelector
83 batchBuilder *batchbuilder.BatchBuilder
84 stateDB *statedb.StateDB
85}
86
87var maxL1UserTxs uint64 = 128
88var maxL1Txs uint64 = 256
89var maxL1CoordinatorTxs uint64 = maxL1Txs - maxL1UserTxs
90var maxTxs uint64 = 376
91var nLevels uint32 = 32 //nolint:deadcode,unused
92var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck
93
94func newTestModules(t *testing.T) modules {
95 var err error
96 syncDBPath, err = ioutil.TempDir("", "tmpSyncDB")
97 require.NoError(t, err)
98 deleteme = append(deleteme, syncDBPath)
99 syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, 48)
100 assert.NoError(t, err)
101
102 pass := os.Getenv("POSTGRES_PASS")
103 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
104 require.NoError(t, err)
105 test.WipeDB(db)
106 l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
107 historyDB := historydb.NewHistoryDB(db)
108
109 txSelDBPath, err = ioutil.TempDir("", "tmpTxSelDB")
110 require.NoError(t, err)
111 deleteme = append(deleteme, txSelDBPath)
112
113 coordAccount := &txselector.CoordAccount{ // TODO TMP
114 Addr: ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
115 BJJ: nil,
116 AccountCreationAuth: nil,
117 }
118 txSelector, err := txselector.NewTxSelector(coordAccount, txSelDBPath, syncStateDB, l2DB)
119 assert.NoError(t, err)
120
121 batchBuilderDBPath, err = ioutil.TempDir("", "tmpBatchBuilderDB")
122 require.NoError(t, err)
123 deleteme = append(deleteme, batchBuilderDBPath)
124 batchBuilder, err := batchbuilder.NewBatchBuilder(batchBuilderDBPath, syncStateDB, nil, 0, uint64(nLevels))
125 assert.NoError(t, err)
126
127 return modules{
128 historyDB: historyDB,
129 l2DB: l2DB,
130 txSelector: txSelector,
131 batchBuilder: batchBuilder,
132 stateDB: syncStateDB,
133 }
134}
135
136type timer struct {
137 time int64
138}
139
140func (t *timer) Time() int64 {
141 currentTime := t.time
142 t.time++
143 return currentTime
144}
145
146var bidder = ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
147var forger = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
148
149func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *test.Client,
150 ethClientSetup *test.ClientSetup, modules modules) *Coordinator {
151 debugBatchPath, err := ioutil.TempDir("", "tmpDebugBatch")
152 require.NoError(t, err)
153 deleteme = append(deleteme, debugBatchPath)
154
155 conf := Config{
156 ForgerAddress: forgerAddr,
157 ConfirmBlocks: 5,
158 L1BatchTimeoutPerc: 0.5,
159 EthClientAttempts: 5,
160 EthClientAttemptsDelay: 100 * time.Millisecond,
161 TxManagerCheckInterval: 300 * time.Millisecond,
162 DebugBatchPath: debugBatchPath,
163 }
164 serverProofs := []prover.Client{&prover.MockClient{}, &prover.MockClient{}}
165
166 scConsts := &synchronizer.SCConsts{
167 Rollup: *ethClientSetup.RollupConstants,
168 Auction: *ethClientSetup.AuctionConstants,
169 WDelayer: *ethClientSetup.WDelayerConstants,
170 }
171 initSCVars := &synchronizer.SCVariables{
172 Rollup: *ethClientSetup.RollupVariables,
173 Auction: *ethClientSetup.AuctionVariables,
174 WDelayer: *ethClientSetup.WDelayerVariables,
175 }
176 coord, err := NewCoordinator(conf, modules.historyDB, modules.l2DB, modules.txSelector,
177 modules.batchBuilder, serverProofs, ethClient, scConsts, initSCVars)
178 require.NoError(t, err)
179 return coord
180}
181
182func newTestSynchronizer(t *testing.T, ethClient *test.Client, ethClientSetup *test.ClientSetup,
183 modules modules) *synchronizer.Synchronizer {
184 sync, err := synchronizer.NewSynchronizer(ethClient, modules.historyDB, modules.stateDB,
185 synchronizer.Config{
186 StatsRefreshPeriod: 0 * time.Second,
187 })
188 require.NoError(t, err)
189 return sync
190}
191
192// TestCoordinatorFlow is a test where the coordinator is stared (which means
193// that goroutines are spawned), and ethereum blocks are mined via the
194// test.Client to simulate starting and stopping forging times. This test
195// works without a synchronizer, and no l2txs are inserted in the pool, so all
196// the batches are forged empty. The purpose of this test is to manually
197// observe via the logs that nothing crashes and that the coordinator starts
198// and stops forging at the right blocks.
199func TestCoordinatorFlow(t *testing.T) {
200 if os.Getenv("TEST_COORD_FLOW") == "" {
201 return
202 }
203 ethClientSetup := test.NewClientSetupExample()
204 var timer timer
205 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
206 modules := newTestModules(t)
207 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
208
209 // Bid for slot 2 and 4
210 _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
211 require.NoError(t, err)
212 _, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
213 require.NoError(t, err)
214 _, err = ethClient.AuctionBidSimple(4, big.NewInt(9999))
215 require.NoError(t, err)
216
217 coord.Start()
218 time.Sleep(1 * time.Second)
219
220 waitForSlot := func(slot int64) {
221 for {
222 blockNum, err := ethClient.EthLastBlock()
223 require.NoError(t, err)
224 nextBlockSlot, err := ethClient.AuctionGetSlotNumber(blockNum + 1)
225 require.NoError(t, err)
226 if nextBlockSlot == slot {
227 break
228 }
229 ethClient.CtlMineBlock()
230 time.Sleep(100 * time.Millisecond)
231 var stats synchronizer.Stats
232 stats.Eth.LastBlock = *ethClient.CtlLastBlock()
233 stats.Sync.LastBlock = stats.Eth.LastBlock
234 stats.Eth.LastBatch = ethClient.CtlLastForgedBatch()
235 stats.Sync.LastBatch = stats.Eth.LastBatch
236 canForge, err := ethClient.AuctionCanForge(forger, blockNum+1)
237 require.NoError(t, err)
238 if canForge {
239 // fmt.Println("DBG canForge")
240 stats.Sync.Auction.CurrentSlot.Forger = forger
241 }
242 // Copy stateDB to synchronizer if there was a new batch
243 source := fmt.Sprintf("%v/BatchNum%v", batchBuilderDBPath, stats.Sync.LastBatch)
244 dest := fmt.Sprintf("%v/BatchNum%v", syncDBPath, stats.Sync.LastBatch)
245 if stats.Sync.LastBatch != 0 {
246 if _, err := os.Stat(dest); os.IsNotExist(err) {
247 log.Infow("Making pebble checkpoint for sync",
248 "source", source, "dest", dest)
249 err = pebbleMakeCheckpoint(source, dest)
250 require.NoError(t, err)
251 }
252 }
253 coord.SendMsg(MsgSyncBlock{
254 Stats: stats,
255 })
256 }
257 }
258
259 // NOTE: With the current test, the coordinator will enter in forge
260 // time before the bidded slot because no one else is forging in the
261 // other slots before the slot deadline.
262 // simulate forgeSequence time
263 waitForSlot(2)
264 log.Info("~~~ simulate entering in forge time")
265 time.Sleep(1 * time.Second)
266
267 // simulate going out from forgeSequence
268 waitForSlot(3)
269 log.Info("~~~ simulate going out from forge time")
270 time.Sleep(1 * time.Second)
271
272 // simulate entering forgeSequence time again
273 waitForSlot(4)
274 log.Info("~~~ simulate entering in forge time again")
275 time.Sleep(2 * time.Second)
276
277 // simulate stopping forgerLoop by channel
278 log.Info("~~~ simulate stopping forgerLoop by closing coordinator stopch")
279 coord.Stop()
280 time.Sleep(1 * time.Second)
281}
282
283func TestCoordinatorStartStop(t *testing.T) {
284 ethClientSetup := test.NewClientSetupExample()
285 var timer timer
286 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
287 modules := newTestModules(t)
288 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
289 coord.Start()
290 coord.Stop()
291}
292
293func TestCoordCanForge(t *testing.T) {
294 ethClientSetup := test.NewClientSetupExample()
295 bootForger := ethClientSetup.AuctionVariables.BootCoordinator
296
297 var timer timer
298 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
299 modules := newTestModules(t)
300 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
301 _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
302 require.NoError(t, err)
303 bid, ok := new(big.Int).SetString("12000000000000000000", 10)
304 if !ok {
305 panic("bad bid")
306 }
307 _, err = ethClient.AuctionBidSimple(2, bid)
308 require.NoError(t, err)
309
310 modules2 := newTestModules(t)
311 bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup, modules2)
312
313 assert.Equal(t, forger, coord.cfg.ForgerAddress)
314 assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress)
315 ethBootCoord, err := ethClient.AuctionGetBootCoordinator()
316 require.NoError(t, err)
317 assert.Equal(t, &bootForger, ethBootCoord)
318
319 var stats synchronizer.Stats
320
321 // Slot 0. No bid, so the winner is the boot coordinator
322 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
323 stats.Sync.LastBlock = stats.Eth.LastBlock
324 stats.Sync.Auction.CurrentSlot.Forger = bootForger
325 assert.Equal(t, false, coord.canForge(&stats))
326 assert.Equal(t, true, bootCoord.canForge(&stats))
327
328 // Slot 0. No bid, and we reach the deadline, so anyone can forge
329 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
330 int64(ethClientSetup.AuctionVariables.SlotDeadline)
331 stats.Sync.LastBlock = stats.Eth.LastBlock
332 stats.Sync.Auction.CurrentSlot.Forger = bootForger
333 assert.Equal(t, true, coord.canForge(&stats))
334 assert.Equal(t, true, bootCoord.canForge(&stats))
335
336 // Slot 1. coordinator bid, so the winner is the coordinator
337 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
338 1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
339 stats.Sync.LastBlock = stats.Eth.LastBlock
340 stats.Sync.Auction.CurrentSlot.Forger = forger
341 assert.Equal(t, true, coord.canForge(&stats))
342 assert.Equal(t, false, bootCoord.canForge(&stats))
343}
344
345func TestCoordHandleMsgSyncBlock(t *testing.T) {
346 ethClientSetup := test.NewClientSetupExample()
347 bootForger := ethClientSetup.AuctionVariables.BootCoordinator
348
349 var timer timer
350 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
351 modules := newTestModules(t)
352 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
353 _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
354 require.NoError(t, err)
355 bid, ok := new(big.Int).SetString("11000000000000000000", 10)
356 if !ok {
357 panic("bad bid")
358 }
359 _, err = ethClient.AuctionBidSimple(2, bid)
360 require.NoError(t, err)
361
362 var msg MsgSyncBlock
363 stats := &msg.Stats
364 ctx := context.Background()
365
366 // Slot 0. No bid, so the winner is the boot coordinator
367 // pipelineStarted: false -> false
368 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
369 stats.Sync.LastBlock = stats.Eth.LastBlock
370 stats.Sync.Auction.CurrentSlot.Forger = bootForger
371 assert.Equal(t, false, coord.canForge(stats))
372 require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
373 assert.Nil(t, coord.pipeline)
374
375 // Slot 0. No bid, and we reach the deadline, so anyone can forge
376 // pipelineStarted: false -> true
377 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
378 int64(ethClientSetup.AuctionVariables.SlotDeadline)
379 stats.Sync.LastBlock = stats.Eth.LastBlock
380 stats.Sync.Auction.CurrentSlot.Forger = bootForger
381 assert.Equal(t, true, coord.canForge(stats))
382 require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
383 assert.NotNil(t, coord.pipeline)
384
385 // Slot 0. No bid, and we reach the deadline, so anyone can forge
386 // pipelineStarted: true -> true
387 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
388 int64(ethClientSetup.AuctionVariables.SlotDeadline) + 1
389 stats.Sync.LastBlock = stats.Eth.LastBlock
390 stats.Sync.Auction.CurrentSlot.Forger = bootForger
391 assert.Equal(t, true, coord.canForge(stats))
392 require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
393 assert.NotNil(t, coord.pipeline)
394
395 // Slot 0. No bid, so the winner is the boot coordinator
396 // pipelineStarted: true -> false
397 stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
398 1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
399 stats.Sync.LastBlock = stats.Eth.LastBlock
400 stats.Sync.Auction.CurrentSlot.Forger = bootForger
401 assert.Equal(t, false, coord.canForge(stats))
402 require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
403 assert.Nil(t, coord.pipeline)
404}
405
406func TestPipelineShouldL1L2Batch(t *testing.T) {
407 ethClientSetup := test.NewClientSetupExample()
408
409 var timer timer
410 ctx := context.Background()
411 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
412 modules := newTestModules(t)
413 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
414 pipeline, err := coord.newPipeline(ctx)
415 require.NoError(t, err)
416 pipeline.vars = coord.vars
417
418 // Check that the parameters are the ones we expect and use in this test
419 require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
420 require.Equal(t, int64(9), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
421 l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
422 l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
423
424 var stats synchronizer.Stats
425
426 startBlock := int64(100)
427
428 //
429 // No scheduled L1Batch
430 //
431
432 // Last L1Batch was a long time ago
433 stats.Eth.LastBlock.Num = startBlock
434 stats.Sync.LastBlock = stats.Eth.LastBlock
435 stats.Sync.LastL1BatchBlock = 0
436 pipeline.stats = stats
437 assert.Equal(t, true, pipeline.shouldL1L2Batch())
438
439 stats.Sync.LastL1BatchBlock = startBlock
440
441 // We are are one block before the timeout range * 0.5
442 stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
443 stats.Sync.LastBlock = stats.Eth.LastBlock
444 pipeline.stats = stats
445 assert.Equal(t, false, pipeline.shouldL1L2Batch())
446
447 // We are are at timeout range * 0.5
448 stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
449 stats.Sync.LastBlock = stats.Eth.LastBlock
450 pipeline.stats = stats
451 assert.Equal(t, true, pipeline.shouldL1L2Batch())
452
453 //
454 // Scheduled L1Batch
455 //
456 pipeline.lastScheduledL1BatchBlockNum = startBlock
457 stats.Sync.LastL1BatchBlock = startBlock - 10
458
459 // We are are one block before the timeout range * 0.5
460 stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
461 stats.Sync.LastBlock = stats.Eth.LastBlock
462 pipeline.stats = stats
463 assert.Equal(t, false, pipeline.shouldL1L2Batch())
464
465 // We are are at timeout range * 0.5
466 stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
467 stats.Sync.LastBlock = stats.Eth.LastBlock
468 pipeline.stats = stats
469 assert.Equal(t, true, pipeline.shouldL1L2Batch())
470}
471
472// ethAddTokens adds the tokens from the blocks to the blockchain
473func ethAddTokens(blocks []common.BlockData, client *test.Client) {
474 for _, block := range blocks {
475 for _, token := range block.Rollup.AddedTokens {
476 consts := eth.ERC20Consts{
477 Name: fmt.Sprintf("Token %d", token.TokenID),
478 Symbol: fmt.Sprintf("TK%d", token.TokenID),
479 Decimals: 18,
480 }
481 // tokenConsts[token.TokenID] = consts
482 client.CtlAddERC20(token.EthAddr, consts)
483 }
484 }
485}
486
487const testTokensLen = 3
488const testUsersLen = 4
489
490func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
491 historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
492 // Create a set with `testTokensLen` tokens and for each token
493 // `testUsersLen` accounts.
494 var set []til.Instruction
495 // set = append(set, til.Instruction{Typ: "Blockchain"})
496 for tokenID := 1; tokenID < testTokensLen; tokenID++ {
497 set = append(set, til.Instruction{
498 Typ: til.TypeAddToken,
499 TokenID: common.TokenID(tokenID),
500 })
501 }
502 depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
503 require.True(t, ok)
504 for tokenID := 0; tokenID < testTokensLen; tokenID++ {
505 for user := 0; user < testUsersLen; user++ {
506 set = append(set, til.Instruction{
507 Typ: common.TxTypeCreateAccountDeposit,
508 TokenID: common.TokenID(tokenID),
509 DepositAmount: depositAmount,
510 From: fmt.Sprintf("User%d", user),
511 })
512 }
513 }
514 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
515 set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
516 set = append(set, til.Instruction{Typ: til.TypeNewBlock})
517
518 tc := til.NewContext(common.RollupConstMaxL1UserTx)
519 blocks, err := tc.GenerateBlocksFromInstructions(set)
520 require.NoError(t, err)
521 require.NotNil(t, blocks)
522
523 ethAddTokens(blocks, ethClient)
524 err = ethClient.CtlAddBlocks(blocks)
525 require.NoError(t, err)
526
527 ctx := context.Background()
528 for {
529 syncBlock, discards, err := sync.Sync2(ctx, nil)
530 require.NoError(t, err)
531 require.Nil(t, discards)
532 if syncBlock == nil {
533 break
534 }
535 }
536 dbTokens, err := historyDB.GetAllTokens()
537 require.Nil(t, err)
538 require.Equal(t, testTokensLen, len(dbTokens))
539
540 dbAccounts, err := historyDB.GetAllAccounts()
541 require.Nil(t, err)
542 require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
543
544 sdbAccounts, err := stateDB.GetAccounts()
545 require.Nil(t, err)
546 require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
547
548 return tc
549}
550
551func TestPipeline1(t *testing.T) {
552 ethClientSetup := test.NewClientSetupExample()
553
554 var timer timer
555 ctx := context.Background()
556 ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
557 modules := newTestModules(t)
558 coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
559 sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
560 pipeline, err := coord.newPipeline(ctx)
561 require.NoError(t, err)
562
563 require.NotNil(t, sync)
564 require.NotNil(t, pipeline)
565
566 // preload the synchronier (via the test ethClient) some tokens and
567 // users with positive balances
568 tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
569 syncStats := sync.Stats()
570 batchNum := common.BatchNum(syncStats.Sync.LastBatch)
571 syncSCVars := sync.SCVars()
572
573 // Insert some l2txs in the Pool
574 setPool := `
575Type: PoolL2
576
577PoolTransfer(0) User0-User1: 100 (126)
578PoolTransfer(0) User1-User2: 200 (126)
579PoolTransfer(0) User2-User3: 300 (126)
580 `
581 l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
582 require.NoError(t, err)
583 for _, tx := range l2txs {
584 err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
585 require.NoError(t, err)
586 }
587
588 err = pipeline.reset(batchNum, syncStats.Sync.LastForgeL1TxsNum, &synchronizer.SCVariables{
589 Rollup: *syncSCVars.Rollup,
590 Auction: *syncSCVars.Auction,
591 WDelayer: *syncSCVars.WDelayer,
592 })
593 require.NoError(t, err)
594 // Sanity check
595 sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
596 require.Nil(t, err)
597 require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
598
599 // Sanity check
600 sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
601 require.Nil(t, err)
602 require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
603
604 // Sanity check
605 require.Equal(t, modules.stateDB.MerkleTree().Root(),
606 pipeline.batchBuilder.LocalStateDB().MerkleTree().Root())
607
608 batchNum++
609
610 selectionConfig := &txselector.SelectionConfig{
611 MaxL1UserTxs: maxL1UserTxs,
612 MaxL1CoordinatorTxs: maxL1CoordinatorTxs,
613 ProcessTxsConfig: statedb.ProcessTxsConfig{
614 NLevels: nLevels,
615 MaxFeeTx: maxFeeTxs,
616 MaxTx: uint32(maxTxs),
617 MaxL1Tx: uint32(maxL1Txs),
618 },
619 }
620
621 batchInfo, err := pipeline.forgeBatch(ctx, batchNum, selectionConfig)
622 require.NoError(t, err)
623 assert.Equal(t, 3, len(batchInfo.L2Txs))
624
625 batchNum++
626 batchInfo, err = pipeline.forgeBatch(ctx, batchNum, selectionConfig)
627 require.NoError(t, err)
628 assert.Equal(t, 0, len(batchInfo.L2Txs))
629}
630
631// TODO: Test Reorg
632// TODO: Test Pipeline
633// TODO: Test TxMonitor
634// TODO: Test forgeBatch
635// TODO: Test waitServerProof
636// TODO: Test handleReorg