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