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