mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-29 16:13:47 +00:00
* port changes from #1013 * port changes from #1068 * go.mod tidy * fix compile error * fix goimports * fix log * address review comments * upgrade golang.org/x/net to 0.23.0 * port changes from #1018 * fix tests and linter errors * address review comments * refactor rollup sync service / verifier to use CalldataBlobSource to retrieve data from L1 * add configuration and initialize blob clients * fix unit tests * remove unused code * address review comments * address more review comments * implement first version of new da-codec and to handle multiple batches submitted in one transaction * add CommitBatchDAV7 and handle multiple commit events submitted in a single transactions * fix bug due to previous batch being empty when processing the first batch within a set of batches * Allow using MPT * implement reading of QueueTransaction from L1MessageQueueV1 and V2 * implement access to V1 and V2 messages and replace usage so that V1 is used before EuclidV2 fork and V2 afterward * add tests * update to latest da-codec * add field to CommittedBatchMeta to store LastL1MessageQueueHash for CodecV7 batches * adjust rollup verifier to support CodecV7 batches * address review comments * consume all L1 messages before EuclidV2 fork * address review comments * address review comments * fix issues after merge * go mod tidy * fix unit tests * update da-codec * add test TestValidateBatchCodecV7 * go mod tidy * do not log error on shutdown * add flag to explicitly disable L1MessageQueueV2 * add TestEuclidV2HardForkMessageQueue to scroll worker * add sanity check for version to deserialization of committedBatchMetaV7 * add mechanism for nodes to retrieve V2 messages even if they upgrade after L1MessageQueueV2 is deployed * chore: auto version bump [bot] * address review comments * Update core/rawdb/accessors_l1_message.go Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com> * address review comments --------- Co-authored-by: Ömer Faruk Irmak <omerfirmak@gmail.com> Co-authored-by: Thegaram <Thegaram@users.noreply.github.com> Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com> Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
194 lines
6 KiB
Go
194 lines
6 KiB
Go
package sync_service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/scroll-tech/go-ethereum/accounts/abi/bind"
|
|
"github.com/scroll-tech/go-ethereum/common"
|
|
"github.com/scroll-tech/go-ethereum/core/types"
|
|
"github.com/scroll-tech/go-ethereum/log"
|
|
"github.com/scroll-tech/go-ethereum/rpc"
|
|
)
|
|
|
|
// BridgeClient is a wrapper around EthClient that adds
|
|
// methods for conveniently collecting L1 messages.
|
|
type BridgeClient struct {
|
|
client EthClient
|
|
confirmations rpc.BlockNumber
|
|
|
|
l1MessageQueueV1Address common.Address
|
|
filtererV1 *L1MessageQueueFilterer
|
|
|
|
enableMessageQueueV2 bool
|
|
l1MessageQueueV2Address common.Address
|
|
filtererV2 *L1MessageQueueFilterer
|
|
}
|
|
|
|
func newBridgeClient(ctx context.Context, l1Client EthClient, l1ChainId uint64, confirmations rpc.BlockNumber, l1MessageQueueV1Address common.Address, enableMessageQueueV2 bool, l1MessageQueueV2Address common.Address) (*BridgeClient, error) {
|
|
if l1MessageQueueV1Address == (common.Address{}) {
|
|
return nil, errors.New("must pass non-zero l1MessageQueueV1Address to BridgeClient")
|
|
}
|
|
if enableMessageQueueV2 && l1MessageQueueV2Address == (common.Address{}) {
|
|
return nil, errors.New("must pass non-zero l1MessageQueueV2Address to BridgeClient")
|
|
}
|
|
|
|
// sanity check: compare chain IDs
|
|
got, err := l1Client.ChainID(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to query L1 chain ID, err = %w", err)
|
|
}
|
|
if got.Cmp(big.NewInt(0).SetUint64(l1ChainId)) != 0 {
|
|
return nil, fmt.Errorf("unexpected chain ID, expected = %v, got = %v", l1ChainId, got)
|
|
}
|
|
|
|
filtererV1, err := NewL1MessageQueueFilterer(l1MessageQueueV1Address, l1Client)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize L1MessageQueueV1Filterer, err = %w", err)
|
|
}
|
|
|
|
var filtererV2 *L1MessageQueueFilterer
|
|
if enableMessageQueueV2 {
|
|
filtererV2, err = NewL1MessageQueueFilterer(l1MessageQueueV2Address, l1Client)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize L1MessageQueueV2Filterer, err = %w", err)
|
|
}
|
|
}
|
|
|
|
client := BridgeClient{
|
|
client: l1Client,
|
|
confirmations: confirmations,
|
|
|
|
l1MessageQueueV1Address: l1MessageQueueV1Address,
|
|
filtererV1: filtererV1,
|
|
|
|
enableMessageQueueV2: enableMessageQueueV2,
|
|
l1MessageQueueV2Address: l1MessageQueueV2Address,
|
|
filtererV2: filtererV2,
|
|
}
|
|
|
|
return &client, nil
|
|
}
|
|
|
|
// fetchMessagesInRange retrieves and parses all L1 messages between the
|
|
// provided from and to L1 block numbers (inclusive).
|
|
func (c *BridgeClient) fetchMessagesInRange(ctx context.Context, from, to uint64, queryL1MessagesV1 bool) ([]types.L1MessageTx, []types.L1MessageTx, error) {
|
|
log.Trace("BridgeClient fetchMessagesInRange", "fromBlock", from, "toBlock", to)
|
|
|
|
var msgsV1, msgsV2 []types.L1MessageTx
|
|
|
|
opts := bind.FilterOpts{
|
|
Start: from,
|
|
End: &to,
|
|
Context: ctx,
|
|
}
|
|
|
|
// Query L1MessageQueueV1 if enabled. We disable querying of L1MessageQueueV1 once L1MessageQueueV2 is enabled,
|
|
// and we have received the first QueueTransaction event from L1MessageQueueV2.
|
|
if queryL1MessagesV1 {
|
|
it, err := c.filtererV1.FilterQueueTransaction(&opts, nil, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
for it.Next() {
|
|
event := it.Event
|
|
log.Trace("Received new L1 QueueTransaction event from L1MessageQueueV1", "event", event)
|
|
|
|
if !event.GasLimit.IsUint64() {
|
|
return nil, nil, fmt.Errorf("invalid QueueTransaction event: QueueIndex = %v, GasLimit = %v", event.QueueIndex, event.GasLimit)
|
|
}
|
|
|
|
msgsV1 = append(msgsV1, types.L1MessageTx{
|
|
QueueIndex: event.QueueIndex,
|
|
Gas: event.GasLimit.Uint64(),
|
|
To: &event.Target,
|
|
Value: event.Value,
|
|
Data: event.Data,
|
|
Sender: event.Sender,
|
|
})
|
|
}
|
|
|
|
if err = it.Error(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
// We allow to explicitly enable/disable querying of L1MessageQueueV2. This is useful for running the node without
|
|
// MessageQueueV2 available on L1 or for testing purposes.
|
|
if !c.enableMessageQueueV2 {
|
|
return msgsV1, nil, nil
|
|
}
|
|
|
|
// We always query L1MessageQueueV2. Before EuclidV2 L1 upgrade tx this will return an empty list as we don't use
|
|
// L1MessageQueueV2 to enqueue L1 messages before EuclidV2.
|
|
it, err := c.filtererV2.FilterQueueTransaction(&opts, nil, nil)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
for it.Next() {
|
|
event := it.Event
|
|
log.Trace("Received new L1 QueueTransaction event from L1MessageQueueV2", "event", event)
|
|
|
|
if !event.GasLimit.IsUint64() {
|
|
return nil, nil, fmt.Errorf("invalid QueueTransaction event: QueueIndex = %v, GasLimit = %v", event.QueueIndex, event.GasLimit)
|
|
}
|
|
|
|
msgsV2 = append(msgsV2, types.L1MessageTx{
|
|
QueueIndex: event.QueueIndex,
|
|
Gas: event.GasLimit.Uint64(),
|
|
To: &event.Target,
|
|
Value: event.Value,
|
|
Data: event.Data,
|
|
Sender: event.Sender,
|
|
})
|
|
}
|
|
|
|
if err = it.Error(); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return msgsV1, msgsV2, nil
|
|
}
|
|
|
|
func (c *BridgeClient) getLatestConfirmedBlockNumber(ctx context.Context) (uint64, error) {
|
|
// confirmation based on "safe" or "finalized" block tag
|
|
if c.confirmations == rpc.SafeBlockNumber || c.confirmations == rpc.FinalizedBlockNumber {
|
|
tag := big.NewInt(int64(c.confirmations))
|
|
header, err := c.client.HeaderByNumber(ctx, tag)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if !header.Number.IsInt64() {
|
|
return 0, fmt.Errorf("received unexpected block number in BridgeClient: %v", header.Number)
|
|
}
|
|
return header.Number.Uint64(), nil
|
|
}
|
|
|
|
// confirmation based on latest block number
|
|
if c.confirmations == rpc.LatestBlockNumber {
|
|
number, err := c.client.BlockNumber(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return number, nil
|
|
}
|
|
|
|
// confirmation based on a certain number of blocks
|
|
if c.confirmations.Int64() >= 0 {
|
|
number, err := c.client.BlockNumber(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
confirmations := uint64(c.confirmations.Int64())
|
|
if number >= confirmations {
|
|
return number - confirmations, nil
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
return 0, fmt.Errorf("unknown confirmation type: %v", c.confirmations)
|
|
}
|