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 var vars struct {
358 Rollup *common.RollupVariables
359 Auction *common.AuctionVariables
360 WDelayer *common.WDelayerVariables
361 }
362 stats := s.Stats()
363 assert.Equal(t, false, stats.Synced())
364
365 // Test Sync for rollup genesis block
366 syncBlock, discards, err := s.Sync2(ctx, nil)
367 require.Nil(t, err)
368 require.Nil(t, discards)
369 require.NotNil(t, syncBlock)
370 require.Nil(t, syncBlock.Rollup.Vars)
371 require.Nil(t, syncBlock.Auction.Vars)
372 require.Nil(t, syncBlock.WDelayer.Vars)
373 assert.Equal(t, int64(1), syncBlock.Block.Num)
374 stats = s.Stats()
375 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
376 assert.Equal(t, int64(1), stats.Eth.LastBlock.Num)
377 assert.Equal(t, int64(1), stats.Sync.LastBlock.Num)
378 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
379 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
380 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
381 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
382
383 dbBlocks, err := s.historyDB.GetAllBlocks()
384 require.Nil(t, err)
385 assert.Equal(t, 2, len(dbBlocks))
386 assert.Equal(t, int64(1), dbBlocks[1].Num)
387
388 // Sync again and expect no new blocks
389 syncBlock, discards, err = s.Sync2(ctx, nil)
390 require.Nil(t, err)
391 require.Nil(t, discards)
392 require.Nil(t, syncBlock)
393
394 //
395 // Generate blockchain and smart contract data, and fill the test smart contracts
396 //
397
398 // Generate blockchain data with til
399 set1 := `
400 Type: Blockchain
401
402 AddToken(1)
403 AddToken(2)
404 AddToken(3)
405
406 CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
407 CreateAccountDeposit(2) A: 2000 // Idx=256+3=259
408 CreateAccountDeposit(1) D: 500 // Idx=256+4=260
409 CreateAccountDeposit(2) B: 500 // Idx=256+5=261
410 CreateAccountDeposit(2) C: 500 // Idx=256+6=262
411
412 CreateAccountCoordinator(1) A // Idx=256+0=256
413 CreateAccountCoordinator(1) B // Idx=256+1=257
414
415 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
416 > batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
417 > block // blockNum=2
418
419 CreateAccountDepositTransfer(1) E-A: 1000, 200 // Idx=256+7=263
420 ForceTransfer(1) C-B: 80
421 ForceExit(1) A: 100
422 ForceExit(1) B: 80
423 ForceTransfer(1) A-D: 100
424
425 Transfer(1) C-A: 100 (200)
426 Exit(1) C: 50 (200)
427 Exit(1) D: 30 (200)
428
429 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
430 > batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
431 > block // blockNum=3
432 `
433 tc := til.NewContext(common.RollupConstMaxL1UserTx)
434 tilCfgExtra := til.ConfigExtra{
435 BootCoordAddr: bootCoordAddr,
436 CoordUser: "A",
437 }
438 blocks, err := tc.GenerateBlocks(set1)
439 require.Nil(t, err)
440 // Sanity check
441 require.Equal(t, 2, len(blocks))
442 // blocks 0 (blockNum=2)
443 i := 0
444 require.Equal(t, 2, int(blocks[i].Block.Num))
445 require.Equal(t, 3, len(blocks[i].Rollup.AddedTokens))
446 require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
447 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
448 require.Equal(t, 2, len(blocks[i].Rollup.Batches[0].L1CoordinatorTxs))
449 // blocks 1 (blockNum=3)
450 i = 1
451 require.Equal(t, 3, int(blocks[i].Block.Num))
452 require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
453 require.Equal(t, 2, len(blocks[i].Rollup.Batches))
454 require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
455
456 // Generate extra required data
457 ethAddTokens(blocks, client)
458
459 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
460 assert.NoError(t, err)
461 tc.FillBlocksL1UserTxsBatchNum(blocks)
462 err = tc.FillBlocksForgedL1UserTxs(blocks)
463 assert.NoError(t, err)
464
465 // Add block data to the smart contracts
466 ethAddBlocks(t, blocks, client, clientSetup)
467
468 //
469 // Sync to synchronize the current state from the test smart contracts,
470 // and check the outcome
471 //
472
473 // Block 2
474
475 syncBlock, discards, err = s.Sync2(ctx, nil)
476 require.Nil(t, err)
477 require.Nil(t, discards)
478 require.NotNil(t, syncBlock)
479 assert.Nil(t, syncBlock.Rollup.Vars)
480 assert.Nil(t, syncBlock.Auction.Vars)
481 assert.Nil(t, syncBlock.WDelayer.Vars)
482 assert.Equal(t, int64(2), syncBlock.Block.Num)
483 stats = s.Stats()
484 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
485 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
486 assert.Equal(t, int64(2), stats.Sync.LastBlock.Num)
487
488 checkSyncBlock(t, s, 2, &blocks[0], syncBlock)
489
490 // Block 3
491
492 syncBlock, discards, err = s.Sync2(ctx, nil)
493 require.Nil(t, err)
494 require.Nil(t, discards)
495 require.NotNil(t, syncBlock)
496 assert.Nil(t, syncBlock.Rollup.Vars)
497 assert.Nil(t, syncBlock.Auction.Vars)
498 assert.Nil(t, syncBlock.WDelayer.Vars)
499 assert.Equal(t, int64(3), syncBlock.Block.Num)
500 stats = s.Stats()
501 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
502 assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
503 assert.Equal(t, int64(3), stats.Sync.LastBlock.Num)
504
505 checkSyncBlock(t, s, 3, &blocks[1], syncBlock)
506
507 // Block 4
508 // Generate 2 withdraws manually
509 _, err = client.RollupWithdrawMerkleProof(tc.Users["A"].BJJ.Public(), 1, 4, 256, big.NewInt(100), []*big.Int{}, true)
510 require.Nil(t, err)
511 _, err = client.RollupWithdrawMerkleProof(tc.Users["C"].BJJ.Public(), 1, 3, 258, big.NewInt(50), []*big.Int{}, false)
512 require.Nil(t, err)
513 client.CtlMineBlock()
514
515 syncBlock, discards, err = s.Sync2(ctx, nil)
516 require.Nil(t, err)
517 require.Nil(t, discards)
518 require.NotNil(t, syncBlock)
519 assert.Nil(t, syncBlock.Rollup.Vars)
520 assert.Nil(t, syncBlock.Auction.Vars)
521 assert.Nil(t, syncBlock.WDelayer.Vars)
522 assert.Equal(t, int64(4), syncBlock.Block.Num)
523 stats = s.Stats()
524 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
525 assert.Equal(t, int64(4), stats.Eth.LastBlock.Num)
526 assert.Equal(t, int64(4), stats.Sync.LastBlock.Num)
527 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
528 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
529 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
530 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
531
532 dbExits, err := s.historyDB.GetAllExits()
533 require.Nil(t, err)
534 foundA1, foundC1 := false, false
535 for _, exit := range dbExits {
536 if exit.AccountIdx == 256 && exit.BatchNum == 4 {
537 foundA1 = true
538 assert.Equal(t, int64(4), *exit.InstantWithdrawn)
539 }
540 if exit.AccountIdx == 258 && exit.BatchNum == 3 {
541 foundC1 = true
542 assert.Equal(t, int64(4), *exit.DelayedWithdrawRequest)
543 }
544 }
545 assert.True(t, foundA1)
546 assert.True(t, foundC1)
547
548 // Block 5
549 // Update variables manually
550 rollupVars, auctionVars, wDelayerVars, err := s.historyDB.GetSCVars()
551 require.Nil(t, err)
552 rollupVars.ForgeL1L2BatchTimeout = 42
553 _, err = client.RollupUpdateForgeL1L2BatchTimeout(rollupVars.ForgeL1L2BatchTimeout)
554 require.Nil(t, err)
555
556 auctionVars.OpenAuctionSlots = 17
557 _, err = client.AuctionSetOpenAuctionSlots(auctionVars.OpenAuctionSlots)
558 require.Nil(t, err)
559
560 wDelayerVars.WithdrawalDelay = 99
561 _, err = client.WDelayerChangeWithdrawalDelay(wDelayerVars.WithdrawalDelay)
562 require.Nil(t, err)
563
564 client.CtlMineBlock()
565
566 syncBlock, discards, err = s.Sync2(ctx, nil)
567 require.Nil(t, err)
568 require.Nil(t, discards)
569 require.NotNil(t, syncBlock)
570 assert.NotNil(t, syncBlock.Rollup.Vars)
571 assert.NotNil(t, syncBlock.Auction.Vars)
572 assert.NotNil(t, syncBlock.WDelayer.Vars)
573 assert.Equal(t, int64(5), syncBlock.Block.Num)
574 stats = s.Stats()
575 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
576 assert.Equal(t, int64(5), stats.Eth.LastBlock.Num)
577 assert.Equal(t, int64(5), stats.Sync.LastBlock.Num)
578 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
579 assert.NotEqual(t, clientSetup.RollupVariables, vars.Rollup)
580 assert.NotEqual(t, clientSetup.AuctionVariables, vars.Auction)
581 assert.NotEqual(t, clientSetup.WDelayerVariables, vars.WDelayer)
582
583 dbRollupVars, dbAuctionVars, dbWDelayerVars, err := s.historyDB.GetSCVars()
584 require.Nil(t, err)
585 // Set EthBlockNum for Vars to the blockNum in which they were updated (should be 5)
586 rollupVars.EthBlockNum = syncBlock.Block.Num
587 auctionVars.EthBlockNum = syncBlock.Block.Num
588 wDelayerVars.EthBlockNum = syncBlock.Block.Num
589 assert.Equal(t, rollupVars, dbRollupVars)
590 assert.Equal(t, auctionVars, dbAuctionVars)
591 assert.Equal(t, wDelayerVars, dbWDelayerVars)
592
593 //
594 // Reorg test
595 //
596
597 // Redo blocks 2-5 (as a reorg) only leaving:
598 // - 2 create account transactions
599 // - 2 add tokens
600 // We add a 6th block so that the synchronizer can detect the reorg
601 set2 := `
602 Type: Blockchain
603
604 AddToken(1)
605 AddToken(2)
606
607 CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
608
609 CreateAccountCoordinator(1) A // Idx=256+0=256
610
611 > batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
612 > batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
613 > block // blockNum=2
614 > block // blockNum=3
615 > block // blockNum=4
616 > block // blockNum=5
617 > block // blockNum=6
618 `
619 tc = til.NewContext(common.RollupConstMaxL1UserTx)
620 tilCfgExtra = til.ConfigExtra{
621 BootCoordAddr: bootCoordAddr,
622 CoordUser: "A",
623 }
624 blocks, err = tc.GenerateBlocks(set2)
625 require.Nil(t, err)
626
627 for i := 0; i < 4; i++ {
628 client.CtlRollback()
629 }
630 block := client.CtlLastBlock()
631 require.Equal(t, int64(1), block.Num)
632
633 // Generate extra required data
634 ethAddTokens(blocks, client)
635
636 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
637 assert.NoError(t, err)
638 tc.FillBlocksL1UserTxsBatchNum(blocks)
639
640 // Add block data to the smart contracts
641 ethAddBlocks(t, blocks, client, clientSetup)
642
643 // First sync detects the reorg and discards 4 blocks
644 syncBlock, discards, err = s.Sync2(ctx, nil)
645 require.Nil(t, err)
646 expetedDiscards := int64(4)
647 require.Equal(t, &expetedDiscards, discards)
648 require.Nil(t, syncBlock)
649 stats = s.Stats()
650 assert.Equal(t, false, stats.Synced())
651 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
652 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
653 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
654 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
655 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
656
657 // At this point, the DB only has data up to block 1
658 dbBlock, err := s.historyDB.GetLastBlock()
659 require.Nil(t, err)
660 assert.Equal(t, int64(1), dbBlock.Num)
661
662 // Accounts in HistoryDB and StateDB must be empty
663 dbAccounts, err := s.historyDB.GetAllAccounts()
664 require.Nil(t, err)
665 sdbAccounts, err := s.stateDB.GetAccounts()
666 require.Nil(t, err)
667 assert.Equal(t, 0, len(dbAccounts))
668 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
669
670 // Sync blocks 2-6
671 for i := 0; i < 5; i++ {
672 syncBlock, discards, err = s.Sync2(ctx, nil)
673 require.Nil(t, err)
674 require.Nil(t, discards)
675 require.NotNil(t, syncBlock)
676 assert.Nil(t, syncBlock.Rollup.Vars)
677 assert.Nil(t, syncBlock.Auction.Vars)
678 assert.Nil(t, syncBlock.WDelayer.Vars)
679 assert.Equal(t, int64(2+i), syncBlock.Block.Num)
680
681 stats = s.Stats()
682 assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
683 assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
684 assert.Equal(t, int64(2+i), stats.Sync.LastBlock.Num)
685 if i == 4 {
686 assert.Equal(t, true, stats.Synced())
687 } else {
688 assert.Equal(t, false, stats.Synced())
689 }
690
691 vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
692 assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
693 assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
694 assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
695 }
696
697 dbBlock, err = s.historyDB.GetLastBlock()
698 require.Nil(t, err)
699 assert.Equal(t, int64(6), dbBlock.Num)
700
701 // Accounts in HistoryDB and StateDB is only 2 entries
702 dbAccounts, err = s.historyDB.GetAllAccounts()
703 require.Nil(t, err)
704 sdbAccounts, err = s.stateDB.GetAccounts()
705 require.Nil(t, err)
706 assert.Equal(t, 2, len(dbAccounts))
707 assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
708}