hermez-node/synchronizer/synchronizer_test.go
synchronizer/synchronizer_test.goRaw
1package synchronizer
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io/ioutil"
8 "math/big"
9 "os"
10 "sort"
11 "testing"
12
13 ethCommon "github.com/ethereum/go-ethereum/common"
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/statedb"
18 "github.com/hermeznetwork/hermez-node/eth"
19 "github.com/hermeznetwork/hermez-node/test"
20 "github.com/hermeznetwork/hermez-node/test/til"
21 "github.com/jinzhu/copier"
22 "github.com/stretchr/testify/assert"
23 "github.com/stretchr/testify/require"
24)
25
26var tokenConsts = map[common.TokenID]eth.ERC20Consts{}
27
28type timer struct {
29 time int64
30}
31
32func (t *timer) Time() int64 {
33 currentTime := t.time
34 t.time++
35 return currentTime
36}
37
38func accountsCmp(accounts []common.Account) func(i, j int) bool {
39 return func(i, j int) bool { return accounts[i].Idx < accounts[j].Idx }
40}
41
42// Check Sync output and HistoryDB state against expected values generated by
43// til
44func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBlock *common.BlockData) {
45 // Check Blocks
46 dbBlocks, err := s.historyDB.GetAllBlocks()
47 require.Nil(t, err)
48 dbBlocks = dbBlocks[1:] // ignore block 0, added by default in the DB
49 assert.Equal(t, blockNum, len(dbBlocks))
50 assert.Equal(t, int64(blockNum), dbBlocks[blockNum-1].Num)
51 assert.NotEqual(t, dbBlocks[blockNum-1].Hash, dbBlocks[blockNum-2].Hash)
52 assert.Greater(t, dbBlocks[blockNum-1].Timestamp.Unix(), dbBlocks[blockNum-2].Timestamp.Unix())
53
54 // Check Tokens
55 assert.Equal(t, len(block.Rollup.AddedTokens), len(syncBlock.Rollup.AddedTokens))
56 dbTokens, err := s.historyDB.GetAllTokens()
57 require.Nil(t, err)
58 dbTokens = dbTokens[1:] // ignore token 0, added by default in the DB
59 for i, token := range block.Rollup.AddedTokens {
60 dbToken := dbTokens[i]
61 syncToken := syncBlock.Rollup.AddedTokens[i]
62
63 assert.Equal(t, block.Block.Num, syncToken.EthBlockNum)
64 assert.Equal(t, token.TokenID, syncToken.TokenID)
65 assert.Equal(t, token.EthAddr, syncToken.EthAddr)
66 tokenConst := tokenConsts[token.TokenID]
67 assert.Equal(t, tokenConst.Name, syncToken.Name)
68 assert.Equal(t, tokenConst.Symbol, syncToken.Symbol)
69 assert.Equal(t, tokenConst.Decimals, syncToken.Decimals)
70
71 var tokenCpy historydb.TokenWithUSD
72 //nolint:gosec
73 require.Nil(t, copier.Copy(&tokenCpy, &token)) // copy common.Token to historydb.TokenWithUSD
74 require.Nil(t, copier.Copy(&tokenCpy, &tokenConst)) // copy common.Token to historydb.TokenWithUSD
75 tokenCpy.ItemID = dbToken.ItemID // we don't care about ItemID
76 assert.Equal(t, tokenCpy, dbToken)
77 }
78
79 // Check L1UserTxs
80 assert.Equal(t, len(block.Rollup.L1UserTxs), len(syncBlock.Rollup.L1UserTxs))
81 dbL1UserTxs, err := s.historyDB.GetAllL1UserTxs()
82 require.Nil(t, err)
83 // Ignore BatchNum in syncBlock.L1UserTxs because this value is set by the HistoryDB
84 for i := range syncBlock.Rollup.L1UserTxs {
85 syncBlock.Rollup.L1UserTxs[i].BatchNum = block.Rollup.L1UserTxs[i].BatchNum
86 }
87 assert.Equal(t, block.Rollup.L1UserTxs, syncBlock.Rollup.L1UserTxs)
88 for _, tx := range block.Rollup.L1UserTxs {
89 var dbTx *common.L1Tx
90 // Find tx in DB output
91 for _, _dbTx := range dbL1UserTxs {
92 if *tx.ToForgeL1TxsNum == *_dbTx.ToForgeL1TxsNum &&
93 tx.Position == _dbTx.Position {
94 dbTx = new(common.L1Tx)
95 *dbTx = _dbTx
96 break
97 }
98 }
99 assert.Equal(t, &tx, dbTx) //nolint:gosec
100 }
101
102 // Check Batches
103 assert.Equal(t, len(block.Rollup.Batches), len(syncBlock.Rollup.Batches))
104 dbBatches, err := s.historyDB.GetAllBatches()
105 require.Nil(t, err)
106
107 dbL1CoordinatorTxs, err := s.historyDB.GetAllL1CoordinatorTxs()
108 require.Nil(t, err)
109 dbL2Txs, err := s.historyDB.GetAllL2Txs()
110 require.Nil(t, err)
111 dbExits, err := s.historyDB.GetAllExits()
112 require.Nil(t, err)
113 // dbL1CoordinatorTxs := []common.L1Tx{}
114 for i, batch := range block.Rollup.Batches {
115 var dbBatch *common.Batch
116 // Find batch in DB output
117 for _, _dbBatch := range dbBatches {
118 if batch.Batch.BatchNum == _dbBatch.BatchNum {
119 dbBatch = new(common.Batch)
120 *dbBatch = _dbBatch
121 break
122 }
123 }
124 syncBatch := syncBlock.Rollup.Batches[i]
125
126 // We don't care about TotalFeesUSD. Use the syncBatch that
127 // has a TotalFeesUSD inserted by the HistoryDB
128 batch.Batch.TotalFeesUSD = syncBatch.Batch.TotalFeesUSD
129 assert.Equal(t, batch.CreatedAccounts, syncBatch.CreatedAccounts)
130 batch.Batch.NumAccounts = len(batch.CreatedAccounts)
131
132 // Test field by field to facilitate debugging of errors
133 assert.Equal(t, batch.L1CoordinatorTxs, syncBatch.L1CoordinatorTxs)
134 assert.Equal(t, batch.L2Txs, syncBatch.L2Txs)
135 // In exit tree, we only check AccountIdx and Balance, because
136 // it's what we have precomputed before.
137 for j := range batch.ExitTree {
138 exit := &batch.ExitTree[j]
139 assert.Equal(t, exit.AccountIdx, syncBatch.ExitTree[j].AccountIdx)
140 assert.Equal(t, exit.Balance, syncBatch.ExitTree[j].Balance)
141 *exit = syncBatch.ExitTree[j]
142 }
143 assert.Equal(t, batch.Batch, syncBatch.Batch)
144 assert.Equal(t, batch, syncBatch)
145 assert.Equal(t, &batch.Batch, dbBatch) //nolint:gosec
146
147 // Check L1CoordinatorTxs from DB
148 for _, tx := range batch.L1CoordinatorTxs {
149 var dbTx *common.L1Tx
150 // Find tx in DB output
151 for _, _dbTx := range dbL1CoordinatorTxs {
152 if *tx.BatchNum == *_dbTx.BatchNum &&
153 tx.Position == _dbTx.Position {
154 dbTx = new(common.L1Tx)
155 *dbTx = _dbTx
156 break
157 }
158 }
159 assert.Equal(t, &tx, dbTx) //nolint:gosec
160 }
161
162 // Check L2Txs from DB
163 for _, tx := range batch.L2Txs {
164 var dbTx *common.L2Tx
165 // Find tx in DB output
166 for _, _dbTx := range dbL2Txs {
167 if tx.BatchNum == _dbTx.BatchNum &&
168 tx.Position == _dbTx.Position {
169 dbTx = new(common.L2Tx)
170 *dbTx = _dbTx
171 break
172 }
173 }
174 assert.Equal(t, &tx, dbTx) //nolint:gosec
175 }
176
177 // Check Exits from DB
178 for _, exit := range batch.ExitTree {
179 var dbExit *common.ExitInfo
180 // Find exit in DB output
181 for _, _dbExit := range dbExits {
182 if exit.BatchNum == _dbExit.BatchNum &&
183 exit.AccountIdx == _dbExit.AccountIdx {
184 dbExit = new(common.ExitInfo)
185 *dbExit = _dbExit
186 break
187 }
188 }
189 // Compare MerkleProof in JSON because unmarshaled 0
190 // big.Int leaves the internal big.Int array at nil,
191 // and gives trouble when comparing big.Int with
192 // internal big.Int array != nil but empty.
193 mtp, err := json.Marshal(exit.MerkleProof)
194 require.Nil(t, err)
195 dbMtp, err := json.Marshal(dbExit.MerkleProof)
196 require.Nil(t, err)
197 assert.Equal(t, mtp, dbMtp)
198 dbExit.MerkleProof = exit.MerkleProof
199 assert.Equal(t, &exit, dbExit) //nolint:gosec
200 }
201 }
202
203 // Compare accounts from HistoryDB with StateDB (they should match)
204 dbAccounts, err := s.historyDB.GetAllAccounts()
205 require.Nil(t, err)
206 sdbAccounts, err := s.stateDB.GetAccounts()
207 require.Nil(t, err)
208 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
209}
210
211func assertEqualAccountsHistoryDBStateDB(t *testing.T, hdbAccs, sdbAccs []common.Account) {
212 assert.Equal(t, len(hdbAccs), len(sdbAccs))
213 sort.SliceStable(hdbAccs, accountsCmp(hdbAccs))
214 sort.SliceStable(sdbAccs, accountsCmp(sdbAccs))
215 for i := range hdbAccs {
216 hdbAcc := hdbAccs[i]
217 sdbAcc := sdbAccs[i]
218 assert.Equal(t, hdbAcc.Idx, sdbAcc.Idx)
219 assert.Equal(t, hdbAcc.TokenID, sdbAcc.TokenID)
220 assert.Equal(t, hdbAcc.EthAddr, sdbAcc.EthAddr)
221 assert.Equal(t, hdbAcc.PublicKey, sdbAcc.PublicKey)
222 }
223}
224
225// ethAddTokens adds the tokens from the blocks to the blockchain
226func ethAddTokens(blocks []common.BlockData, client *test.Client) {
227 for _, block := range blocks {
228 for _, token := range block.Rollup.AddedTokens {
229 consts := eth.ERC20Consts{
230 Name: fmt.Sprintf("Token %d", token.TokenID),
231 Symbol: fmt.Sprintf("TK%d", token.TokenID),
232 Decimals: 18,
233 }
234 tokenConsts[token.TokenID] = consts
235 client.CtlAddERC20(token.EthAddr, consts)
236 }
237 }
238}
239
240// ethAddBlocks adds block data to the smart contracts
241func ethAddBlocks(t *testing.T, blocks []common.BlockData,
242 client *test.Client, clientSetup *test.ClientSetup) {
243 for _, block := range blocks {
244 for _, token := range block.Rollup.AddedTokens {
245 _, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
246 require.Nil(t, err)
247 }
248 for _, tx := range block.Rollup.L1UserTxs {
249 client.CtlSetAddr(tx.FromEthAddr)
250 _, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount, tx.Amount,
251 uint32(tx.TokenID), int64(tx.ToIdx))
252 require.Nil(t, err)
253 }
254 client.CtlSetAddr(clientSetup.AuctionVariables.BootCoordinator)
255 for _, batch := range block.Rollup.Batches {
256 _, err := client.RollupForgeBatch(ð.RollupForgeBatchArgs{
257 NewLastIdx: batch.Batch.LastIdx,
258 NewStRoot: batch.Batch.StateRoot,
259 NewExitRoot: batch.Batch.ExitRoot,
260 L1CoordinatorTxs: batch.L1CoordinatorTxs,
261 L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
262 L2TxsData: batch.L2Txs,
263 FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
264 // Circuit selector
265 VerifierIdx: 0, // Intentionally empty
266 L1Batch: batch.L1Batch,
267 ProofA: [2]*big.Int{}, // Intentionally empty
268 ProofB: [2][2]*big.Int{}, // Intentionally empty
269 ProofC: [2]*big.Int{}, // Intentionally empty
270 })
271 require.Nil(t, err)
272 }
273 // Mine block and sync
274 client.CtlMineBlock()
275 }
276}
277
278func TestSync(t *testing.T) {
279 //
280 // Setup
281 //
282
283 ctx := context.Background()
284 // Int State DB
285 dir, err := ioutil.TempDir("", "tmpdb")
286 require.Nil(t, err)
287 defer assert.Nil(t, os.RemoveAll(dir))
288
289 stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
290 assert.Nil(t, err)
291
292 // Init History DB
293 pass := os.Getenv("POSTGRES_PASS")
294 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
295 require.Nil(t, err)
296 historyDB := historydb.NewHistoryDB(db)
297 // Clear DB
298 test.WipeDB(historyDB.DB())
299
300 // Init eth client
301 var timer timer
302 clientSetup := test.NewClientSetupExample()
303 bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
304 client := test.NewClient(true, &timer, ðCommon.Address{}, clientSetup)
305
306 // Create Synchronizer
307 s, err := NewSynchronizer(client, historyDB, stateDB, Config{
308 StartBlockNum: ConfigStartBlockNum{
309 Rollup: 1,
310 Auction: 1,
311 WDelayer: 1,
312 },
313 InitialVariables: SCVariables{
314 Rollup: *clientSetup.RollupVariables,
315 Auction: *clientSetup.AuctionVariables,
316 WDelayer: *clientSetup.WDelayerVariables,
317 },
318 })
319 require.Nil(t, err)
320
321 //
322 // First Sync from an initial state
323 //
324 var vars struct {
325 Rollup *common.RollupVariables
326 Auction *common.AuctionVariables
327 WDelayer *common.WDelayerVariables
328 }
329 stats := s.Stats()
330 assert.Equal(t, false, stats.Synced())
331
332 // Test Sync for rollup genesis block
333 syncBlock, discards, err := s.Sync2(ctx, nil)
334 require.Nil(t, err)
335 require.Nil(t, discards)
336 require.NotNil(t, syncBlock)
337 require.Nil(t, syncBlock.Rollup.Vars)
338 require.Nil(t, syncBlock.Auction.Vars)
339 require.Nil(t, syncBlock.WDelayer.Vars)
340 assert.Equal(t, int64(1), syncBlock.Block.Num)
341 stats = s.Stats()
342 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
343 assert.Equal(t, int64(1), stats.Eth.LastBlock.Num)
344 assert.Equal(t, int64(1), stats.Sync.LastBlock.Num)
345 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
346 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
347 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
348 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
349
350 dbBlocks, err := s.historyDB.GetAllBlocks()
351 require.Nil(t, err)
352 assert.Equal(t, 2, len(dbBlocks))
353 assert.Equal(t, int64(1), dbBlocks[1].Num)
354
355 // Sync again and expect no new blocks
356 syncBlock, discards, err = s.Sync2(ctx, nil)
357 require.Nil(t, err)
358 require.Nil(t, discards)
359 require.Nil(t, syncBlock)
360
361 //
362 // Generate blockchain and smart contract data, and fill the test smart contracts
363 //
364
365 // Generate blockchain data with til
366 set1 := `
367 Type: Blockchain
368
369 AddToken(1)
370 AddToken(2)
371 AddToken(3)
372
373 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
374 CreateAccountDeposit(2) A: 2000 // Idx=256+3=259
375 CreateAccountDeposit(1) D: 500 // Idx=256+4=260
376 CreateAccountDeposit(2) B: 500 // Idx=256+5=261
377 CreateAccountDeposit(2) C: 500 // Idx=256+6=262
378
379 CreateAccountCoordinator(1) A // Idx=256+0=256
380 CreateAccountCoordinator(1) B // Idx=256+1=257
381
382 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
383 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
384 > block // blockNum=2
385
386 CreateAccountDepositTransfer(1) E-A: 1000, 200 // Idx=256+7=263
387 ForceExit(1) A: 100
388 ForceExit(1) B: 80
389 ForceTransfer(1) A-D: 100
390
391 Transfer(1) C-A: 100 (200)
392 Exit(1) C: 50 (200)
393 Exit(1) D: 30 (200)
394
395 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
396 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
397 > block // blockNum=3
398 `
399 tc := til.NewContext(common.RollupConstMaxL1UserTx)
400 tilCfgExtra := til.ConfigExtra{
401 BootCoordAddr: bootCoordAddr,
402 CoordUser: "A",
403 }
404 blocks, err := tc.GenerateBlocks(set1)
405 require.Nil(t, err)
406 // Sanity check
407 require.Equal(t, 2, len(blocks))
408 // blocks 0 (blockNum=2)
409 i := 0
410 require.Equal(t, 2, int(blocks[i].Block.Num))
411 require.Equal(t, 3, len(blocks[i].Rollup.AddedTokens))
412 require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
413 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
414 require.Equal(t, 2, len(blocks[i].Rollup.Batches[0].L1CoordinatorTxs))
415 // blocks 1 (blockNum=3)
416 i = 1
417 require.Equal(t, 3, int(blocks[i].Block.Num))
418 require.Equal(t, 4, len(blocks[i].Rollup.L1UserTxs))
419 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
420 require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
421
422 // Generate extra required data
423 ethAddTokens(blocks, client)
424
425 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
426 assert.Nil(t, err)
427 tc.FillBlocksL1UserTxsBatchNum(blocks)
428
429 // Add block data to the smart contracts
430 ethAddBlocks(t, blocks, client, clientSetup)
431
432 //
433 // Sync to synchronize the current state from the test smart contracts,
434 // and check the outcome
435 //
436
437 // Block 2
438
439 syncBlock, discards, err = s.Sync2(ctx, nil)
440 require.Nil(t, err)
441 require.Nil(t, discards)
442 require.NotNil(t, syncBlock)
443 assert.Nil(t, syncBlock.Rollup.Vars)
444 assert.Nil(t, syncBlock.Auction.Vars)
445 assert.Nil(t, syncBlock.WDelayer.Vars)
446 assert.Equal(t, int64(2), syncBlock.Block.Num)
447 stats = s.Stats()
448 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
449 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
450 assert.Equal(t, int64(2), stats.Sync.LastBlock.Num)
451
452 checkSyncBlock(t, s, 2, &blocks[0], syncBlock)
453
454 // Block 3
455
456 syncBlock, discards, err = s.Sync2(ctx, nil)
457 require.Nil(t, err)
458 require.Nil(t, discards)
459 require.NotNil(t, syncBlock)
460 assert.Nil(t, syncBlock.Rollup.Vars)
461 assert.Nil(t, syncBlock.Auction.Vars)
462 assert.Nil(t, syncBlock.WDelayer.Vars)
463 assert.Equal(t, int64(3), syncBlock.Block.Num)
464 stats = s.Stats()
465 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
466 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
467 assert.Equal(t, int64(3), stats.Sync.LastBlock.Num)
468
469 checkSyncBlock(t, s, 3, &blocks[1], syncBlock)
470
471 // Block 4
472 // Generate 2 withdraws manually
473 _, err = client.RollupWithdrawMerkleProof(tc.Users["A"].BJJ.Public(), 1, 4, 256, big.NewInt(100), []*big.Int{}, true)
474 require.Nil(t, err)
475 _, err = client.RollupWithdrawMerkleProof(tc.Users["C"].BJJ.Public(), 1, 3, 258, big.NewInt(50), []*big.Int{}, false)
476 require.Nil(t, err)
477 client.CtlMineBlock()
478
479 syncBlock, discards, err = s.Sync2(ctx, nil)
480 require.Nil(t, err)
481 require.Nil(t, discards)
482 require.NotNil(t, syncBlock)
483 assert.Nil(t, syncBlock.Rollup.Vars)
484 assert.Nil(t, syncBlock.Auction.Vars)
485 assert.Nil(t, syncBlock.WDelayer.Vars)
486 assert.Equal(t, int64(4), syncBlock.Block.Num)
487 stats = s.Stats()
488 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
489 assert.Equal(t, int64(4), stats.Eth.LastBlock.Num)
490 assert.Equal(t, int64(4), stats.Sync.LastBlock.Num)
491 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
492 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
493 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
494 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
495
496 dbExits, err := s.historyDB.GetAllExits()
497 require.Nil(t, err)
498 foundA1, foundC1 := false, false
499 for _, exit := range dbExits {
500 if exit.AccountIdx == 256 && exit.BatchNum == 4 {
501 foundA1 = true
502 assert.Equal(t, int64(4), *exit.InstantWithdrawn)
503 }
504 if exit.AccountIdx == 258 && exit.BatchNum == 3 {
505 foundC1 = true
506 assert.Equal(t, int64(4), *exit.DelayedWithdrawRequest)
507 }
508 }
509 assert.True(t, foundA1)
510 assert.True(t, foundC1)
511
512 // Block 5
513 // Update variables manually
514 rollupVars, auctionVars, wDelayerVars, err := s.historyDB.GetSCVars()
515 require.Nil(t, err)
516 rollupVars.ForgeL1L2BatchTimeout = 42
517 _, err = client.RollupUpdateForgeL1L2BatchTimeout(rollupVars.ForgeL1L2BatchTimeout)
518 require.Nil(t, err)
519
520 auctionVars.OpenAuctionSlots = 17
521 _, err = client.AuctionSetOpenAuctionSlots(auctionVars.OpenAuctionSlots)
522 require.Nil(t, err)
523
524 wDelayerVars.WithdrawalDelay = 99
525 _, err = client.WDelayerChangeWithdrawalDelay(wDelayerVars.WithdrawalDelay)
526 require.Nil(t, err)
527
528 client.CtlMineBlock()
529
530 syncBlock, discards, err = s.Sync2(ctx, nil)
531 require.Nil(t, err)
532 require.Nil(t, discards)
533 require.NotNil(t, syncBlock)
534 assert.NotNil(t, syncBlock.Rollup.Vars)
535 assert.NotNil(t, syncBlock.Auction.Vars)
536 assert.NotNil(t, syncBlock.WDelayer.Vars)
537 assert.Equal(t, int64(5), syncBlock.Block.Num)
538 stats = s.Stats()
539 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
540 assert.Equal(t, int64(5), stats.Eth.LastBlock.Num)
541 assert.Equal(t, int64(5), stats.Sync.LastBlock.Num)
542 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
543 assert.NotEqual(t, clientSetup.RollupVariables, vars.Rollup)
544 assert.NotEqual(t, clientSetup.AuctionVariables, vars.Auction)
545 assert.NotEqual(t, clientSetup.WDelayerVariables, vars.WDelayer)
546
547 dbRollupVars, dbAuctionVars, dbWDelayerVars, err := s.historyDB.GetSCVars()
548 require.Nil(t, err)
549 // Set EthBlockNum for Vars to the blockNum in which they were updated (should be 5)
550 rollupVars.EthBlockNum = syncBlock.Block.Num
551 auctionVars.EthBlockNum = syncBlock.Block.Num
552 wDelayerVars.EthBlockNum = syncBlock.Block.Num
553 assert.Equal(t, rollupVars, dbRollupVars)
554 assert.Equal(t, auctionVars, dbAuctionVars)
555 assert.Equal(t, wDelayerVars, dbWDelayerVars)
556
557 //
558 // Reorg test
559 //
560
561 // Redo blocks 2-5 (as a reorg) only leaving:
562 // - 2 create account transactions
563 // - 2 add tokens
564 // We add a 6th block so that the synchronizer can detect the reorg
565 set2 := `
566 Type: Blockchain
567
568 AddToken(1)
569 AddToken(2)
570
571 CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
572
573 CreateAccountCoordinator(1) A // Idx=256+0=256
574
575 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
576 > batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
577 > block // blockNum=2
578 > block // blockNum=3
579 > block // blockNum=4
580 > block // blockNum=5
581 > block // blockNum=6
582 `
583 tc = til.NewContext(common.RollupConstMaxL1UserTx)
584 tilCfgExtra = til.ConfigExtra{
585 BootCoordAddr: bootCoordAddr,
586 CoordUser: "A",
587 }
588 blocks, err = tc.GenerateBlocks(set2)
589 require.Nil(t, err)
590
591 for i := 0; i < 4; i++ {
592 client.CtlRollback()
593 }
594 block := client.CtlLastBlock()
595 require.Equal(t, int64(1), block.Num)
596
597 // Generate extra required data
598 ethAddTokens(blocks, client)
599
600 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
601 assert.Nil(t, err)
602 tc.FillBlocksL1UserTxsBatchNum(blocks)
603
604 // Add block data to the smart contracts
605 ethAddBlocks(t, blocks, client, clientSetup)
606
607 // First sync detects the reorg and discards 4 blocks
608 syncBlock, discards, err = s.Sync2(ctx, nil)
609 require.Nil(t, err)
610 expetedDiscards := int64(4)
611 require.Equal(t, &expetedDiscards, discards)
612 require.Nil(t, syncBlock)
613 stats = s.Stats()
614 assert.Equal(t, false, stats.Synced())
615 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
616 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
617 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
618 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
619 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
620
621 // At this point, the DB only has data up to block 1
622 dbBlock, err := s.historyDB.GetLastBlock()
623 require.Nil(t, err)
624 assert.Equal(t, int64(1), dbBlock.Num)
625
626 // Accounts in HistoryDB and StateDB must be empty
627 dbAccounts, err := s.historyDB.GetAllAccounts()
628 require.Nil(t, err)
629 sdbAccounts, err := s.stateDB.GetAccounts()
630 require.Nil(t, err)
631 assert.Equal(t, 0, len(dbAccounts))
632 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
633
634 // Sync blocks 2-6
635 for i := 0; i < 5; i++ {
636 syncBlock, discards, err = s.Sync2(ctx, nil)
637 require.Nil(t, err)
638 require.Nil(t, discards)
639 require.NotNil(t, syncBlock)
640 assert.Nil(t, syncBlock.Rollup.Vars)
641 assert.Nil(t, syncBlock.Auction.Vars)
642 assert.Nil(t, syncBlock.WDelayer.Vars)
643 assert.Equal(t, int64(2+i), syncBlock.Block.Num)
644
645 stats = s.Stats()
646 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
647 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
648 assert.Equal(t, int64(2+i), stats.Sync.LastBlock.Num)
649 if i == 4 {
650 assert.Equal(t, true, stats.Synced())
651 } else {
652 assert.Equal(t, false, stats.Synced())
653 }
654
655 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
656 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
657 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
658 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
659 }
660
661 dbBlock, err = s.historyDB.GetLastBlock()
662 require.Nil(t, err)
663 assert.Equal(t, int64(6), dbBlock.Num)
664
665 // Accounts in HistoryDB and StateDB is only 2 entries
666 dbAccounts, err = s.historyDB.GetAllAccounts()
667 require.Nil(t, err)
668 sdbAccounts, err = s.stateDB.GetAccounts()
669 require.Nil(t, err)
670 assert.Equal(t, 2, len(dbAccounts))
671 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
672}