github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/rollup/sync_service/bridge_client.go (about) 1 package sync_service 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "math/big" 8 9 "github.com/scroll-tech/go-ethereum/accounts/abi/bind" 10 "github.com/scroll-tech/go-ethereum/common" 11 "github.com/scroll-tech/go-ethereum/core/types" 12 "github.com/scroll-tech/go-ethereum/log" 13 "github.com/scroll-tech/go-ethereum/rpc" 14 ) 15 16 // BridgeClient is a wrapper around EthClient that adds 17 // methods for conveniently collecting L1 messages. 18 type BridgeClient struct { 19 client EthClient 20 confirmations rpc.BlockNumber 21 l1MessageQueueAddress common.Address 22 filterer *L1MessageQueueFilterer 23 } 24 25 func newBridgeClient(ctx context.Context, l1Client EthClient, l1ChainId uint64, confirmations rpc.BlockNumber, l1MessageQueueAddress common.Address) (*BridgeClient, error) { 26 if l1MessageQueueAddress == (common.Address{}) { 27 return nil, errors.New("must pass non-zero l1MessageQueueAddress to BridgeClient") 28 } 29 30 // sanity check: compare chain IDs 31 got, err := l1Client.ChainID(ctx) 32 if err != nil { 33 return nil, fmt.Errorf("failed to query L1 chain ID, err = %w", err) 34 } 35 if got.Cmp(big.NewInt(0).SetUint64(l1ChainId)) != 0 { 36 return nil, fmt.Errorf("unexpected chain ID, expected = %v, got = %v", l1ChainId, got) 37 } 38 39 filterer, err := NewL1MessageQueueFilterer(l1MessageQueueAddress, l1Client) 40 if err != nil { 41 return nil, fmt.Errorf("failed to initialize L1MessageQueueFilterer, err = %w", err) 42 } 43 44 client := BridgeClient{ 45 client: l1Client, 46 confirmations: confirmations, 47 l1MessageQueueAddress: l1MessageQueueAddress, 48 filterer: filterer, 49 } 50 51 return &client, nil 52 } 53 54 // fetchMessagesInRange retrieves and parses all L1 messages between the 55 // provided from and to L1 block numbers (inclusive). 56 func (c *BridgeClient) fetchMessagesInRange(ctx context.Context, from, to uint64) ([]types.L1MessageTx, error) { 57 log.Trace("BridgeClient fetchMessagesInRange", "fromBlock", from, "toBlock", to) 58 59 opts := bind.FilterOpts{ 60 Start: from, 61 End: &to, 62 Context: ctx, 63 } 64 it, err := c.filterer.FilterQueueTransaction(&opts, nil, nil) 65 if err != nil { 66 return nil, err 67 } 68 69 var msgs []types.L1MessageTx 70 71 for it.Next() { 72 event := it.Event 73 log.Trace("Received new L1 QueueTransaction event", "event", event) 74 75 if !event.GasLimit.IsUint64() { 76 return nil, fmt.Errorf("invalid QueueTransaction event: QueueIndex = %v, GasLimit = %v", event.QueueIndex, event.GasLimit) 77 } 78 79 msgs = append(msgs, types.L1MessageTx{ 80 QueueIndex: event.QueueIndex, 81 Gas: event.GasLimit.Uint64(), 82 To: &event.Target, 83 Value: event.Value, 84 Data: event.Data, 85 Sender: event.Sender, 86 }) 87 } 88 89 return msgs, nil 90 } 91 92 func (c *BridgeClient) getLatestConfirmedBlockNumber(ctx context.Context) (uint64, error) { 93 // confirmation based on "safe" or "finalized" block tag 94 if c.confirmations == rpc.SafeBlockNumber || c.confirmations == rpc.FinalizedBlockNumber { 95 tag := big.NewInt(int64(c.confirmations)) 96 header, err := c.client.HeaderByNumber(ctx, tag) 97 if err != nil { 98 return 0, err 99 } 100 if !header.Number.IsInt64() { 101 return 0, fmt.Errorf("received unexpected block number in BridgeClient: %v", header.Number) 102 } 103 return header.Number.Uint64(), nil 104 } 105 106 // confirmation based on latest block number 107 if c.confirmations == rpc.LatestBlockNumber { 108 number, err := c.client.BlockNumber(ctx) 109 if err != nil { 110 return 0, err 111 } 112 return number, nil 113 } 114 115 // confirmation based on a certain number of blocks 116 if c.confirmations.Int64() >= 0 { 117 number, err := c.client.BlockNumber(ctx) 118 if err != nil { 119 return 0, err 120 } 121 confirmations := uint64(c.confirmations.Int64()) 122 if number >= confirmations { 123 return number - confirmations, nil 124 } 125 return 0, nil 126 } 127 128 return 0, fmt.Errorf("unknown confirmation type: %v", c.confirmations) 129 }