arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/synchronizer/synchronizer_test.go
synchronizer/synchronizer_test.goRaw
  1package synchronizer
  2
  3import (
  4	"context"
  5	"encoding/json"
  6	"fmt"
  7	"io/ioutil"
  8	"math/big"
  9	"os"
 10	"sort"
 11	"testing"
 12
 13	ethCommon "github.com/ethereum/go-ethereum/common"
 14	"github.com/hermeznetwork/hermez-node/common"
 15	dbUtils "github.com/hermeznetwork/hermez-node/db"
 16	"github.com/hermeznetwork/hermez-node/db/historydb"
 17	"github.com/hermeznetwork/hermez-node/db/statedb"
 18	"github.com/hermeznetwork/hermez-node/eth"
 19	"github.com/hermeznetwork/hermez-node/test"
 20	"github.com/hermeznetwork/hermez-node/test/til"
 21	"github.com/jinzhu/copier"
 22	"github.com/stretchr/testify/assert"
 23	"github.com/stretchr/testify/require"
 24)
 25
 26var tokenConsts = map[common.TokenID]eth.ERC20Consts{}
 27
 28type timer struct {
 29	time int64
 30}
 31
 32func (t *timer) Time() int64 {
 33	currentTime := t.time
 34	t.time++
 35	return currentTime
 36}
 37
 38func accountsCmp(accounts []common.Account) func(i, j int) bool {
 39	return func(i, j int) bool { return accounts[i].Idx < accounts[j].Idx }
 40}
 41
 42// Check Sync output and HistoryDB state against expected values generated by
 43// til
 44func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBlock *common.BlockData) {
 45	// Check Blocks
 46	dbBlocks, err := s.historyDB.GetAllBlocks()
 47	require.Nil(t, err)
 48	dbBlocks = dbBlocks[1:] // ignore block 0, added by default in the DB
 49	assert.Equal(t, blockNum, len(dbBlocks))
 50	assert.Equal(t, int64(blockNum), dbBlocks[blockNum-1].Num)
 51	assert.NotEqual(t, dbBlocks[blockNum-1].Hash, dbBlocks[blockNum-2].Hash)
 52	assert.Greater(t, dbBlocks[blockNum-1].Timestamp.Unix(), dbBlocks[blockNum-2].Timestamp.Unix())
 53
 54	// Check Tokens
 55	assert.Equal(t, len(block.Rollup.AddedTokens), len(syncBlock.Rollup.AddedTokens))
 56	dbTokens, err := s.historyDB.GetAllTokens()
 57	require.Nil(t, err)
 58	dbTokens = dbTokens[1:] // ignore token 0, added by default in the DB
 59	for i, token := range block.Rollup.AddedTokens {
 60		dbToken := dbTokens[i]
 61		syncToken := syncBlock.Rollup.AddedTokens[i]
 62
 63		assert.Equal(t, block.Block.Num, syncToken.EthBlockNum)
 64		assert.Equal(t, token.TokenID, syncToken.TokenID)
 65		assert.Equal(t, token.EthAddr, syncToken.EthAddr)
 66		tokenConst := tokenConsts[token.TokenID]
 67		assert.Equal(t, tokenConst.Name, syncToken.Name)
 68		assert.Equal(t, tokenConst.Symbol, syncToken.Symbol)
 69		assert.Equal(t, tokenConst.Decimals, syncToken.Decimals)
 70
 71		var tokenCpy historydb.TokenWithUSD
 72		//nolint:gosec
 73		require.Nil(t, copier.Copy(&tokenCpy, &token))      // copy common.Token to historydb.TokenWithUSD
 74		require.Nil(t, copier.Copy(&tokenCpy, &tokenConst)) // copy common.Token to historydb.TokenWithUSD
 75		tokenCpy.ItemID = dbToken.ItemID                    // we don't care about ItemID
 76		assert.Equal(t, tokenCpy, dbToken)
 77	}
 78
 79	// Check L1UserTxs
 80	assert.Equal(t, len(block.Rollup.L1UserTxs), len(syncBlock.Rollup.L1UserTxs))
 81	dbL1UserTxs, err := s.historyDB.GetAllL1UserTxs()
 82	require.Nil(t, err)
 83	// Ignore BatchNum in syncBlock.L1UserTxs because this value is set by
 84	// the HistoryDB. Also ignore EffectiveAmount & EffectiveLoadAmount
 85	// because this value is set by StateDB.ProcessTxs.
 86	for i := range syncBlock.Rollup.L1UserTxs {
 87		syncBlock.Rollup.L1UserTxs[i].BatchNum = block.Rollup.L1UserTxs[i].BatchNum
 88		syncBlock.Rollup.L1UserTxs[i].EffectiveAmount = block.Rollup.L1UserTxs[i].EffectiveAmount
 89		syncBlock.Rollup.L1UserTxs[i].EffectiveLoadAmount =
 90			block.Rollup.L1UserTxs[i].EffectiveLoadAmount
 91	}
 92	assert.Equal(t, block.Rollup.L1UserTxs, syncBlock.Rollup.L1UserTxs)
 93	for _, tx := range block.Rollup.L1UserTxs {
 94		var dbTx *common.L1Tx
 95		// Find tx in DB output
 96		for _, _dbTx := range dbL1UserTxs {
 97			if *tx.ToForgeL1TxsNum == *_dbTx.ToForgeL1TxsNum &&
 98				tx.Position == _dbTx.Position {
 99				dbTx = new(common.L1Tx)
100				*dbTx = _dbTx
101				break
102			}
103		}
104		tx.EffectiveAmount = tx.Amount
105		tx.EffectiveLoadAmount = tx.LoadAmount
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.LoadAmount, 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(&eth.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, &ethCommon.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}