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