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