arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/synchronizer/synchronizer.go
synchronizer/synchronizer.goRaw
   1package synchronizer
   2
   3import (
   4	"context"
   5	"database/sql"
   6	"fmt"
   7	"math/big"
   8	"sync"
   9	"time"
  10
  11	"github.com/ethereum/go-ethereum"
  12	"github.com/hermeznetwork/hermez-node/common"
  13	"github.com/hermeznetwork/hermez-node/db/historydb"
  14	"github.com/hermeznetwork/hermez-node/db/statedb"
  15	"github.com/hermeznetwork/hermez-node/eth"
  16	"github.com/hermeznetwork/hermez-node/log"
  17	"github.com/hermeznetwork/hermez-node/txprocessor"
  18	"github.com/hermeznetwork/tracerr"
  19)
  20
  21// Stats of the syncrhonizer
  22type Stats struct {
  23	Eth struct {
  24		RefreshPeriod time.Duration
  25		Updated       time.Time
  26		FirstBlockNum int64
  27		LastBlock     common.Block
  28		LastBatch     int64
  29	}
  30	Sync struct {
  31		Updated   time.Time
  32		LastBlock common.Block
  33		LastBatch int64
  34		// LastL1BatchBlock is the last ethereum block in which an
  35		// l1Batch was forged
  36		LastL1BatchBlock  int64
  37		LastForgeL1TxsNum int64
  38		Auction           struct {
  39			CurrentSlot common.Slot
  40		}
  41	}
  42}
  43
  44// Synced returns true if the Synchronizer is up to date with the last ethereum block
  45func (s *Stats) Synced() bool {
  46	return s.Eth.LastBlock.Num == s.Sync.LastBlock.Num
  47}
  48
  49// TODO(Edu): Consider removing all the mutexes from StatsHolder, make
  50// Synchronizer.Stats not thread-safe, don't pass the synchronizer to the
  51// debugAPI, and have a copy of the Stats in the DebugAPI that the node passes
  52// when the Sync updates.
  53
  54// StatsHolder stores stats and that allows reading and writing them
  55// concurrently
  56type StatsHolder struct {
  57	Stats
  58	rw sync.RWMutex
  59}
  60
  61// NewStatsHolder creates a new StatsHolder
  62func NewStatsHolder(firstBlockNum int64, refreshPeriod time.Duration) *StatsHolder {
  63	stats := Stats{}
  64	stats.Eth.RefreshPeriod = refreshPeriod
  65	stats.Eth.FirstBlockNum = firstBlockNum
  66	return &StatsHolder{Stats: stats}
  67}
  68
  69// UpdateCurrentSlot updates the auction stats
  70func (s *StatsHolder) UpdateCurrentSlot(slot common.Slot) {
  71	s.rw.Lock()
  72	s.Sync.Auction.CurrentSlot = slot
  73	s.rw.Unlock()
  74}
  75
  76// UpdateSync updates the synchronizer stats
  77func (s *StatsHolder) UpdateSync(lastBlock *common.Block, lastBatch *common.BatchNum,
  78	lastL1BatchBlock *int64, lastForgeL1TxsNum *int64) {
  79	now := time.Now()
  80	s.rw.Lock()
  81	s.Sync.LastBlock = *lastBlock
  82	if lastBatch != nil {
  83		s.Sync.LastBatch = int64(*lastBatch)
  84	}
  85	if lastL1BatchBlock != nil {
  86		s.Sync.LastL1BatchBlock = *lastL1BatchBlock
  87		s.Sync.LastForgeL1TxsNum = *lastForgeL1TxsNum
  88	}
  89	s.Sync.Updated = now
  90	s.rw.Unlock()
  91}
  92
  93// UpdateEth updates the ethereum stats, only if the previous stats expired
  94func (s *StatsHolder) UpdateEth(ethClient eth.ClientInterface) error {
  95	now := time.Now()
  96	s.rw.RLock()
  97	elapsed := now.Sub(s.Eth.Updated)
  98	s.rw.RUnlock()
  99	if elapsed < s.Eth.RefreshPeriod {
 100		return nil
 101	}
 102
 103	lastBlock, err := ethClient.EthBlockByNumber(context.TODO(), -1)
 104	if err != nil {
 105		return tracerr.Wrap(err)
 106	}
 107	lastBatch, err := ethClient.RollupLastForgedBatch()
 108	if err != nil {
 109		return tracerr.Wrap(err)
 110	}
 111	s.rw.Lock()
 112	s.Eth.Updated = now
 113	s.Eth.LastBlock = *lastBlock
 114	s.Eth.LastBatch = lastBatch
 115	s.rw.Unlock()
 116	return nil
 117}
 118
 119// CopyStats returns a copy of the inner Stats
 120func (s *StatsHolder) CopyStats() *Stats {
 121	s.rw.RLock()
 122	sCopy := s.Stats
 123	if s.Sync.Auction.CurrentSlot.BidValue != nil {
 124		sCopy.Sync.Auction.CurrentSlot.BidValue =
 125			common.CopyBigInt(s.Sync.Auction.CurrentSlot.BidValue)
 126	}
 127	if s.Sync.Auction.CurrentSlot.DefaultSlotBid != nil {
 128		sCopy.Sync.Auction.CurrentSlot.DefaultSlotBid =
 129			common.CopyBigInt(s.Sync.Auction.CurrentSlot.DefaultSlotBid)
 130	}
 131	s.rw.RUnlock()
 132	return &sCopy
 133}
 134
 135func (s *StatsHolder) blocksPerc() float64 {
 136	syncLastBlockNum := s.Sync.LastBlock.Num
 137	if s.Sync.LastBlock.Num == 0 {
 138		syncLastBlockNum = s.Eth.FirstBlockNum - 1
 139	}
 140	return float64(syncLastBlockNum-(s.Eth.FirstBlockNum-1)) * 100.0 /
 141		float64(s.Eth.LastBlock.Num-(s.Eth.FirstBlockNum-1))
 142}
 143
 144func (s *StatsHolder) batchesPerc(batchNum int64) float64 {
 145	return float64(batchNum) * 100.0 /
 146		float64(s.Eth.LastBatch)
 147}
 148
 149// StartBlockNums sets the first block used to start tracking the smart
 150// contracts
 151type StartBlockNums struct {
 152	Rollup   int64
 153	Auction  int64
 154	WDelayer int64
 155}
 156
 157// SCVariables joins all the smart contract variables in a single struct
 158type SCVariables struct {
 159	Rollup   common.RollupVariables   `validate:"required"`
 160	Auction  common.AuctionVariables  `validate:"required"`
 161	WDelayer common.WDelayerVariables `validate:"required"`
 162}
 163
 164// SCVariablesPtr joins all the smart contract variables as pointers in a single
 165// struct
 166type SCVariablesPtr struct {
 167	Rollup   *common.RollupVariables   `validate:"required"`
 168	Auction  *common.AuctionVariables  `validate:"required"`
 169	WDelayer *common.WDelayerVariables `validate:"required"`
 170}
 171
 172// SCConsts joins all the smart contract constants in a single struct
 173type SCConsts struct {
 174	Rollup   common.RollupConstants
 175	Auction  common.AuctionConstants
 176	WDelayer common.WDelayerConstants
 177}
 178
 179// Config is the Synchronizer configuration
 180type Config struct {
 181	StatsRefreshPeriod time.Duration
 182}
 183
 184// Synchronizer implements the Synchronizer type
 185type Synchronizer struct {
 186	ethClient     eth.ClientInterface
 187	consts        SCConsts
 188	historyDB     *historydb.HistoryDB
 189	stateDB       *statedb.StateDB
 190	cfg           Config
 191	initVars      SCVariables
 192	startBlockNum int64
 193	vars          SCVariables
 194	stats         *StatsHolder
 195}
 196
 197// NewSynchronizer creates a new Synchronizer
 198func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.HistoryDB,
 199	stateDB *statedb.StateDB, cfg Config) (*Synchronizer, error) {
 200	auctionConstants, err := ethClient.AuctionConstants()
 201	if err != nil {
 202		return nil, tracerr.Wrap(fmt.Errorf("NewSynchronizer ethClient.AuctionConstants(): %w",
 203			err))
 204	}
 205	rollupConstants, err := ethClient.RollupConstants()
 206	if err != nil {
 207		return nil, tracerr.Wrap(fmt.Errorf("NewSynchronizer ethClient.RollupConstants(): %w",
 208			err))
 209	}
 210	wDelayerConstants, err := ethClient.WDelayerConstants()
 211	if err != nil {
 212		return nil, tracerr.Wrap(fmt.Errorf("NewSynchronizer ethClient.WDelayerConstants(): %w",
 213			err))
 214	}
 215	consts := SCConsts{
 216		Rollup:   *rollupConstants,
 217		Auction:  *auctionConstants,
 218		WDelayer: *wDelayerConstants,
 219	}
 220
 221	initVars, startBlockNums, err := getInitialVariables(ethClient, &consts)
 222	if err != nil {
 223		return nil, tracerr.Wrap(err)
 224	}
 225	log.Infow("Synchronizer syncing from smart contract blocks",
 226		"rollup", startBlockNums.Rollup,
 227		"auction", startBlockNums.Auction,
 228		"wdelayer", startBlockNums.WDelayer,
 229	)
 230	// Set startBlockNum to the minimum between Auction, Rollup and
 231	// WDelayer StartBlockNum
 232	startBlockNum := startBlockNums.Auction
 233	if startBlockNums.Rollup < startBlockNum {
 234		startBlockNum = startBlockNums.Rollup
 235	}
 236	if startBlockNums.WDelayer < startBlockNum {
 237		startBlockNum = startBlockNums.WDelayer
 238	}
 239	stats := NewStatsHolder(startBlockNum, cfg.StatsRefreshPeriod)
 240	s := &Synchronizer{
 241		ethClient:     ethClient,
 242		consts:        consts,
 243		historyDB:     historyDB,
 244		stateDB:       stateDB,
 245		cfg:           cfg,
 246		initVars:      *initVars,
 247		startBlockNum: startBlockNum,
 248		stats:         stats,
 249	}
 250	return s, s.init()
 251}
 252
 253// Stats returns a copy of the Synchronizer Stats.  It is safe to call Stats()
 254// during a Sync call
 255func (s *Synchronizer) Stats() *Stats {
 256	return s.stats.CopyStats()
 257}
 258
 259// AuctionConstants returns the AuctionConstants read from the smart contract
 260func (s *Synchronizer) AuctionConstants() *common.AuctionConstants {
 261	return &s.consts.Auction
 262}
 263
 264// RollupConstants returns the RollupConstants read from the smart contract
 265func (s *Synchronizer) RollupConstants() *common.RollupConstants {
 266	return &s.consts.Rollup
 267}
 268
 269// WDelayerConstants returns the WDelayerConstants read from the smart contract
 270func (s *Synchronizer) WDelayerConstants() *common.WDelayerConstants {
 271	return &s.consts.WDelayer
 272}
 273
 274// SCVars returns a copy of the Smart Contract Variables
 275func (s *Synchronizer) SCVars() SCVariablesPtr {
 276	return SCVariablesPtr{
 277		Rollup:   s.vars.Rollup.Copy(),
 278		Auction:  s.vars.Auction.Copy(),
 279		WDelayer: s.vars.WDelayer.Copy(),
 280	}
 281}
 282
 283// firstBatchBlockNum is the blockNum of first batch in that block, if any
 284func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *int64) error {
 285	slot := common.Slot{
 286		SlotNum:          s.stats.Sync.Auction.CurrentSlot.SlotNum,
 287		ForgerCommitment: s.stats.Sync.Auction.CurrentSlot.ForgerCommitment,
 288	}
 289	// We want the next block because the current one is already mined
 290	blockNum := s.stats.Sync.LastBlock.Num + 1
 291	slotNum := s.consts.Auction.SlotNum(blockNum)
 292	if reset {
 293		dbFirstBatchBlockNum, err := s.historyDB.GetFirstBatchBlockNumBySlot(slotNum)
 294		if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 295			return tracerr.Wrap(fmt.Errorf("historyDB.GetFirstBatchBySlot: %w", err))
 296		} else if tracerr.Unwrap(err) == sql.ErrNoRows {
 297			firstBatchBlockNum = nil
 298		} else {
 299			firstBatchBlockNum = &dbFirstBatchBlockNum
 300		}
 301		slot.ForgerCommitment = false
 302	} else if slotNum > slot.SlotNum {
 303		// We are in a new slotNum, start from default values
 304		slot.ForgerCommitment = false
 305	}
 306	slot.SlotNum = slotNum
 307	slot.StartBlock, slot.EndBlock = s.consts.Auction.SlotBlocks(slot.SlotNum)
 308	// If Synced, update the current coordinator
 309	if s.stats.Synced() && blockNum >= s.consts.Auction.GenesisBlockNum {
 310		bidCoord, err := s.historyDB.GetBestBidCoordinator(slot.SlotNum)
 311		if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 312			return tracerr.Wrap(err)
 313		}
 314		if tracerr.Unwrap(err) == sql.ErrNoRows {
 315			slot.BootCoord = true
 316			slot.Forger = s.vars.Auction.BootCoordinator
 317			slot.URL = s.vars.Auction.BootCoordinatorURL
 318		} else if err == nil {
 319			slot.BidValue = bidCoord.BidValue
 320			slot.DefaultSlotBid = bidCoord.DefaultSlotSetBid[slot.SlotNum%6]
 321			// Only if the highest bid value is greater/equal than
 322			// the default slot bid, the bidder is the winner of
 323			// the slot.  Otherwise the boot coordinator is the
 324			// winner.
 325			if slot.BidValue.Cmp(slot.DefaultSlotBid) >= 0 {
 326				slot.Bidder = bidCoord.Bidder
 327				slot.Forger = bidCoord.Forger
 328				slot.URL = bidCoord.URL
 329			} else {
 330				slot.BootCoord = true
 331				slot.Forger = s.vars.Auction.BootCoordinator
 332				slot.URL = s.vars.Auction.BootCoordinatorURL
 333			}
 334		}
 335		if firstBatchBlockNum != nil &&
 336			s.consts.Auction.RelativeBlock(*firstBatchBlockNum) <
 337				int64(s.vars.Auction.SlotDeadline) {
 338			slot.ForgerCommitment = true
 339		}
 340
 341		// TODO: Remove this SANITY CHECK once this code is tested enough
 342		// BEGIN SANITY CHECK
 343		canForge, err := s.ethClient.AuctionCanForge(slot.Forger, blockNum)
 344		if err != nil {
 345			return tracerr.Wrap(err)
 346		}
 347		if !canForge {
 348			return tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+
 349				"differs from smart contract: %+v", slot))
 350		}
 351		// END SANITY CHECK
 352	}
 353	s.stats.UpdateCurrentSlot(slot)
 354	return nil
 355}
 356
 357func (s *Synchronizer) init() error {
 358	// Update stats parameters so that they have valid values before the
 359	// first Sync call
 360	if err := s.stats.UpdateEth(s.ethClient); err != nil {
 361		return tracerr.Wrap(err)
 362	}
 363	lastBlock := &common.Block{}
 364	lastSavedBlock, err := s.historyDB.GetLastBlock()
 365	// `s.historyDB.GetLastBlock()` will never return `sql.ErrNoRows`
 366	// because we always have the default block 0 in the DB
 367	if err != nil {
 368		return tracerr.Wrap(err)
 369	}
 370	// If we only have the default block 0,
 371	// make sure that the stateDB is clean
 372	if lastSavedBlock.Num == 0 {
 373		if err := s.stateDB.Reset(0); err != nil {
 374			return tracerr.Wrap(err)
 375		}
 376	} else {
 377		lastBlock = lastSavedBlock
 378	}
 379	if err := s.resetState(lastBlock); err != nil {
 380		return tracerr.Wrap(err)
 381	}
 382
 383	log.Infow("Sync init block",
 384		"syncLastBlock", s.stats.Sync.LastBlock,
 385		"syncBlocksPerc", s.stats.blocksPerc(),
 386		"ethFirstBlockNum", s.stats.Eth.FirstBlockNum,
 387		"ethLastBlock", s.stats.Eth.LastBlock,
 388	)
 389	log.Infow("Sync init batch",
 390		"syncLastBatch", s.stats.Sync.LastBatch,
 391		"syncBatchesPerc", s.stats.batchesPerc(s.stats.Sync.LastBatch),
 392		"ethLastBatch", s.stats.Eth.LastBatch,
 393	)
 394	return nil
 395}
 396
 397// Sync2 attems to synchronize an ethereum block starting from lastSavedBlock.
 398// If lastSavedBlock is nil, the lastSavedBlock value is obtained from de DB.
 399// If a block is synched, it will be returned and also stored in the DB.  If a
 400// reorg is detected, the number of discarded blocks will be returned and no
 401// synchronization will be made.
 402// TODO: Be smart about locking: only lock during the read/write operations
 403func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block) (*common.BlockData, *int64, error) {
 404	var nextBlockNum int64 // next block number to sync
 405	if lastSavedBlock == nil {
 406		var err error
 407		// Get lastSavedBlock from History DB
 408		lastSavedBlock, err = s.historyDB.GetLastBlock()
 409		if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 410			return nil, nil, tracerr.Wrap(err)
 411		}
 412		// If we don't have any stored block, we must do a full sync
 413		// starting from the startBlockNum
 414		if tracerr.Unwrap(err) == sql.ErrNoRows || lastSavedBlock.Num == 0 {
 415			nextBlockNum = s.startBlockNum
 416			lastSavedBlock = nil
 417		}
 418	}
 419	if lastSavedBlock != nil {
 420		nextBlockNum = lastSavedBlock.Num + 1
 421		if lastSavedBlock.Num < s.startBlockNum {
 422			return nil, nil, tracerr.Wrap(
 423				fmt.Errorf("lastSavedBlock (%v) < startBlockNum (%v)",
 424					lastSavedBlock.Num, s.startBlockNum))
 425		}
 426	}
 427
 428	ethBlock, err := s.ethClient.EthBlockByNumber(ctx, nextBlockNum)
 429	if tracerr.Unwrap(err) == ethereum.NotFound {
 430		return nil, nil, nil
 431	} else if err != nil {
 432		return nil, nil, tracerr.Wrap(err)
 433	}
 434	log.Debugf("ethBlock: num: %v, parent: %v, hash: %v",
 435		ethBlock.Num, ethBlock.ParentHash.String(), ethBlock.Hash.String())
 436
 437	if err := s.stats.UpdateEth(s.ethClient); err != nil {
 438		return nil, nil, tracerr.Wrap(err)
 439	}
 440
 441	log.Debugw("Syncing...",
 442		"block", nextBlockNum,
 443		"ethLastBlock", s.stats.Eth.LastBlock,
 444	)
 445
 446	// Check that the obtianed ethBlock.ParentHash == prevEthBlock.Hash; if not, reorg!
 447	if lastSavedBlock != nil {
 448		if lastSavedBlock.Hash != ethBlock.ParentHash {
 449			// Reorg detected
 450			log.Debugw("Reorg Detected",
 451				"blockNum", ethBlock.Num,
 452				"block.parent(got)", ethBlock.ParentHash, "parent.hash(exp)", lastSavedBlock.Hash)
 453			lastDBBlockNum, err := s.reorg(lastSavedBlock)
 454			if err != nil {
 455				return nil, nil, tracerr.Wrap(err)
 456			}
 457			discarded := lastSavedBlock.Num - lastDBBlockNum
 458			return nil, &discarded, nil
 459		}
 460	}
 461
 462	// Get data from the rollup contract
 463	rollupData, err := s.rollupSync(ethBlock)
 464	if err != nil {
 465		return nil, nil, tracerr.Wrap(err)
 466	}
 467
 468	// Get data from the auction contract
 469	auctionData, err := s.auctionSync(ethBlock)
 470	if err != nil {
 471		return nil, nil, tracerr.Wrap(err)
 472	}
 473
 474	// Get data from the WithdrawalDelayer contract
 475	wDelayerData, err := s.wdelayerSync(ethBlock)
 476	if err != nil {
 477		return nil, nil, tracerr.Wrap(err)
 478	}
 479
 480	for i := range rollupData.Withdrawals {
 481		withdrawal := &rollupData.Withdrawals[i]
 482		if !withdrawal.InstantWithdraw {
 483			wDelayerTransfers := wDelayerData.DepositsByTxHash[withdrawal.TxHash]
 484			if len(wDelayerTransfers) == 0 {
 485				return nil, nil, tracerr.Wrap(fmt.Errorf("WDelayer deposit corresponding to " +
 486					"non-instant rollup withdrawal not found"))
 487			}
 488			// Pop the first wDelayerTransfer to consume them in chronological order
 489			wDelayerTransfer := wDelayerTransfers[0]
 490			wDelayerData.DepositsByTxHash[withdrawal.TxHash] =
 491				wDelayerData.DepositsByTxHash[withdrawal.TxHash][1:]
 492
 493			withdrawal.Owner = wDelayerTransfer.Owner
 494			withdrawal.Token = wDelayerTransfer.Token
 495		}
 496	}
 497
 498	// Group all the block data into the structs to save into HistoryDB
 499	blockData := common.BlockData{
 500		Block:    *ethBlock,
 501		Rollup:   *rollupData,
 502		Auction:  *auctionData,
 503		WDelayer: *wDelayerData,
 504	}
 505
 506	err = s.historyDB.AddBlockSCData(&blockData)
 507	if err != nil {
 508		return nil, nil, tracerr.Wrap(err)
 509	}
 510
 511	batchesLen := len(rollupData.Batches)
 512	if batchesLen == 0 {
 513		s.stats.UpdateSync(ethBlock, nil, nil, nil)
 514	} else {
 515		var lastL1BatchBlock *int64
 516		var lastForgeL1TxsNum *int64
 517		for _, batchData := range rollupData.Batches {
 518			if batchData.L1Batch {
 519				lastL1BatchBlock = &batchData.Batch.EthBlockNum
 520				lastForgeL1TxsNum = batchData.Batch.ForgeL1TxsNum
 521			}
 522		}
 523		s.stats.UpdateSync(ethBlock,
 524			&rollupData.Batches[batchesLen-1].Batch.BatchNum,
 525			lastL1BatchBlock, lastForgeL1TxsNum)
 526	}
 527	var firstBatchBlockNum *int64
 528	if len(rollupData.Batches) > 0 {
 529		firstBatchBlockNum = &rollupData.Batches[0].Batch.EthBlockNum
 530	}
 531	if err := s.updateCurrentSlotIfSync(false, firstBatchBlockNum); err != nil {
 532		return nil, nil, tracerr.Wrap(err)
 533	}
 534
 535	log.Debugw("Synced block",
 536		"syncLastBlockNum", s.stats.Sync.LastBlock.Num,
 537		"syncBlocksPerc", s.stats.blocksPerc(),
 538		"ethLastBlockNum", s.stats.Eth.LastBlock.Num,
 539	)
 540	for _, batchData := range rollupData.Batches {
 541		log.Debugw("Synced batch",
 542			"syncLastBatch", batchData.Batch.BatchNum,
 543			"syncBatchesPerc", s.stats.batchesPerc(int64(batchData.Batch.BatchNum)),
 544			"ethLastBatch", s.stats.Eth.LastBatch,
 545		)
 546	}
 547
 548	return &blockData, nil, nil
 549}
 550
 551// reorg manages a reorg, updating History and State DB as needed.  Keeps
 552// checking previous blocks from the HistoryDB against the blockchain until a
 553// block hash match is found.  All future blocks in the HistoryDB and
 554// corresponding batches in StateBD are discarded.  Returns the last valid
 555// blockNum from the HistoryDB.
 556func (s *Synchronizer) reorg(uncleBlock *common.Block) (int64, error) {
 557	blockNum := uncleBlock.Num
 558
 559	var block *common.Block
 560	for blockNum >= s.startBlockNum {
 561		ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), blockNum)
 562		if err != nil {
 563			return 0, tracerr.Wrap(fmt.Errorf("ethClient.EthBlockByNumber: %w", err))
 564		}
 565
 566		block, err = s.historyDB.GetBlock(blockNum)
 567		if err != nil {
 568			return 0, tracerr.Wrap(fmt.Errorf("historyDB.GetBlock: %w", err))
 569		}
 570		if block.Hash == ethBlock.Hash {
 571			log.Debugf("Found valid block: %v", blockNum)
 572			break
 573		}
 574		blockNum--
 575	}
 576	total := uncleBlock.Num - block.Num
 577	log.Debugw("Discarding blocks", "total", total, "from", uncleBlock.Num, "to", block.Num+1)
 578
 579	// Set History DB and State DB to the correct state
 580	err := s.historyDB.Reorg(block.Num)
 581	if err != nil {
 582		return 0, tracerr.Wrap(err)
 583	}
 584
 585	if err := s.resetState(block); err != nil {
 586		return 0, tracerr.Wrap(err)
 587	}
 588
 589	return block.Num, nil
 590}
 591
 592func getInitialVariables(ethClient eth.ClientInterface,
 593	consts *SCConsts) (*SCVariables, *StartBlockNums, error) {
 594	rollupInit, rollupInitBlock, err := ethClient.RollupEventInit()
 595	if err != nil {
 596		return nil, nil, tracerr.Wrap(err)
 597	}
 598	auctionInit, auctionInitBlock, err := ethClient.AuctionEventInit()
 599	if err != nil {
 600		return nil, nil, tracerr.Wrap(err)
 601	}
 602	wDelayerInit, wDelayerInitBlock, err := ethClient.WDelayerEventInit()
 603	if err != nil {
 604		return nil, nil, tracerr.Wrap(err)
 605	}
 606	rollupVars := rollupInit.RollupVariables()
 607	auctionVars := auctionInit.AuctionVariables(consts.Auction.InitialMinimalBidding)
 608	wDelayerVars := wDelayerInit.WDelayerVariables()
 609	return &SCVariables{
 610			Rollup:   *rollupVars,
 611			Auction:  *auctionVars,
 612			WDelayer: *wDelayerVars,
 613		}, &StartBlockNums{
 614			Rollup:   rollupInitBlock,
 615			Auction:  auctionInitBlock,
 616			WDelayer: wDelayerInitBlock,
 617		}, nil
 618}
 619
 620func (s *Synchronizer) resetState(block *common.Block) error {
 621	rollup, auction, wDelayer, err := s.historyDB.GetSCVars()
 622	// If SCVars are not in the HistoryDB, this is probably the first run
 623	// of the Synchronizer: store the initial vars taken from config
 624	if tracerr.Unwrap(err) == sql.ErrNoRows {
 625		vars := s.initVars
 626		log.Info("Setting initial SCVars in HistoryDB")
 627		if err = s.historyDB.SetInitialSCVars(&vars.Rollup, &vars.Auction, &vars.WDelayer); err != nil {
 628			return tracerr.Wrap(fmt.Errorf("historyDB.SetInitialSCVars: %w", err))
 629		}
 630		s.vars.Rollup = *vars.Rollup.Copy()
 631		s.vars.Auction = *vars.Auction.Copy()
 632		s.vars.WDelayer = *vars.WDelayer.Copy()
 633		// Add initial boot coordinator to HistoryDB
 634		if err := s.historyDB.AddCoordinators([]common.Coordinator{{
 635			Forger:      s.initVars.Auction.BootCoordinator,
 636			URL:         s.initVars.Auction.BootCoordinatorURL,
 637			EthBlockNum: s.initVars.Auction.EthBlockNum,
 638		}}); err != nil {
 639			return tracerr.Wrap(err)
 640		}
 641	} else if err != nil {
 642		return tracerr.Wrap(err)
 643	} else {
 644		s.vars.Rollup = *rollup
 645		s.vars.Auction = *auction
 646		s.vars.WDelayer = *wDelayer
 647	}
 648
 649	batchNum, err := s.historyDB.GetLastBatchNum()
 650	if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 651		return tracerr.Wrap(fmt.Errorf("historyDB.GetLastBatchNum: %w", err))
 652	}
 653	if tracerr.Unwrap(err) == sql.ErrNoRows {
 654		batchNum = 0
 655	}
 656
 657	lastL1BatchBlockNum, err := s.historyDB.GetLastL1BatchBlockNum()
 658	if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 659		return tracerr.Wrap(fmt.Errorf("historyDB.GetLastL1BatchBlockNum: %w", err))
 660	}
 661	if tracerr.Unwrap(err) == sql.ErrNoRows {
 662		lastL1BatchBlockNum = 0
 663	}
 664
 665	lastForgeL1TxsNum, err := s.historyDB.GetLastL1TxsNum()
 666	if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
 667		return tracerr.Wrap(fmt.Errorf("historyDB.GetLastL1BatchBlockNum: %w", err))
 668	}
 669	if tracerr.Unwrap(err) == sql.ErrNoRows || lastForgeL1TxsNum == nil {
 670		n := int64(-1)
 671		lastForgeL1TxsNum = &n
 672	}
 673
 674	err = s.stateDB.Reset(batchNum)
 675	if err != nil {
 676		return tracerr.Wrap(fmt.Errorf("stateDB.Reset: %w", err))
 677	}
 678
 679	s.stats.UpdateSync(block, &batchNum, &lastL1BatchBlockNum, lastForgeL1TxsNum)
 680
 681	if err := s.updateCurrentSlotIfSync(true, nil); err != nil {
 682		return tracerr.Wrap(err)
 683	}
 684	return nil
 685}
 686
 687// rollupSync retreives all the Rollup Smart Contract Data that happened at
 688// ethBlock.blockNum with ethBlock.Hash.
 689func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, error) {
 690	blockNum := ethBlock.Num
 691	var rollupData = common.NewRollupData()
 692	// var forgeL1TxsNum int64
 693
 694	// Get rollup events in the block, and make sure the block hash matches
 695	// the expected one.
 696	rollupEvents, blockHash, err := s.ethClient.RollupEventsByBlock(blockNum)
 697	if err != nil {
 698		return nil, tracerr.Wrap(err)
 699	}
 700	// No events in this block
 701	if blockHash == nil {
 702		return &rollupData, nil
 703	}
 704	if *blockHash != ethBlock.Hash {
 705		log.Errorw("Block hash mismatch in Rollup events", "expected", ethBlock.Hash.String(),
 706			"got", blockHash.String())
 707		return nil, tracerr.Wrap(eth.ErrBlockHashMismatchEvent)
 708	}
 709
 710	var nextForgeL1TxsNum int64 // forgeL1TxsNum for the next L1Batch
 711	nextForgeL1TxsNumPtr, err := s.historyDB.GetLastL1TxsNum()
 712	if err != nil {
 713		return nil, tracerr.Wrap(err)
 714	}
 715	if nextForgeL1TxsNumPtr != nil {
 716		nextForgeL1TxsNum = *nextForgeL1TxsNumPtr + 1
 717	} else {
 718		nextForgeL1TxsNum = 0
 719	}
 720
 721	// Get L1UserTX
 722	rollupData.L1UserTxs, err = getL1UserTx(rollupEvents.L1UserTx, blockNum)
 723	if err != nil {
 724		return nil, tracerr.Wrap(err)
 725	}
 726
 727	// Get ForgeBatch events to get the L1CoordinatorTxs
 728	for _, evtForgeBatch := range rollupEvents.ForgeBatch {
 729		batchData := common.NewBatchData()
 730		position := 0
 731
 732		// Get the input for each Tx
 733		forgeBatchArgs, sender, err := s.ethClient.RollupForgeBatchArgs(evtForgeBatch.EthTxHash,
 734			evtForgeBatch.L1UserTxsLen)
 735		if err != nil {
 736			return nil, tracerr.Wrap(err)
 737		}
 738
 739		batchNum := common.BatchNum(evtForgeBatch.BatchNum)
 740		var l1UserTxs []common.L1Tx
 741		// Check if this is a L1Batch to get L1 Tx from it
 742		if forgeBatchArgs.L1Batch {
 743			// Get L1UserTxs with toForgeL1TxsNum, which correspond
 744			// to the L1UserTxs that are forged in this batch, so
 745			// that stateDB can process them.
 746
 747			// First try to find them in HistoryDB.
 748			l1UserTxs, err = s.historyDB.GetUnforgedL1UserTxs(nextForgeL1TxsNum)
 749			if err != nil {
 750				return nil, tracerr.Wrap(err)
 751			}
 752			// Apart from the DB, try to find them in this block.
 753			// This could happen because in a block there could be
 754			// multiple batches with L1Batch = true (although it's
 755			// a very rare case).  If not found in the DB and the
 756			// block doesn't contain the l1UserTxs, it means that
 757			// the L1UserTxs queue with toForgeL1TxsNum was closed
 758			// empty, so we leave `l1UserTxs` as an empty slice.
 759			for _, l1UserTx := range rollupData.L1UserTxs {
 760				if *l1UserTx.ToForgeL1TxsNum == nextForgeL1TxsNum {
 761					l1UserTxs = append(l1UserTxs, l1UserTx)
 762				}
 763			}
 764
 765			position = len(l1UserTxs)
 766		}
 767		// Get L1 Coordinator Txs
 768		for i := range forgeBatchArgs.L1CoordinatorTxs {
 769			l1CoordinatorTx := forgeBatchArgs.L1CoordinatorTxs[i]
 770			l1CoordinatorTx.Position = position
 771			// l1CoordinatorTx.ToForgeL1TxsNum = &forgeL1TxsNum
 772			l1CoordinatorTx.UserOrigin = false
 773			l1CoordinatorTx.EthBlockNum = blockNum
 774			l1CoordinatorTx.BatchNum = &batchNum
 775			l1Tx, err := common.NewL1Tx(&l1CoordinatorTx)
 776			if err != nil {
 777				return nil, tracerr.Wrap(err)
 778			}
 779
 780			batchData.L1CoordinatorTxs = append(batchData.L1CoordinatorTxs, *l1Tx)
 781			position++
 782			// fmt.Println("DGB l1coordtx")
 783		}
 784
 785		// Insert all the txs forged in this batch (l1UserTxs,
 786		// L1CoordinatorTxs, PoolL2Txs) into stateDB so that they are
 787		// processed.
 788
 789		// Set TxType to the forged L2Txs
 790		for i := range forgeBatchArgs.L2TxsData {
 791			if err := forgeBatchArgs.L2TxsData[i].SetType(); err != nil {
 792				return nil, tracerr.Wrap(err)
 793			}
 794		}
 795
 796		// Transform L2 txs to PoolL2Txs
 797		poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // NOTE: This is a big ugly, find a better way
 798
 799		// ProcessTxs updates poolL2Txs adding: Nonce (and also TokenID, but we don't use it).
 800		//nolint:gomnd
 801		tpc := txprocessor.Config{ // TODO TMP
 802			NLevels:  32,
 803			MaxFeeTx: 64,
 804			MaxTx:    512,
 805			MaxL1Tx:  64,
 806			ChainID:  uint16(0),
 807		}
 808		tp := txprocessor.NewTxProcessor(s.stateDB, tpc)
 809
 810		processTxsOut, err := tp.ProcessTxs(forgeBatchArgs.FeeIdxCoordinator,
 811			l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs)
 812		if err != nil {
 813			return nil, tracerr.Wrap(err)
 814		}
 815
 816		// Transform processed PoolL2 txs to L2 and store in BatchData
 817		l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way
 818		if err != nil {
 819			return nil, tracerr.Wrap(err)
 820		}
 821
 822		// Set TxID, BlockNum, BatchNum and Position to the forged L2Txs
 823		for i := range l2Txs {
 824			if err := l2Txs[i].SetID(); err != nil {
 825				return nil, tracerr.Wrap(err)
 826			}
 827			l2Txs[i].EthBlockNum = blockNum
 828			l2Txs[i].BatchNum = batchNum
 829			l2Txs[i].Position = position
 830			position++
 831		}
 832		batchData.L2Txs = l2Txs
 833
 834		// Set the BatchNum in the forged L1UserTxs
 835		for i := range l1UserTxs {
 836			l1UserTxs[i].BatchNum = &batchNum
 837		}
 838		batchData.L1UserTxs = l1UserTxs
 839
 840		// Set batchNum in exits
 841		for i := range processTxsOut.ExitInfos {
 842			exit := &processTxsOut.ExitInfos[i]
 843			exit.BatchNum = batchNum
 844		}
 845		batchData.ExitTree = processTxsOut.ExitInfos
 846
 847		for i := range processTxsOut.CreatedAccounts {
 848			createdAccount := &processTxsOut.CreatedAccounts[i]
 849			createdAccount.Nonce = 0
 850			createdAccount.Balance = big.NewInt(0)
 851			createdAccount.BatchNum = batchNum
 852		}
 853		batchData.CreatedAccounts = processTxsOut.CreatedAccounts
 854
 855		slotNum := int64(0)
 856		if ethBlock.Num >= s.consts.Auction.GenesisBlockNum {
 857			slotNum = (ethBlock.Num - s.consts.Auction.GenesisBlockNum) /
 858				int64(s.consts.Auction.BlocksPerSlot)
 859		}
 860
 861		// Get Batch information
 862		batch := common.Batch{
 863			BatchNum:           batchNum,
 864			EthBlockNum:        blockNum,
 865			ForgerAddr:         *sender,
 866			CollectedFees:      processTxsOut.CollectedFees,
 867			FeeIdxsCoordinator: forgeBatchArgs.FeeIdxCoordinator,
 868			StateRoot:          forgeBatchArgs.NewStRoot,
 869			NumAccounts:        len(batchData.CreatedAccounts),
 870			LastIdx:            forgeBatchArgs.NewLastIdx,
 871			ExitRoot:           forgeBatchArgs.NewExitRoot,
 872			SlotNum:            slotNum,
 873		}
 874		nextForgeL1TxsNumCpy := nextForgeL1TxsNum
 875		if forgeBatchArgs.L1Batch {
 876			batch.ForgeL1TxsNum = &nextForgeL1TxsNumCpy
 877			batchData.L1Batch = true
 878			nextForgeL1TxsNum++
 879		}
 880		batchData.Batch = batch
 881		rollupData.Batches = append(rollupData.Batches, *batchData)
 882	}
 883
 884	// Get Registered Tokens
 885	for _, evtAddToken := range rollupEvents.AddToken {
 886		var token common.Token
 887
 888		token.TokenID = common.TokenID(evtAddToken.TokenID)
 889		token.EthAddr = evtAddToken.TokenAddress
 890		token.EthBlockNum = blockNum
 891
 892		if consts, err := s.ethClient.EthERC20Consts(evtAddToken.TokenAddress); err != nil {
 893			log.Warnw("Error retreiving ERC20 token constants", "addr", evtAddToken.TokenAddress)
 894			token.Name = "ERC20_ETH_ERROR"
 895			token.Symbol = "ERROR"
 896			token.Decimals = 1
 897		} else {
 898			token.Name = cutStringMax(consts.Name, 20)
 899			token.Symbol = cutStringMax(consts.Symbol, 10)
 900			token.Decimals = consts.Decimals
 901		}
 902
 903		rollupData.AddedTokens = append(rollupData.AddedTokens, token)
 904	}
 905
 906	for _, evt := range rollupEvents.UpdateBucketWithdraw {
 907		rollupData.UpdateBucketWithdraw = append(rollupData.UpdateBucketWithdraw,
 908			common.BucketUpdate{
 909				EthBlockNum: blockNum,
 910				NumBucket:   evt.NumBucket,
 911				BlockStamp:  evt.BlockStamp,
 912				Withdrawals: evt.Withdrawals,
 913			})
 914	}
 915
 916	for _, evt := range rollupEvents.Withdraw {
 917		rollupData.Withdrawals = append(rollupData.Withdrawals, common.WithdrawInfo{
 918			Idx:             common.Idx(evt.Idx),
 919			NumExitRoot:     common.BatchNum(evt.NumExitRoot),
 920			InstantWithdraw: evt.InstantWithdraw,
 921			TxHash:          evt.TxHash,
 922		})
 923	}
 924
 925	for _, evt := range rollupEvents.UpdateTokenExchange {
 926		if len(evt.AddressArray) != len(evt.ValueArray) {
 927			return nil, tracerr.Wrap(fmt.Errorf("in RollupEventUpdateTokenExchange "+
 928				"len(AddressArray) != len(ValueArray) (%v != %v)",
 929				len(evt.AddressArray), len(evt.ValueArray)))
 930		}
 931		for i := range evt.AddressArray {
 932			rollupData.TokenExchanges = append(rollupData.TokenExchanges,
 933				common.TokenExchange{
 934					EthBlockNum: blockNum,
 935					Address:     evt.AddressArray[i],
 936					ValueUSD:    int64(evt.ValueArray[i]),
 937				})
 938		}
 939	}
 940
 941	varsUpdate := false
 942
 943	for _, evt := range rollupEvents.UpdateForgeL1L2BatchTimeout {
 944		s.vars.Rollup.ForgeL1L2BatchTimeout = evt.NewForgeL1L2BatchTimeout
 945		varsUpdate = true
 946	}
 947
 948	for _, evt := range rollupEvents.UpdateFeeAddToken {
 949		s.vars.Rollup.FeeAddToken = evt.NewFeeAddToken
 950		varsUpdate = true
 951	}
 952
 953	for _, evt := range rollupEvents.UpdateWithdrawalDelay {
 954		s.vars.Rollup.WithdrawalDelay = evt.NewWithdrawalDelay
 955		varsUpdate = true
 956	}
 957
 958	// NOTE: We skip the event rollupEvents.SafeMode because the
 959	// implementation RollupEventsByBlock already inserts a non-existing
 960	// RollupEventUpdateBucketsParameters into UpdateBucketsParameters with
 961	// all the bucket values at 0 and SafeMode = true
 962
 963	for _, evt := range rollupEvents.UpdateBucketsParameters {
 964		for i, bucket := range evt.ArrayBuckets {
 965			s.vars.Rollup.Buckets[i] = common.BucketParams{
 966				CeilUSD:             bucket.CeilUSD,
 967				Withdrawals:         bucket.Withdrawals,
 968				BlockWithdrawalRate: bucket.BlockWithdrawalRate,
 969				MaxWithdrawals:      bucket.MaxWithdrawals,
 970			}
 971		}
 972		s.vars.Rollup.SafeMode = evt.SafeMode
 973		varsUpdate = true
 974	}
 975
 976	if varsUpdate {
 977		s.vars.Rollup.EthBlockNum = blockNum
 978		rollupData.Vars = s.vars.Rollup.Copy()
 979	}
 980
 981	return &rollupData, nil
 982}
 983
 984func cutStringMax(s string, max int) string {
 985	if len(s) > max {
 986		return s[:max]
 987	}
 988	return s
 989}
 990
 991// auctionSync gets information from the Auction Contract
 992func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, error) {
 993	blockNum := ethBlock.Num
 994	var auctionData = common.NewAuctionData()
 995
 996	// Get auction events in the block
 997	auctionEvents, blockHash, err := s.ethClient.AuctionEventsByBlock(blockNum)
 998	if err != nil {
 999		return nil, tracerr.Wrap(err)
1000	}
1001	// No events in this block
1002	if blockHash == nil {
1003		return &auctionData, nil
1004	}
1005	if *blockHash != ethBlock.Hash {
1006		log.Errorw("Block hash mismatch in Auction events", "expected", ethBlock.Hash.String(),
1007			"got", blockHash.String())
1008		return nil, tracerr.Wrap(eth.ErrBlockHashMismatchEvent)
1009	}
1010
1011	// Get bids
1012	for _, evt := range auctionEvents.NewBid {
1013		bid := common.Bid{
1014			SlotNum:     evt.Slot,
1015			BidValue:    evt.BidAmount,
1016			Bidder:      evt.Bidder,
1017			EthBlockNum: blockNum,
1018		}
1019		auctionData.Bids = append(auctionData.Bids, bid)
1020	}
1021
1022	// Get Coordinators
1023	for _, evt := range auctionEvents.SetCoordinator {
1024		coordinator := common.Coordinator{
1025			Bidder:      evt.BidderAddress,
1026			Forger:      evt.ForgerAddress,
1027			URL:         evt.CoordinatorURL,
1028			EthBlockNum: blockNum,
1029		}
1030		auctionData.Coordinators = append(auctionData.Coordinators, coordinator)
1031	}
1032
1033	varsUpdate := false
1034
1035	for _, evt := range auctionEvents.NewSlotDeadline {
1036		s.vars.Auction.SlotDeadline = evt.NewSlotDeadline
1037		varsUpdate = true
1038	}
1039	for _, evt := range auctionEvents.NewClosedAuctionSlots {
1040		s.vars.Auction.ClosedAuctionSlots = evt.NewClosedAuctionSlots
1041		varsUpdate = true
1042	}
1043	for _, evt := range auctionEvents.NewOutbidding {
1044		s.vars.Auction.Outbidding = evt.NewOutbidding
1045		varsUpdate = true
1046	}
1047	for _, evt := range auctionEvents.NewDonationAddress {
1048		s.vars.Auction.DonationAddress = evt.NewDonationAddress
1049		varsUpdate = true
1050	}
1051	for _, evt := range auctionEvents.NewBootCoordinator {
1052		s.vars.Auction.BootCoordinator = evt.NewBootCoordinator
1053		s.vars.Auction.BootCoordinatorURL = evt.NewBootCoordinatorURL
1054		varsUpdate = true
1055		// Add new boot coordinator
1056		auctionData.Coordinators = append(auctionData.Coordinators, common.Coordinator{
1057			Forger:      evt.NewBootCoordinator,
1058			URL:         evt.NewBootCoordinatorURL,
1059			EthBlockNum: blockNum,
1060		})
1061	}
1062	for _, evt := range auctionEvents.NewOpenAuctionSlots {
1063		s.vars.Auction.OpenAuctionSlots = evt.NewOpenAuctionSlots
1064		varsUpdate = true
1065	}
1066	for _, evt := range auctionEvents.NewAllocationRatio {
1067		s.vars.Auction.AllocationRatio = evt.NewAllocationRatio
1068		varsUpdate = true
1069	}
1070	for _, evt := range auctionEvents.NewDefaultSlotSetBid {
1071		if evt.SlotSet > 6 { //nolint:gomnd
1072			return nil, tracerr.Wrap(fmt.Errorf("unexpected SlotSet in "+
1073				"auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet))
1074		}
1075		s.vars.Auction.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid
1076		s.vars.Auction.DefaultSlotSetBidSlotNum = s.consts.Auction.SlotNum(blockNum) +
1077			int64(s.vars.Auction.ClosedAuctionSlots) + 1
1078		varsUpdate = true
1079	}
1080
1081	// NOTE: We ignore NewForgeAllocated
1082	// NOTE: We ignore NewForge because we're already tracking ForgeBatch event from Rollup
1083	// NOTE: We ignore HEZClaimed
1084
1085	if varsUpdate {
1086		s.vars.Auction.EthBlockNum = blockNum
1087		auctionData.Vars = s.vars.Auction.Copy()
1088	}
1089
1090	return &auctionData, nil
1091}
1092
1093// wdelayerSync gets information from the Withdrawal Delayer Contract
1094func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerData, error) {
1095	blockNum := ethBlock.Num
1096	wDelayerData := common.NewWDelayerData()
1097
1098	// Get wDelayer events in the block
1099	wDelayerEvents, blockHash, err := s.ethClient.WDelayerEventsByBlock(blockNum)
1100	if err != nil {
1101		return nil, tracerr.Wrap(err)
1102	}
1103	// No events in this block
1104	if blockHash == nil {
1105		return &wDelayerData, nil
1106	}
1107	if *blockHash != ethBlock.Hash {
1108		log.Errorw("Block hash mismatch in WDelayer events", "expected", ethBlock.Hash.String(),
1109			"got", blockHash.String())
1110		return nil, tracerr.Wrap(eth.ErrBlockHashMismatchEvent)
1111	}
1112
1113	for _, evt := range wDelayerEvents.Deposit {
1114		wDelayerData.Deposits = append(wDelayerData.Deposits, common.WDelayerTransfer{
1115			Owner:  evt.Owner,
1116			Token:  evt.Token,
1117			Amount: evt.Amount,
1118		})
1119		wDelayerData.DepositsByTxHash[evt.TxHash] =
1120			append(wDelayerData.DepositsByTxHash[evt.TxHash],
1121				&wDelayerData.Deposits[len(wDelayerData.Deposits)-1])
1122	}
1123	for _, evt := range wDelayerEvents.Withdraw {
1124		wDelayerData.Withdrawals = append(wDelayerData.Withdrawals, common.WDelayerTransfer{
1125			Owner:  evt.Owner,
1126			Token:  evt.Token,
1127			Amount: evt.Amount,
1128		})
1129	}
1130	for _, evt := range wDelayerEvents.EscapeHatchWithdrawal {
1131		wDelayerData.EscapeHatchWithdrawals = append(wDelayerData.EscapeHatchWithdrawals,
1132			common.WDelayerEscapeHatchWithdrawal{
1133				EthBlockNum: blockNum,
1134				Who:         evt.Who,
1135				To:          evt.To,
1136				TokenAddr:   evt.Token,
1137				Amount:      evt.Amount,
1138			})
1139	}
1140
1141	varsUpdate := false
1142
1143	for range wDelayerEvents.EmergencyModeEnabled {
1144		s.vars.WDelayer.EmergencyMode = true
1145		s.vars.WDelayer.EmergencyModeStartingBlock = blockNum
1146		varsUpdate = true
1147	}
1148	for _, evt := range wDelayerEvents.NewWithdrawalDelay {
1149		s.vars.WDelayer.WithdrawalDelay = evt.WithdrawalDelay
1150		varsUpdate = true
1151	}
1152	for _, evt := range wDelayerEvents.NewEmergencyCouncil {
1153		s.vars.WDelayer.EmergencyCouncilAddress = evt.NewEmergencyCouncil
1154		varsUpdate = true
1155	}
1156	for _, evt := range wDelayerEvents.NewHermezGovernanceAddress {
1157		s.vars.WDelayer.HermezGovernanceAddress = evt.NewHermezGovernanceAddress
1158		varsUpdate = true
1159	}
1160
1161	if varsUpdate {
1162		s.vars.WDelayer.EthBlockNum = blockNum
1163		wDelayerData.Vars = s.vars.WDelayer.Copy()
1164	}
1165
1166	return &wDelayerData, nil
1167}
1168
1169func getL1UserTx(eventsL1UserTx []eth.RollupEventL1UserTx, blockNum int64) ([]common.L1Tx, error) {
1170	l1Txs := make([]common.L1Tx, len(eventsL1UserTx))
1171	for i := range eventsL1UserTx {
1172		eventsL1UserTx[i].L1UserTx.EthBlockNum = blockNum
1173		// Check validity of L1UserTx
1174		l1Tx, err := common.NewL1Tx(&eventsL1UserTx[i].L1UserTx)
1175		if err != nil {
1176			return nil, tracerr.Wrap(err)
1177		}
1178		l1Txs[i] = *l1Tx
1179	}
1180	return l1Txs, nil
1181}