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