hermez-node/synchronizer/synchronizer.go
synchronizer/synchronizer.goRaw
1package synchronizer
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "math/big"
8
9 "github.com/ethereum/go-ethereum"
10 "github.com/hermeznetwork/hermez-node/common"
11 "github.com/hermeznetwork/hermez-node/db/historydb"
12 "github.com/hermeznetwork/hermez-node/db/statedb"
13 "github.com/hermeznetwork/hermez-node/eth"
14 "github.com/hermeznetwork/hermez-node/log"
15)
16
17var (
18// ErrNotAbleToSync is used when there is not possible to find a valid block to sync
19// ErrNotAbleToSync = errors.New("it has not been possible to synchronize any block")
20)
21
22// // SyncronizerState describes the synchronization progress of the smart contracts
23// type SyncronizerState struct {
24// LastUpdate time.Time // last time this information was updated
25// CurrentBatchNum BatchNum // Last batch that was forged on the blockchain
26// CurrentBlockNum uint64 // Last block that was mined on Ethereum
27// CurrentToForgeL1TxsNum uint32
28// LastSyncedBatchNum BatchNum // last batch synchronized by the coordinator
29// LastSyncedBlockNum uint64 // last Ethereum block synchronized by the coordinator
30// LastSyncedToForgeL1TxsNum uint32
31// }
32
33// // SyncStatus is returned by the Status method of the Synchronizer
34// type SyncStatus struct {
35// CurrentBlock int64
36// CurrentBatch BatchNum
37// CurrentForgerAddr ethCommon.Address
38// NextForgerAddr ethCommon.Address
39// Synchronized bool
40// }
41
42// ConfigStartBlockNum sets the first block used to start tracking the smart
43// contracts
44type ConfigStartBlockNum struct {
45 Rollup int64 `validate:"required"`
46 Auction int64 `validate:"required"`
47 WDelayer int64 `validate:"required"`
48}
49
50// SCVariables joins all the smart contract variables in a single struct
51type SCVariables struct {
52 Rollup common.RollupVariables `validate:"required"`
53 Auction common.AuctionVariables `validate:"required"`
54 WDelayer common.WDelayerVariables `validate:"required"`
55}
56
57// Config is the Synchronizer configuration
58type Config struct {
59 StartBlockNum ConfigStartBlockNum
60 InitialVariables SCVariables
61}
62
63// Synchronizer implements the Synchronizer type
64type Synchronizer struct {
65 ethClient eth.ClientInterface
66 auctionConstants common.AuctionConstants
67 rollupConstants common.RollupConstants
68 wDelayerConstants common.WDelayerConstants
69 historyDB *historydb.HistoryDB
70 stateDB *statedb.StateDB
71 cfg Config
72 startBlockNum int64
73 vars SCVariables
74 // firstSavedBlock *common.Block
75 // mux sync.Mutex
76}
77
78// NewSynchronizer creates a new Synchronizer
79func NewSynchronizer(ethClient eth.ClientInterface, historyDB *historydb.HistoryDB,
80 stateDB *statedb.StateDB, cfg Config) (*Synchronizer, error) {
81 auctionConstants, err := ethClient.AuctionConstants()
82 if err != nil {
83 log.Errorw("NewSynchronizer ethClient.AuctionConstants()", "err", err)
84 return nil, err
85 }
86 rollupConstants, err := ethClient.RollupConstants()
87 if err != nil {
88 log.Errorw("NewSynchronizer ethClient.RollupConstants()", "err", err)
89 return nil, err
90 }
91 wDelayerConstants, err := ethClient.WDelayerConstants()
92 if err != nil {
93 log.Errorw("NewSynchronizer ethClient.WDelayerConstants()", "err", err)
94 return nil, err
95 }
96
97 // Set startBlockNum to the minimum between Auction, Rollup and
98 // WDelayer StartBlockNum
99 startBlockNum := cfg.StartBlockNum.Auction
100 if startBlockNum < cfg.StartBlockNum.Rollup {
101 startBlockNum = cfg.StartBlockNum.Rollup
102 }
103 if startBlockNum < cfg.StartBlockNum.WDelayer {
104 startBlockNum = cfg.StartBlockNum.WDelayer
105 }
106 s := &Synchronizer{
107 ethClient: ethClient,
108 auctionConstants: *auctionConstants,
109 rollupConstants: *rollupConstants,
110 wDelayerConstants: *wDelayerConstants,
111 historyDB: historyDB,
112 stateDB: stateDB,
113 cfg: cfg,
114 startBlockNum: startBlockNum,
115 }
116 return s, s.init()
117}
118
119// AuctionConstants returns the AuctionConstants read from the smart contract
120func (s *Synchronizer) AuctionConstants() *common.AuctionConstants {
121 return &s.auctionConstants
122}
123
124// RollupConstants returns the RollupConstants read from the smart contract
125func (s *Synchronizer) RollupConstants() *common.RollupConstants {
126 return &s.rollupConstants
127}
128
129// WDelayerConstants returns the WDelayerConstants read from the smart contract
130func (s *Synchronizer) WDelayerConstants() *common.WDelayerConstants {
131 return &s.wDelayerConstants
132}
133
134func (s *Synchronizer) init() error {
135 rollup, auction, wDelayer, err := s.historyDB.GetSCVars()
136 if err == sql.ErrNoRows {
137 rollup = &s.cfg.InitialVariables.Rollup
138 auction = &s.cfg.InitialVariables.Auction
139 wDelayer = &s.cfg.InitialVariables.WDelayer
140 log.Debug("Setting initial SCVars in HistoryDB")
141 if err = s.historyDB.SetInitialSCVars(rollup, auction, wDelayer); err != nil {
142 return err
143 }
144 }
145 s.vars.Rollup = *rollup
146 s.vars.Auction = *auction
147 s.vars.WDelayer = *wDelayer
148 return nil
149}
150
151// Sync2 attems to synchronize an ethereum block starting from lastSavedBlock.
152// If lastSavedBlock is nil, the lastSavedBlock value is obtained from de DB.
153// If a block is synched, it will be returned and also stored in the DB. If a
154// reorg is detected, the number of discarded blocks will be returned and no
155// synchronization will be made.
156// TODO: Be smart about locking: only lock during the read/write operations
157func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block) (*common.BlockData, *int64, error) {
158 var nextBlockNum int64 // next block number to sync
159 if lastSavedBlock == nil {
160 var err error
161 // Get lastSavedBlock from History DB
162 lastSavedBlock, err = s.historyDB.GetLastBlock()
163 if err != nil && err != sql.ErrNoRows {
164 return nil, nil, err
165 }
166 // If we don't have any stored block, we must do a full sync
167 // starting from the startBlockNum
168 if err == sql.ErrNoRows || lastSavedBlock.EthBlockNum == 0 {
169 nextBlockNum = s.startBlockNum
170 lastSavedBlock = nil
171 }
172 }
173 if lastSavedBlock != nil {
174 nextBlockNum = lastSavedBlock.EthBlockNum + 1
175 }
176
177 ethBlock, err := s.ethClient.EthBlockByNumber(ctx, nextBlockNum)
178 if err == ethereum.NotFound {
179 return nil, nil, nil
180 } else if err != nil {
181 return nil, nil, err
182 }
183 log.Debugf("ethBlock: num: %v, parent: %v, hash: %v", ethBlock.EthBlockNum, ethBlock.ParentHash.String(), ethBlock.Hash.String())
184
185 log.Debugw("Syncing...", "block", nextBlockNum)
186
187 // Check that the obtianed ethBlock.ParentHash == prevEthBlock.Hash; if not, reorg!
188 if lastSavedBlock != nil {
189 if lastSavedBlock.Hash != ethBlock.ParentHash {
190 // Reorg detected
191 log.Debugw("Reorg Detected",
192 "blockNum", ethBlock.EthBlockNum,
193 "block.parent(got)", ethBlock.ParentHash, "parent.hash(exp)", lastSavedBlock.Hash)
194 lastDBBlockNum, err := s.reorg(lastSavedBlock)
195 if err != nil {
196 return nil, nil, err
197 }
198 discarded := lastSavedBlock.EthBlockNum - lastDBBlockNum
199 return nil, &discarded, nil
200 }
201 }
202
203 // Get data from the rollup contract
204 rollupData, err := s.rollupSync(ethBlock)
205 if err != nil {
206 return nil, nil, err
207 }
208
209 // Get data from the auction contract
210 auctionData, err := s.auctionSync(ethBlock)
211 if err != nil {
212 return nil, nil, err
213 }
214
215 // Get data from the WithdrawalDelayer contract
216 wDelayerData, err := s.wdelayerSync(ethBlock)
217 if err != nil {
218 return nil, nil, err
219 }
220
221 for i := range rollupData.Withdrawals {
222 withdrawal := &rollupData.Withdrawals[i]
223 if !withdrawal.InstantWithdraw {
224 wDelayerTransfer, ok := wDelayerData.DepositsByTxHash[withdrawal.TxHash]
225 if !ok {
226 return nil, nil, fmt.Errorf("WDelayer deposit corresponding to " +
227 "non-instant rollup withdrawal not found")
228 }
229 withdrawal.Owner = wDelayerTransfer.Owner
230 withdrawal.Token = wDelayerTransfer.Token
231 }
232 }
233
234 // Group all the block data into the structs to save into HistoryDB
235 blockData := common.BlockData{
236 Block: *ethBlock,
237 Rollup: *rollupData,
238 Auction: *auctionData,
239 WDelayer: *wDelayerData,
240 }
241
242 // log.Debugw("Sync()", "block", blockData)
243 // err = s.historyDB.AddBlock(blockData.Block)
244 // if err != nil {
245 // return err
246 // }
247 err = s.historyDB.AddBlockSCData(&blockData)
248 if err != nil {
249 return nil, nil, err
250 }
251
252 return &blockData, nil, nil
253}
254
255// reorg manages a reorg, updating History and State DB as needed. Keeps
256// checking previous blocks from the HistoryDB against the blockchain until a
257// block hash match is found. All future blocks in the HistoryDB and
258// corresponding batches in StateBD are discarded. Returns the last valid
259// blockNum from the HistoryDB.
260func (s *Synchronizer) reorg(uncleBlock *common.Block) (int64, error) {
261 blockNum := uncleBlock.EthBlockNum
262
263 for blockNum >= s.startBlockNum {
264 ethBlock, err := s.ethClient.EthBlockByNumber(context.Background(), blockNum)
265 if err != nil {
266 return 0, err
267 }
268
269 block, err := s.historyDB.GetBlock(blockNum)
270 if err != nil {
271 return 0, err
272 }
273 if block.Hash == ethBlock.Hash {
274 log.Debugf("Found valid block: %v", blockNum)
275 break
276 }
277 blockNum--
278 }
279 total := uncleBlock.EthBlockNum - blockNum
280 log.Debugw("Discarding blocks", "total", total, "from", uncleBlock.EthBlockNum, "to", blockNum+1)
281
282 // Set History DB and State DB to the correct state
283 err := s.historyDB.Reorg(blockNum)
284 if err != nil {
285 return 0, err
286 }
287
288 batchNum, err := s.historyDB.GetLastBatchNum()
289 if err != nil && err != sql.ErrNoRows {
290 return 0, err
291 }
292 if err == sql.ErrNoRows {
293 batchNum = 0
294 }
295 err = s.stateDB.Reset(batchNum)
296 if err != nil {
297 return 0, err
298 }
299
300 return blockNum, nil
301}
302
303// TODO: Figure out who will use the Status output, and only return what's strictly need
304/*
305// Status returns current status values from the Synchronizer
306func (s *Synchronizer) Status() (*common.SyncStatus, error) {
307 // Avoid possible inconsistencies
308 s.mux.Lock()
309 defer s.mux.Unlock()
310
311 var status *common.SyncStatus
312
313 // TODO: Join all queries to the DB into a single transaction so that
314 // we can remove the mutex locking here:
315 // - HistoryDB.GetLastBlock
316 // - HistoryDB.GetLastBatchNum
317 // - HistoryDB.GetCurrentForgerAddr
318 // - HistoryDB.GetNextForgerAddr
319
320 // Get latest block in History DB
321 lastSavedBlock, err := s.historyDB.GetLastBlock()
322 if err != nil {
323 return nil, err
324 }
325 status.CurrentBlock = lastSavedBlock.EthBlockNum
326
327 // Get latest batch in History DB
328 lastSavedBatch, err := s.historyDB.GetLastBatchNum()
329 if err != nil && err != sql.ErrNoRows {
330 return nil, err
331 }
332 status.CurrentBatch = lastSavedBatch
333
334 // Get latest blockNum in blockchain
335 latestBlockNum, err := s.ethClient.EthCurrentBlock()
336 if err != nil {
337 return nil, err
338 }
339
340 // TODO: Get CurrentForgerAddr & NextForgerAddr from the Auction SC / Or from the HistoryDB
341
342 // Check if Synchronizer is synchronized
343 status.Synchronized = status.CurrentBlock == latestBlockNum
344 return status, nil
345}
346*/
347
348// rollupSync retreives all the Rollup Smart Contract Data that happened at
349// ethBlock.blockNum with ethBlock.Hash.
350func (s *Synchronizer) rollupSync(ethBlock *common.Block) (*common.RollupData, error) {
351 blockNum := ethBlock.EthBlockNum
352 var rollupData = common.NewRollupData()
353 // var forgeL1TxsNum int64
354
355 // Get rollup events in the block, and make sure the block hash matches
356 // the expected one.
357 rollupEvents, blockHash, err := s.ethClient.RollupEventsByBlock(blockNum)
358 if err != nil {
359 return nil, err
360 }
361 // No events in this block
362 if blockHash == nil {
363 return &rollupData, nil
364 }
365 if *blockHash != ethBlock.Hash {
366 log.Errorw("Block hash mismatch in Rollup events", "expected", ethBlock.Hash.String(),
367 "got", blockHash.String())
368 return nil, eth.ErrBlockHashMismatchEvent
369 }
370
371 var nextForgeL1TxsNum int64 // forgeL1TxsNum for the next L1Batch
372 nextForgeL1TxsNumPtr, err := s.historyDB.GetLastL1TxsNum()
373 if err != nil {
374 return nil, err
375 }
376 if nextForgeL1TxsNumPtr != nil {
377 nextForgeL1TxsNum = *nextForgeL1TxsNumPtr + 1
378 } else {
379 nextForgeL1TxsNum = 0
380 }
381
382 // Get L1UserTX
383 rollupData.L1UserTxs, err = getL1UserTx(rollupEvents.L1UserTx, blockNum)
384 if err != nil {
385 return nil, err
386 }
387
388 // Get ForgeBatch events to get the L1CoordinatorTxs
389 for _, evtForgeBatch := range rollupEvents.ForgeBatch {
390 batchData := common.NewBatchData()
391 position := 0
392
393 // Get the input for each Tx
394 forgeBatchArgs, sender, err := s.ethClient.RollupForgeBatchArgs(evtForgeBatch.EthTxHash)
395 if err != nil {
396 return nil, err
397 }
398
399 batchNum := common.BatchNum(evtForgeBatch.BatchNum)
400 var l1UserTxs []common.L1Tx
401 // Check if this is a L1Batch to get L1 Tx from it
402 if forgeBatchArgs.L1Batch {
403 // Get L1UserTxs with toForgeL1TxsNum, which correspond
404 // to the L1UserTxs that are forged in this batch, so
405 // that stateDB can process them.
406
407 // First try to find them in HistoryDB.
408 l1UserTxs, err = s.historyDB.GetL1UserTxs(nextForgeL1TxsNum)
409 if err != nil {
410 return nil, err
411 }
412 // Apart from the DB, try to find them in this block.
413 // This could happen because in a block there could be
414 // multiple batches with L1Batch = true (although it's
415 // a very rare case). If not found in the DB and the
416 // block doesn't contain the l1UserTxs, it means that
417 // the L1UserTxs queue with toForgeL1TxsNum was closed
418 // empty, so we leave `l1UserTxs` as an empty slice.
419 for _, l1UserTx := range rollupData.L1UserTxs {
420 if *l1UserTx.ToForgeL1TxsNum == nextForgeL1TxsNum {
421 l1UserTxs = append(l1UserTxs, l1UserTx)
422 }
423 }
424
425 position = len(l1UserTxs)
426 }
427 // Get L1 Coordinator Txs
428 for i := range forgeBatchArgs.L1CoordinatorTxs {
429 l1CoordinatorTx := forgeBatchArgs.L1CoordinatorTxs[i]
430 l1CoordinatorTx.Position = position
431 // l1CoordinatorTx.ToForgeL1TxsNum = &forgeL1TxsNum
432 l1CoordinatorTx.UserOrigin = false
433 l1CoordinatorTx.EthBlockNum = blockNum
434 l1CoordinatorTx.BatchNum = &batchNum
435 l1Tx, err := common.NewL1Tx(&l1CoordinatorTx)
436 if err != nil {
437 return nil, err
438 }
439
440 batchData.L1CoordinatorTxs = append(batchData.L1CoordinatorTxs, *l1Tx)
441 position++
442 // fmt.Println("DGB l1coordtx")
443 }
444
445 // Insert all the txs forged in this batch (l1UserTxs,
446 // L1CoordinatorTxs, PoolL2Txs) into stateDB so that they are
447 // processed.
448 poolL2Txs := common.L2TxsToPoolL2Txs(forgeBatchArgs.L2TxsData) // NOTE: This is a big ugly, find a better way
449
450 // ProcessTxs updates poolL2Txs adding: Nonce (and also TokenID, but we don't use it).
451 processTxsOut, err := s.stateDB.ProcessTxs(forgeBatchArgs.FeeIdxCoordinator, l1UserTxs,
452 batchData.L1CoordinatorTxs, poolL2Txs)
453 if err != nil {
454 return nil, err
455 }
456
457 // Set batchNum in exits
458 for i := range processTxsOut.ExitInfos {
459 exit := &processTxsOut.ExitInfos[i]
460 exit.BatchNum = batchNum
461 }
462 batchData.ExitTree = processTxsOut.ExitInfos
463
464 l2Txs, err := common.PoolL2TxsToL2Txs(poolL2Txs) // NOTE: This is a big uggly, find a better way
465 if err != nil {
466 return nil, err
467 }
468
469 for i := range l2Txs {
470 tx := &l2Txs[i]
471 tx.Position = position
472 tx.EthBlockNum = blockNum
473 tx.BatchNum = batchNum
474 nTx, err := common.NewL2Tx(tx)
475 if err != nil {
476 return nil, err
477 }
478
479 batchData.L2Txs = append(batchData.L2Txs, *nTx)
480 position++
481 }
482
483 for i := range processTxsOut.CreatedAccounts {
484 createdAccount := &processTxsOut.CreatedAccounts[i]
485 createdAccount.Nonce = 0
486 createdAccount.Balance = big.NewInt(0)
487 createdAccount.BatchNum = batchNum
488 }
489 batchData.CreatedAccounts = processTxsOut.CreatedAccounts
490
491 slotNum := int64(0)
492 if ethBlock.EthBlockNum >= s.auctionConstants.GenesisBlockNum {
493 slotNum = (ethBlock.EthBlockNum - s.auctionConstants.GenesisBlockNum) /
494 int64(s.auctionConstants.BlocksPerSlot)
495 }
496
497 // Get Batch information
498 batch := common.Batch{
499 BatchNum: batchNum,
500 EthBlockNum: blockNum,
501 ForgerAddr: *sender,
502 CollectedFees: processTxsOut.CollectedFees,
503 FeeIdxsCoordinator: forgeBatchArgs.FeeIdxCoordinator,
504 StateRoot: forgeBatchArgs.NewStRoot,
505 NumAccounts: len(batchData.CreatedAccounts),
506 LastIdx: forgeBatchArgs.NewLastIdx,
507 ExitRoot: forgeBatchArgs.NewExitRoot,
508 SlotNum: slotNum,
509 }
510 nextForgeL1TxsNumCpy := nextForgeL1TxsNum
511 if forgeBatchArgs.L1Batch {
512 batch.ForgeL1TxsNum = &nextForgeL1TxsNumCpy
513 batchData.L1Batch = true
514 nextForgeL1TxsNum++
515 }
516 batchData.Batch = batch
517 rollupData.Batches = append(rollupData.Batches, *batchData)
518 }
519
520 // Get Registered Tokens
521 for _, evtAddToken := range rollupEvents.AddToken {
522 var token common.Token
523
524 token.TokenID = common.TokenID(evtAddToken.TokenID)
525 token.EthAddr = evtAddToken.TokenAddress
526 token.EthBlockNum = blockNum
527
528 if consts, err := s.ethClient.EthERC20Consts(evtAddToken.TokenAddress); err != nil {
529 log.Warnw("Error retreiving ERC20 token constants", "addr", evtAddToken.TokenAddress)
530 token.Name = "ERC20_ETH_ERROR"
531 token.Symbol = "ERROR"
532 token.Decimals = 1
533 } else {
534 token.Name = cutStringMax(consts.Name, 20)
535 token.Symbol = cutStringMax(consts.Symbol, 10)
536 token.Decimals = consts.Decimals
537 }
538
539 rollupData.AddedTokens = append(rollupData.AddedTokens, token)
540 }
541
542 varsUpdate := false
543
544 for _, evtUpdateForgeL1L2BatchTimeout := range rollupEvents.UpdateForgeL1L2BatchTimeout {
545 s.vars.Rollup.ForgeL1L2BatchTimeout = evtUpdateForgeL1L2BatchTimeout.NewForgeL1L2BatchTimeout
546 varsUpdate = true
547 }
548
549 for _, evtUpdateFeeAddToken := range rollupEvents.UpdateFeeAddToken {
550 s.vars.Rollup.FeeAddToken = evtUpdateFeeAddToken.NewFeeAddToken
551 varsUpdate = true
552 }
553
554 // NOTE: WithdrawDelay update doesn't have event, so we can't track changes
555
556 // NOTE: Buckets update dones't have event, so we can't track changes
557
558 for _, evtWithdraw := range rollupEvents.Withdraw {
559 rollupData.Withdrawals = append(rollupData.Withdrawals, common.WithdrawInfo{
560 Idx: common.Idx(evtWithdraw.Idx),
561 NumExitRoot: common.BatchNum(evtWithdraw.NumExitRoot),
562 InstantWithdraw: evtWithdraw.InstantWithdraw,
563 TxHash: evtWithdraw.TxHash,
564 })
565 }
566
567 if varsUpdate {
568 s.vars.Rollup.EthBlockNum = blockNum
569 rollupData.Vars = &s.vars.Rollup
570 }
571
572 return &rollupData, nil
573}
574
575func cutStringMax(s string, max int) string {
576 if len(s) > max {
577 return s[:max]
578 }
579 return s
580}
581
582// auctionSync gets information from the Auction Contract
583func (s *Synchronizer) auctionSync(ethBlock *common.Block) (*common.AuctionData, error) {
584 blockNum := ethBlock.EthBlockNum
585 var auctionData = common.NewAuctionData()
586
587 // Get auction events in the block
588 auctionEvents, blockHash, err := s.ethClient.AuctionEventsByBlock(blockNum)
589 if err != nil {
590 return nil, err
591 }
592 // No events in this block
593 if blockHash == nil {
594 return &auctionData, nil
595 }
596 if *blockHash != ethBlock.Hash {
597 log.Errorw("Block hash mismatch in Auction events", "expected", ethBlock.Hash.String(),
598 "got", blockHash.String())
599 return nil, eth.ErrBlockHashMismatchEvent
600 }
601
602 // Get bids
603 for _, evtNewBid := range auctionEvents.NewBid {
604 bid := common.Bid{
605 SlotNum: evtNewBid.Slot,
606 BidValue: evtNewBid.BidAmount,
607 Bidder: evtNewBid.Bidder,
608 EthBlockNum: blockNum,
609 }
610 auctionData.Bids = append(auctionData.Bids, bid)
611 }
612
613 // Get Coordinators
614 for _, evtSetCoordinator := range auctionEvents.SetCoordinator {
615 coordinator := common.Coordinator{
616 Bidder: evtSetCoordinator.BidderAddress,
617 Forger: evtSetCoordinator.ForgerAddress,
618 URL: evtSetCoordinator.CoordinatorURL,
619 }
620 auctionData.Coordinators = append(auctionData.Coordinators, coordinator)
621 }
622
623 varsUpdate := false
624
625 for _, evt := range auctionEvents.NewSlotDeadline {
626 s.vars.Auction.SlotDeadline = evt.NewSlotDeadline
627 varsUpdate = true
628 }
629 for _, evt := range auctionEvents.NewClosedAuctionSlots {
630 s.vars.Auction.ClosedAuctionSlots = evt.NewClosedAuctionSlots
631 varsUpdate = true
632 }
633 for _, evt := range auctionEvents.NewOutbidding {
634 s.vars.Auction.Outbidding = evt.NewOutbidding
635 varsUpdate = true
636 }
637 for _, evt := range auctionEvents.NewDonationAddress {
638 s.vars.Auction.DonationAddress = evt.NewDonationAddress
639 varsUpdate = true
640 }
641 for _, evt := range auctionEvents.NewBootCoordinator {
642 s.vars.Auction.BootCoordinator = evt.NewBootCoordinator
643 varsUpdate = true
644 }
645 for _, evt := range auctionEvents.NewOpenAuctionSlots {
646 s.vars.Auction.OpenAuctionSlots = evt.NewOpenAuctionSlots
647 varsUpdate = true
648 }
649 for _, evt := range auctionEvents.NewAllocationRatio {
650 s.vars.Auction.AllocationRatio = evt.NewAllocationRatio
651 varsUpdate = true
652 }
653 for _, evt := range auctionEvents.NewDefaultSlotSetBid {
654 if evt.SlotSet > 6 { //nolint:gomnd
655 return nil, fmt.Errorf("unexpected SlotSet in "+
656 "auctionEvents.NewDefaultSlotSetBid: %v", evt.SlotSet)
657 }
658 s.vars.Auction.DefaultSlotSetBid[evt.SlotSet] = evt.NewInitialMinBid
659 varsUpdate = true
660 }
661
662 // NOTE: We ignore NewForgeAllocated
663 // NOTE: We ignore NewForge because we're already tracking ForgeBatch event from Rollup
664 // NOTE: We ignore HEZClaimed
665
666 if varsUpdate {
667 s.vars.Auction.EthBlockNum = blockNum
668 auctionData.Vars = &s.vars.Auction
669 }
670
671 return &auctionData, nil
672}
673
674// wdelayerSync gets information from the Withdrawal Delayer Contract
675func (s *Synchronizer) wdelayerSync(ethBlock *common.Block) (*common.WDelayerData, error) {
676 blockNum := ethBlock.EthBlockNum
677 wDelayerData := common.NewWDelayerData()
678
679 // Get wDelayer events in the block
680 wDelayerEvents, blockHash, err := s.ethClient.WDelayerEventsByBlock(blockNum)
681 if err != nil {
682 return nil, err
683 }
684 // No events in this block
685 if blockHash == nil {
686 return &wDelayerData, nil
687 }
688 if *blockHash != ethBlock.Hash {
689 log.Errorw("Block hash mismatch in WDelayer events", "expected", ethBlock.Hash.String(),
690 "got", blockHash.String())
691 return nil, eth.ErrBlockHashMismatchEvent
692 }
693
694 for _, evt := range wDelayerEvents.Deposit {
695 wDelayerData.Deposits = append(wDelayerData.Deposits, common.WDelayerTransfer{
696 Owner: evt.Owner,
697 Token: evt.Token,
698 Amount: evt.Amount,
699 })
700 wDelayerData.DepositsByTxHash[evt.TxHash] =
701 &wDelayerData.Deposits[len(wDelayerData.Deposits)-1]
702 }
703 for _, evt := range wDelayerEvents.Withdraw {
704 wDelayerData.Withdrawals = append(wDelayerData.Withdrawals, common.WDelayerTransfer{
705 Owner: evt.Owner,
706 Token: evt.Token,
707 Amount: evt.Amount,
708 })
709 }
710
711 varsUpdate := false
712
713 // TODO EscapeHatchWithdrawal
714 for range wDelayerEvents.EmergencyModeEnabled {
715 s.vars.WDelayer.EmergencyMode = true
716 varsUpdate = true
717 }
718 for _, evt := range wDelayerEvents.NewWithdrawalDelay {
719 s.vars.WDelayer.WithdrawalDelay = evt.WithdrawalDelay
720 varsUpdate = true
721 }
722 for _, evt := range wDelayerEvents.NewHermezKeeperAddress {
723 s.vars.WDelayer.HermezKeeperAddress = evt.NewHermezKeeperAddress
724 varsUpdate = true
725 }
726 for _, evt := range wDelayerEvents.NewWhiteHackGroupAddress {
727 s.vars.WDelayer.WhiteHackGroupAddress = evt.NewWhiteHackGroupAddress
728 varsUpdate = true
729 }
730 for _, evt := range wDelayerEvents.NewHermezGovernanceDAOAddress {
731 s.vars.WDelayer.HermezGovernanceDAOAddress = evt.NewHermezGovernanceDAOAddress
732 varsUpdate = true
733 }
734
735 if varsUpdate {
736 s.vars.WDelayer.EthBlockNum = blockNum
737 wDelayerData.Vars = &s.vars.WDelayer
738 }
739
740 return &wDelayerData, nil
741}
742
743func getL1UserTx(eventsL1UserTx []eth.RollupEventL1UserTx, blockNum int64) ([]common.L1Tx, error) {
744 l1Txs := make([]common.L1Tx, len(eventsL1UserTx))
745 for i := range eventsL1UserTx {
746 eventsL1UserTx[i].L1UserTx.EthBlockNum = blockNum
747 // Check validity of L1UserTx
748 l1Tx, err := common.NewL1Tx(&eventsL1UserTx[i].L1UserTx)
749 if err != nil {
750 return nil, err
751 }
752 l1Txs[i] = *l1Tx
753 }
754 return l1Txs, nil
755}