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