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