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