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