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