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