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