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