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