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		// Set TxType to the forged L2Txs
 757		for i := range forgeBatchArgs.L2TxsData {
 758			if err := forgeBatchArgs.L2TxsData[i].SetType(); err != nil {
 759				return nil, tracerr.Wrap(err)
 760			}
 761		}
 762
 763		// Transform L2 txs to PoolL2Txs
 764		poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // NOTE: This is a big ugly, find a better way
 765
 766		// ProcessTxs updates poolL2Txs adding: Nonce (and also TokenID, but we don't use it).
 767		//nolint:gomnd
 768		ptc := statedb.ProcessTxsConfig{ // TODO TMP
 769			NLevels:  32,
 770			MaxFeeTx: 64,
 771			MaxTx:    512,
 772			MaxL1Tx:  64,
 773		}
 774		processTxsOut, err := s.stateDB.ProcessTxs(ptc, forgeBatchArgs.FeeIdxCoordinator,
 775			l1UserTxs, batchData.L1CoordinatorTxs, poolL2Txs)
 776		if err != nil {
 777			return nil, tracerr.Wrap(err)
 778		}
 779
 780		// Transform processed PoolL2 txs to L2 and store in BatchData
 781		l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way
 782		if err != nil {
 783			return nil, tracerr.Wrap(err)
 784		}
 785
 786		// Set TxID, BlockNum, BatchNum and Position to the forged L2Txs
 787		for i := range l2Txs {
 788			if err := l2Txs[i].SetID(); err != nil {
 789				return nil, err
 790			}
 791			l2Txs[i].EthBlockNum = blockNum
 792			l2Txs[i].BatchNum = batchNum
 793			l2Txs[i].Position = position
 794			position++
 795		}
 796		batchData.L2Txs = l2Txs
 797
 798		// Set the BatchNum in the forged L1UserTxs
 799		for i := range l1UserTxs {
 800			l1UserTxs[i].BatchNum = &batchNum
 801		}
 802		batchData.L1UserTxs = l1UserTxs
 803
 804		// Set batchNum in exits
 805		for i := range processTxsOut.ExitInfos {
 806			exit := &processTxsOut.ExitInfos[i]
 807			exit.BatchNum = batchNum
 808		}
 809		batchData.ExitTree = processTxsOut.ExitInfos
 810
 811		for i := range processTxsOut.CreatedAccounts {
 812			createdAccount := &processTxsOut.CreatedAccounts[i]
 813			createdAccount.Nonce = 0
 814			createdAccount.Balance = big.NewInt(0)
 815			createdAccount.BatchNum = batchNum
 816		}
 817		batchData.CreatedAccounts = processTxsOut.CreatedAccounts
 818
 819		slotNum := int64(0)
 820		if ethBlock.Num >= s.consts.Auction.GenesisBlockNum {
 821			slotNum = (ethBlock.Num - s.consts.Auction.GenesisBlockNum) /
 822				int64(s.consts.Auction.BlocksPerSlot)
 823		}
 824
 825		// Get Batch information
 826		batch := common.Batch{
 827			BatchNum:           batchNum,
 828			EthBlockNum:        blockNum,
 829			ForgerAddr:         *sender,
 830			CollectedFees:      processTxsOut.CollectedFees,
 831			FeeIdxsCoordinator: forgeBatchArgs.FeeIdxCoordinator,
 832			StateRoot:          forgeBatchArgs.NewStRoot,
 833			NumAccounts:        len(batchData.CreatedAccounts),
 834			LastIdx:            forgeBatchArgs.NewLastIdx,
 835			ExitRoot:           forgeBatchArgs.NewExitRoot,
 836			SlotNum:            slotNum,
 837		}
 838		nextForgeL1TxsNumCpy := nextForgeL1TxsNum
 839		if forgeBatchArgs.L1Batch {
 840			batch.ForgeL1TxsNum = &nextForgeL1TxsNumCpy
 841			batchData.L1Batch = true
 842			nextForgeL1TxsNum++
 843		}
 844		batchData.Batch = batch
 845		rollupData.Batches = append(rollupData.Batches, *batchData)
 846	}
 847
 848	// Get Registered Tokens
 849	for _, evtAddToken := range rollupEvents.AddToken {
 850		var token common.Token
 851
 852		token.TokenID = common.TokenID(evtAddToken.TokenID)
 853		token.EthAddr = evtAddToken.TokenAddress
 854		token.EthBlockNum = blockNum
 855
 856		if consts, err := s.ethClient.EthERC20Consts(evtAddToken.TokenAddress); err != nil {
 857			log.Warnw("Error retreiving ERC20 token constants", "addr", evtAddToken.TokenAddress)
 858			token.Name = "ERC20_ETH_ERROR"
 859			token.Symbol = "ERROR"
 860			token.Decimals = 1
 861		} else {
 862			token.Name = cutStringMax(consts.Name, 20)
 863			token.Symbol = cutStringMax(consts.Symbol, 10)
 864			token.Decimals = consts.Decimals
 865		}
 866
 867		rollupData.AddedTokens = append(rollupData.AddedTokens, token)
 868	}
 869
 870	for _, evt := range rollupEvents.UpdateBucketWithdraw {
 871		rollupData.UpdateBucketWithdraw = append(rollupData.UpdateBucketWithdraw,
 872			common.BucketUpdate{
 873				EthBlockNum: blockNum,
 874				NumBucket:   evt.NumBucket,
 875				BlockStamp:  evt.BlockStamp,
 876				Withdrawals: evt.Withdrawals,
 877			})
 878	}
 879
 880	for _, evt := range rollupEvents.Withdraw {
 881		rollupData.Withdrawals = append(rollupData.Withdrawals, common.WithdrawInfo{
 882			Idx:             common.Idx(evt.Idx),
 883			NumExitRoot:     common.BatchNum(evt.NumExitRoot),
 884			InstantWithdraw: evt.InstantWithdraw,
 885			TxHash:          evt.TxHash,
 886		})
 887	}
 888
 889	for _, evt := range rollupEvents.UpdateTokenExchange {
 890		if len(evt.AddressArray) != len(evt.ValueArray) {
 891			return nil, tracerr.Wrap(fmt.Errorf("in RollupEventUpdateTokenExchange "+
 892				"len(AddressArray) != len(ValueArray) (%v != %v)",
 893				len(evt.AddressArray), len(evt.ValueArray)))
 894		}
 895		for i := range evt.AddressArray {
 896			rollupData.TokenExchanges = append(rollupData.TokenExchanges,
 897				common.TokenExchange{
 898					EthBlockNum: blockNum,
 899					Address:     evt.AddressArray[i],
 900					ValueUSD:    int64(evt.ValueArray[i]),
 901				})
 902		}
 903	}
 904
 905	varsUpdate := false
 906
 907	for _, evt := range rollupEvents.UpdateForgeL1L2BatchTimeout {
 908		s.vars.Rollup.ForgeL1L2BatchTimeout = evt.NewForgeL1L2BatchTimeout
 909		varsUpdate = true
 910	}
 911
 912	for _, evt := range rollupEvents.UpdateFeeAddToken {
 913		s.vars.Rollup.FeeAddToken = evt.NewFeeAddToken
 914		varsUpdate = true
 915	}
 916
 917	for _, evt := range rollupEvents.UpdateWithdrawalDelay {
 918		s.vars.Rollup.WithdrawalDelay = evt.NewWithdrawalDelay
 919		varsUpdate = true
 920	}
 921
 922	// NOTE: We skip the event rollupEvents.SafeMode because the
 923	// implementation RollupEventsByBlock already inserts a non-existing
 924	// RollupEventUpdateBucketsParameters into UpdateBucketsParameters with
 925	// all the bucket values at 0 and SafeMode = true
 926
 927	for _, evt := range rollupEvents.UpdateBucketsParameters {
 928		for i, bucket := range evt.ArrayBuckets {
 929			s.vars.Rollup.Buckets[i] = common.BucketParams{
 930				CeilUSD:             bucket.CeilUSD,
 931				Withdrawals:         bucket.Withdrawals,
 932				BlockWithdrawalRate: bucket.BlockWithdrawalRate,
 933				MaxWithdrawals:      bucket.MaxWithdrawals,
 934			}
 935		}
 936		s.vars.Rollup.SafeMode = evt.SafeMode
 937		varsUpdate = true
 938	}
 939
 940	if varsUpdate {
 941		s.vars.Rollup.EthBlockNum = blockNum
 942		rollupData.Vars = s.vars.Rollup.Copy()
 943	}
 944
 945	return &rollupData, nil
 946}
 947
 948func cutStringMax(s string, max int) string {
 949	if len(s) > max {
 950		return s[:max]
 951	}
 952	return s
 953}
 954
 955// auctionSync gets information from the Auction Contract
 956func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, error) {
 957	blockNum := ethBlock.Num
 958	var auctionData = common.NewAuctionData()
 959
 960	// Get auction events in the block
 961	auctionEvents, blockHash, err := s.ethClient.AuctionEventsByBlock(blockNum)
 962	if err != nil {
 963		return nil, tracerr.Wrap(err)
 964	}
 965	// No events in this block
 966	if blockHash == nil {
 967		return &auctionData, nil
 968	}
 969	if *blockHash != ethBlock.Hash {
 970		log.Errorw("Block hash mismatch in Auction events", "expected", ethBlock.Hash.String(),
 971			"got", blockHash.String())
 972		return nil, tracerr.Wrap(eth.ErrBlockHashMismatchEvent)
 973	}
 974
 975	// Get bids
 976	for _, evt := range auctionEvents.NewBid {
 977		bid := common.Bid{
 978			SlotNum:     evt.Slot,
 979			BidValue:    evt.BidAmount,
 980			Bidder:      evt.Bidder,
 981			EthBlockNum: blockNum,
 982		}
 983		auctionData.Bids = append(auctionData.Bids, bid)
 984	}
 985
 986	// Get Coordinators
 987	for _, evt := range auctionEvents.SetCoordinator {
 988		coordinator := common.Coordinator{
 989			Bidder:      evt.BidderAddress,
 990			Forger:      evt.ForgerAddress,
 991			URL:         evt.CoordinatorURL,
 992			EthBlockNum: blockNum,
 993		}
 994		auctionData.Coordinators = append(auctionData.Coordinators, coordinator)
 995	}
 996
 997	varsUpdate := false
 998
 999	for _, evt := range auctionEvents.NewSlotDeadline {
1000		s.vars.Auction.SlotDeadline = evt.NewSlotDeadline
1001		varsUpdate = true
1002	}
1003	for _, evt := range auctionEvents.NewClosedAuctionSlots {
1004		s.vars.Auction.ClosedAuctionSlots = evt.NewClosedAuctionSlots
1005		varsUpdate = true
1006	}
1007	for _, evt := range auctionEvents.NewOutbidding {
1008		s.vars.Auction.Outbidding = evt.NewOutbidding
1009		varsUpdate = true
1010	}
1011	for _, evt := range auctionEvents.NewDonationAddress {
1012		s.vars.Auction.DonationAddress = evt.NewDonationAddress
1013		varsUpdate = true
1014	}
1015	for _, evt := range auctionEvents.NewBootCoordinator {
1016		s.vars.Auction.BootCoordinator = evt.NewBootCoordinator
1017		s.vars.Auction.BootCoordinatorURL = evt.NewBootCoordinatorURL
1018		varsUpdate = true
1019	}
1020	for _, evt := range auctionEvents.NewOpenAuctionSlots {
1021		s.vars.Auction.OpenAuctionSlots = evt.NewOpenAuctionSlots
1022		varsUpdate = true
1023	}
1024	for _, evt := range auctionEvents.NewAllocationRatio {
1025		s.vars.Auction.AllocationRatio = evt.NewAllocationRatio
1026		varsUpdate = true
1027	}
1028	for _, evt := range auctionEvents.NewDefaultSlotSetBid {
1029		if evt.SlotSet > 6 { //nolint:gomnd
1030			return nil, tracerr.Wrap(fmt.Errorf("unexpected SlotSet in "+
1031				"auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet))
1032		}
1033		s.vars.Auction.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid
1034		s.vars.Auction.DefaultSlotSetBidSlotNum = s.consts.Auction.SlotNum(blockNum) +
1035			int64(s.vars.Auction.ClosedAuctionSlots) + 1
1036		varsUpdate = true
1037	}
1038
1039	// NOTE: We ignore NewForgeAllocated
1040	// NOTE: We ignore NewForge because we're already tracking ForgeBatch event from Rollup
1041	// NOTE: We ignore HEZClaimed
1042
1043	if varsUpdate {
1044		s.vars.Auction.EthBlockNum = blockNum
1045		auctionData.Vars = s.vars.Auction.Copy()
1046	}
1047
1048	return &auctionData, nil
1049}
1050
1051// wdelayerSync gets information from the Withdrawal Delayer Contract
1052func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerData, error) {
1053	blockNum := ethBlock.Num
1054	wDelayerData := common.NewWDelayerData()
1055
1056	// Get wDelayer events in the block
1057	wDelayerEvents, blockHash, err := s.ethClient.WDelayerEventsByBlock(blockNum)
1058	if err != nil {
1059		return nil, tracerr.Wrap(err)
1060	}
1061	// No events in this block
1062	if blockHash == nil {
1063		return &wDelayerData, nil
1064	}
1065	if *blockHash != ethBlock.Hash {
1066		log.Errorw("Block hash mismatch in WDelayer events", "expected", ethBlock.Hash.String(),
1067			"got", blockHash.String())
1068		return nil, tracerr.Wrap(eth.ErrBlockHashMismatchEvent)
1069	}
1070
1071	for _, evt := range wDelayerEvents.Deposit {
1072		wDelayerData.Deposits = append(wDelayerData.Deposits, common.WDelayerTransfer{
1073			Owner:  evt.Owner,
1074			Token:  evt.Token,
1075			Amount: evt.Amount,
1076		})
1077		wDelayerData.DepositsByTxHash[evt.TxHash] =
1078			append(wDelayerData.DepositsByTxHash[evt.TxHash],
1079				&wDelayerData.Deposits[len(wDelayerData.Deposits)-1])
1080	}
1081	for _, evt := range wDelayerEvents.Withdraw {
1082		wDelayerData.Withdrawals = append(wDelayerData.Withdrawals, common.WDelayerTransfer{
1083			Owner:  evt.Owner,
1084			Token:  evt.Token,
1085			Amount: evt.Amount,
1086		})
1087	}
1088	for _, evt := range wDelayerEvents.EscapeHatchWithdrawal {
1089		wDelayerData.EscapeHatchWithdrawals = append(wDelayerData.EscapeHatchWithdrawals,
1090			common.WDelayerEscapeHatchWithdrawal{
1091				EthBlockNum: blockNum,
1092				Who:         evt.Who,
1093				To:          evt.To,
1094				TokenAddr:   evt.Token,
1095				Amount:      evt.Amount,
1096			})
1097	}
1098
1099	varsUpdate := false
1100
1101	for range wDelayerEvents.EmergencyModeEnabled {
1102		s.vars.WDelayer.EmergencyMode = true
1103		s.vars.WDelayer.EmergencyModeStartingBlock = blockNum
1104		varsUpdate = true
1105	}
1106	for _, evt := range wDelayerEvents.NewWithdrawalDelay {
1107		s.vars.WDelayer.WithdrawalDelay = evt.WithdrawalDelay
1108		varsUpdate = true
1109	}
1110	for _, evt := range wDelayerEvents.NewEmergencyCouncil {
1111		s.vars.WDelayer.EmergencyCouncilAddress = evt.NewEmergencyCouncil
1112		varsUpdate = true
1113	}
1114	for _, evt := range wDelayerEvents.NewHermezGovernanceAddress {
1115		s.vars.WDelayer.HermezGovernanceAddress = evt.NewHermezGovernanceAddress
1116		varsUpdate = true
1117	}
1118
1119	if varsUpdate {
1120		s.vars.WDelayer.EthBlockNum = blockNum
1121		wDelayerData.Vars = s.vars.WDelayer.Copy()
1122	}
1123
1124	return &wDelayerData, nil
1125}
1126
1127func getL1UserTx(eventsL1UserTx []eth.RollupEventL1UserTx, blockNum int64) ([]common.L1Tx, error) {
1128	l1Txs := make([]common.L1Tx, len(eventsL1UserTx))
1129	for i := range eventsL1UserTx {
1130		eventsL1UserTx[i].L1UserTx.EthBlockNum = blockNum
1131		// Check validity of L1UserTx
1132		l1Tx, err := common.NewL1Tx(&eventsL1UserTx[i].L1UserTx)
1133		if err != nil {
1134			return nil, tracerr.Wrap(err)
1135		}
1136		l1Txs[i] = *l1Tx
1137	}
1138	return l1Txs, nil
1139}