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