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
273// ethAddBlocks adds block data to the smart contracts
274func ethAddBlocks(t *testing.T, blocks []common.BlockData,
275 client *test.Client, clientSetup *test.ClientSetup) {
276 for _, block := range blocks {
277 for _, token := range block.Rollup.AddedTokens {
278 _, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
279 require.Nil(t, err)
280 }
281 for _, tx := range block.Rollup.L1UserTxs {
282 client.CtlSetAddr(tx.FromEthAddr)
283 _, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
284 uint32(tx.TokenID), int64(tx.ToIdx))
285 require.Nil(t, err)
286 }
287 client.CtlSetAddr(clientSetup.AuctionVariables.BootCoordinator)
288 for _, batch := range block.Rollup.Batches {
289 _, err := client.RollupForgeBatch(ð.RollupForgeBatchArgs{
290 NewLastIdx: batch.Batch.LastIdx,
291 NewStRoot: batch.Batch.StateRoot,
292 NewExitRoot: batch.Batch.ExitRoot,
293 L1CoordinatorTxs: batch.L1CoordinatorTxs,
294 L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
295 L2TxsData: batch.L2Txs,
296 FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
297 // Circuit selector
298 VerifierIdx: 0, // Intentionally empty
299 L1Batch: batch.L1Batch,
300 ProofA: [2]*big.Int{}, // Intentionally empty
301 ProofB: [2][2]*big.Int{}, // Intentionally empty
302 ProofC: [2]*big.Int{}, // Intentionally empty
303 })
304 require.Nil(t, err)
305 }
306 // Mine block and sync
307 client.CtlMineBlock()
308 }
309}
310
311func TestSync(t *testing.T) {
312 //
313 // Setup
314 //
315
316 ctx := context.Background()
317 // Int State DB
318 dir, err := ioutil.TempDir("", "tmpdb")
319 require.Nil(t, err)
320 defer assert.Nil(t, os.RemoveAll(dir))
321
322 stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
323 assert.NoError(t, err)
324
325 // Init History DB
326 pass := os.Getenv("POSTGRES_PASS")
327 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
328 require.Nil(t, err)
329 historyDB := historydb.NewHistoryDB(db)
330 // Clear DB
331 test.WipeDB(historyDB.DB())
332
333 // Init eth client
334 var timer timer
335 clientSetup := test.NewClientSetupExample()
336 bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
337 client := test.NewClient(true, &timer, ðCommon.Address{}, clientSetup)
338
339 // Create Synchronizer
340 s, err := NewSynchronizer(client, historyDB, stateDB, Config{
341 StartBlockNum: ConfigStartBlockNum{
342 Rollup: 1,
343 Auction: 1,
344 WDelayer: 1,
345 },
346 InitialVariables: SCVariables{
347 Rollup: *clientSetup.RollupVariables,
348 Auction: *clientSetup.AuctionVariables,
349 WDelayer: *clientSetup.WDelayerVariables,
350 },
351 })
352 require.Nil(t, err)
353
354 //
355 // First Sync from an initial state
356 //
357 stats := s.Stats()
358 assert.Equal(t, false, stats.Synced())
359
360 // Test Sync for rollup genesis block
361 syncBlock, discards, err := s.Sync2(ctx, nil)
362 require.Nil(t, err)
363 require.Nil(t, discards)
364 require.NotNil(t, syncBlock)
365 require.Nil(t, syncBlock.Rollup.Vars)
366 require.Nil(t, syncBlock.Auction.Vars)
367 require.Nil(t, syncBlock.WDelayer.Vars)
368 assert.Equal(t, int64(1), syncBlock.Block.Num)
369 stats = s.Stats()
370 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
371 assert.Equal(t, int64(1), stats.Eth.LastBlock.Num)
372 assert.Equal(t, int64(1), stats.Sync.LastBlock.Num)
373 vars := s.SCVars()
374 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
375 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
376 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
377
378 dbBlocks, err := s.historyDB.GetAllBlocks()
379 require.Nil(t, err)
380 assert.Equal(t, 2, len(dbBlocks))
381 assert.Equal(t, int64(1), dbBlocks[1].Num)
382
383 // Sync again and expect no new blocks
384 syncBlock, discards, err = s.Sync2(ctx, nil)
385 require.Nil(t, err)
386 require.Nil(t, discards)
387 require.Nil(t, syncBlock)
388
389 //
390 // Generate blockchain and smart contract data, and fill the test smart contracts
391 //
392
393 // Generate blockchain data with til
394 set1 := `
395 Type: Blockchain
396
397 AddToken(1)
398 AddToken(2)
399 AddToken(3)
400
401 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
402 CreateAccountDeposit(2) A: 2000 // Idx=256+3=259
403 CreateAccountDeposit(1) D: 500 // Idx=256+4=260
404 CreateAccountDeposit(2) B: 500 // Idx=256+5=261
405 CreateAccountDeposit(2) C: 500 // Idx=256+6=262
406
407 CreateAccountCoordinator(1) A // Idx=256+0=256
408 CreateAccountCoordinator(1) B // Idx=256+1=257
409
410 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
411 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
412 > block // blockNum=2
413
414 CreateAccountDepositTransfer(1) E-A: 1000, 200 // Idx=256+7=263
415 ForceTransfer(1) C-B: 80
416 ForceExit(1) A: 100
417 ForceExit(1) B: 80
418 ForceTransfer(1) A-D: 100
419
420 Transfer(1) C-A: 100 (200)
421 Exit(1) C: 50 (200)
422 Exit(1) D: 30 (200)
423
424 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
425 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
426 > block // blockNum=3
427 `
428 tc := til.NewContext(common.RollupConstMaxL1UserTx)
429 tilCfgExtra := til.ConfigExtra{
430 BootCoordAddr: bootCoordAddr,
431 CoordUser: "A",
432 }
433 blocks, err := tc.GenerateBlocks(set1)
434 require.Nil(t, err)
435 // Sanity check
436 require.Equal(t, 2, len(blocks))
437 // blocks 0 (blockNum=2)
438 i := 0
439 require.Equal(t, 2, int(blocks[i].Block.Num))
440 require.Equal(t, 3, len(blocks[i].Rollup.AddedTokens))
441 require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
442 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
443 require.Equal(t, 2, len(blocks[i].Rollup.Batches[0].L1CoordinatorTxs))
444 // blocks 1 (blockNum=3)
445 i = 1
446 require.Equal(t, 3, int(blocks[i].Block.Num))
447 require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
448 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
449 require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
450
451 // Generate extra required data
452 ethAddTokens(blocks, client)
453
454 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
455 assert.NoError(t, err)
456 tc.FillBlocksL1UserTxsBatchNum(blocks)
457 err = tc.FillBlocksForgedL1UserTxs(blocks)
458 assert.NoError(t, err)
459
460 // Add block data to the smart contracts
461 ethAddBlocks(t, blocks, client, clientSetup)
462
463 //
464 // Sync to synchronize the current state from the test smart contracts,
465 // and check the outcome
466 //
467
468 // Block 2
469
470 syncBlock, discards, err = s.Sync2(ctx, nil)
471 require.Nil(t, err)
472 require.Nil(t, discards)
473 require.NotNil(t, syncBlock)
474 assert.Nil(t, syncBlock.Rollup.Vars)
475 assert.Nil(t, syncBlock.Auction.Vars)
476 assert.Nil(t, syncBlock.WDelayer.Vars)
477 assert.Equal(t, int64(2), syncBlock.Block.Num)
478 stats = s.Stats()
479 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
480 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
481 assert.Equal(t, int64(2), stats.Sync.LastBlock.Num)
482
483 checkSyncBlock(t, s, 2, &blocks[0], syncBlock)
484
485 // Block 3
486
487 syncBlock, discards, err = s.Sync2(ctx, nil)
488 assert.NoError(t, err)
489 require.Nil(t, err)
490 require.Nil(t, discards)
491 require.NotNil(t, syncBlock)
492 assert.Nil(t, syncBlock.Rollup.Vars)
493 assert.Nil(t, syncBlock.Auction.Vars)
494 assert.Nil(t, syncBlock.WDelayer.Vars)
495 assert.Equal(t, int64(3), syncBlock.Block.Num)
496 stats = s.Stats()
497 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
498 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
499 assert.Equal(t, int64(3), stats.Sync.LastBlock.Num)
500
501 checkSyncBlock(t, s, 3, &blocks[1], syncBlock)
502
503 // Block 4
504 // Generate 2 withdraws manually
505 _, err = client.RollupWithdrawMerkleProof(tc.Users["A"].BJJ.Public(), 1, 4, 256, big.NewInt(100), []*big.Int{}, true)
506 require.Nil(t, err)
507 _, err = client.RollupWithdrawMerkleProof(tc.Users["C"].BJJ.Public(), 1, 3, 258, big.NewInt(50), []*big.Int{}, false)
508 require.Nil(t, err)
509 client.CtlMineBlock()
510
511 syncBlock, discards, err = s.Sync2(ctx, nil)
512 require.Nil(t, err)
513 require.Nil(t, discards)
514 require.NotNil(t, syncBlock)
515 assert.Nil(t, syncBlock.Rollup.Vars)
516 assert.Nil(t, syncBlock.Auction.Vars)
517 assert.Nil(t, syncBlock.WDelayer.Vars)
518 assert.Equal(t, int64(4), syncBlock.Block.Num)
519 stats = s.Stats()
520 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
521 assert.Equal(t, int64(4), stats.Eth.LastBlock.Num)
522 assert.Equal(t, int64(4), stats.Sync.LastBlock.Num)
523 vars = s.SCVars()
524 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
525 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
526 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
527
528 dbExits, err := s.historyDB.GetAllExits()
529 require.Nil(t, err)
530 foundA1, foundC1 := false, false
531 for _, exit := range dbExits {
532 if exit.AccountIdx == 256 && exit.BatchNum == 4 {
533 foundA1 = true
534 assert.Equal(t, int64(4), *exit.InstantWithdrawn)
535 }
536 if exit.AccountIdx == 258 && exit.BatchNum == 3 {
537 foundC1 = true
538 assert.Equal(t, int64(4), *exit.DelayedWithdrawRequest)
539 }
540 }
541 assert.True(t, foundA1)
542 assert.True(t, foundC1)
543
544 // Block 5
545 // Update variables manually
546 rollupVars, auctionVars, wDelayerVars, err := s.historyDB.GetSCVars()
547 require.Nil(t, err)
548 rollupVars.ForgeL1L2BatchTimeout = 42
549 _, err = client.RollupUpdateForgeL1L2BatchTimeout(rollupVars.ForgeL1L2BatchTimeout)
550 require.Nil(t, err)
551
552 auctionVars.OpenAuctionSlots = 17
553 _, err = client.AuctionSetOpenAuctionSlots(auctionVars.OpenAuctionSlots)
554 require.Nil(t, err)
555
556 wDelayerVars.WithdrawalDelay = 99
557 _, err = client.WDelayerChangeWithdrawalDelay(wDelayerVars.WithdrawalDelay)
558 require.Nil(t, err)
559
560 client.CtlMineBlock()
561
562 syncBlock, discards, err = s.Sync2(ctx, nil)
563 require.Nil(t, err)
564 require.Nil(t, discards)
565 require.NotNil(t, syncBlock)
566 assert.NotNil(t, syncBlock.Rollup.Vars)
567 assert.NotNil(t, syncBlock.Auction.Vars)
568 assert.NotNil(t, syncBlock.WDelayer.Vars)
569 assert.Equal(t, int64(5), syncBlock.Block.Num)
570 stats = s.Stats()
571 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
572 assert.Equal(t, int64(5), stats.Eth.LastBlock.Num)
573 assert.Equal(t, int64(5), stats.Sync.LastBlock.Num)
574 vars = s.SCVars()
575 assert.NotEqual(t, clientSetup.RollupVariables, vars.Rollup)
576 assert.NotEqual(t, clientSetup.AuctionVariables, vars.Auction)
577 assert.NotEqual(t, clientSetup.WDelayerVariables, vars.WDelayer)
578
579 dbRollupVars, dbAuctionVars, dbWDelayerVars, err := s.historyDB.GetSCVars()
580 require.Nil(t, err)
581 // Set EthBlockNum for Vars to the blockNum in which they were updated (should be 5)
582 rollupVars.EthBlockNum = syncBlock.Block.Num
583 auctionVars.EthBlockNum = syncBlock.Block.Num
584 wDelayerVars.EthBlockNum = syncBlock.Block.Num
585 assert.Equal(t, rollupVars, dbRollupVars)
586 assert.Equal(t, auctionVars, dbAuctionVars)
587 assert.Equal(t, wDelayerVars, dbWDelayerVars)
588
589 //
590 // Reorg test
591 //
592
593 // Redo blocks 2-5 (as a reorg) only leaving:
594 // - 2 create account transactions
595 // - 2 add tokens
596 // We add a 6th block so that the synchronizer can detect the reorg
597 set2 := `
598 Type: Blockchain
599
600 AddToken(1)
601 AddToken(2)
602
603 CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
604
605 CreateAccountCoordinator(1) A // Idx=256+0=256
606
607 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
608 > batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
609 > block // blockNum=2
610 > block // blockNum=3
611 > block // blockNum=4
612 > block // blockNum=5
613 > block // blockNum=6
614 `
615 tc = til.NewContext(common.RollupConstMaxL1UserTx)
616 tilCfgExtra = til.ConfigExtra{
617 BootCoordAddr: bootCoordAddr,
618 CoordUser: "A",
619 }
620 blocks, err = tc.GenerateBlocks(set2)
621 require.Nil(t, err)
622
623 for i := 0; i < 4; i++ {
624 client.CtlRollback()
625 }
626 block := client.CtlLastBlock()
627 require.Equal(t, int64(1), block.Num)
628
629 // Generate extra required data
630 ethAddTokens(blocks, client)
631
632 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
633 assert.NoError(t, err)
634 tc.FillBlocksL1UserTxsBatchNum(blocks)
635
636 // Add block data to the smart contracts
637 ethAddBlocks(t, blocks, client, clientSetup)
638
639 // First sync detects the reorg and discards 4 blocks
640 syncBlock, discards, err = s.Sync2(ctx, nil)
641 require.Nil(t, err)
642 expetedDiscards := int64(4)
643 require.Equal(t, &expetedDiscards, discards)
644 require.Nil(t, syncBlock)
645 stats = s.Stats()
646 assert.Equal(t, false, stats.Synced())
647 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
648 vars = s.SCVars()
649 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
650 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
651 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
652
653 // At this point, the DB only has data up to block 1
654 dbBlock, err := s.historyDB.GetLastBlock()
655 require.Nil(t, err)
656 assert.Equal(t, int64(1), dbBlock.Num)
657
658 // Accounts in HistoryDB and StateDB must be empty
659 dbAccounts, err := s.historyDB.GetAllAccounts()
660 require.Nil(t, err)
661 sdbAccounts, err := s.stateDB.GetAccounts()
662 require.Nil(t, err)
663 assert.Equal(t, 0, len(dbAccounts))
664 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
665
666 // Sync blocks 2-6
667 for i := 0; i < 5; i++ {
668 syncBlock, discards, err = s.Sync2(ctx, nil)
669 require.Nil(t, err)
670 require.Nil(t, discards)
671 require.NotNil(t, syncBlock)
672 assert.Nil(t, syncBlock.Rollup.Vars)
673 assert.Nil(t, syncBlock.Auction.Vars)
674 assert.Nil(t, syncBlock.WDelayer.Vars)
675 assert.Equal(t, int64(2+i), syncBlock.Block.Num)
676
677 stats = s.Stats()
678 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
679 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
680 assert.Equal(t, int64(2+i), stats.Sync.LastBlock.Num)
681 if i == 4 {
682 assert.Equal(t, true, stats.Synced())
683 } else {
684 assert.Equal(t, false, stats.Synced())
685 }
686
687 vars = s.SCVars()
688 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
689 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
690 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
691 }
692
693 dbBlock, err = s.historyDB.GetLastBlock()
694 require.Nil(t, err)
695 assert.Equal(t, int64(6), dbBlock.Num)
696
697 // Accounts in HistoryDB and StateDB is only 2 entries
698 dbAccounts, err = s.historyDB.GetAllAccounts()
699 require.Nil(t, err)
700 sdbAccounts, err = s.stateDB.GetAccounts()
701 require.Nil(t, err)
702 assert.Equal(t, 2, len(dbAccounts))
703 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
704}