diff --git a/cmd/geth/main.go b/cmd/geth/main.go index efffc9480ace..6a31b7be11bc 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -178,6 +178,7 @@ var ( utils.ShadowforkPeersFlag, utils.TxGossipBroadcastDisabledFlag, utils.TxGossipReceivingDisabledFlag, + utils.TxGossipSequencerHTTPFlag, utils.DASyncEnabledFlag, utils.DABlockNativeAPIEndpointFlag, utils.DABlobScanAPIEndpointFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 60b7e5416b01..767baeb97cb5 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -250,6 +250,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.CircuitCapacityCheckWorkersFlag, utils.TxGossipBroadcastDisabledFlag, utils.TxGossipReceivingDisabledFlag, + utils.TxGossipSequencerHTTPFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index a2a1655502d7..452908b0b832 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -902,6 +902,10 @@ var ( Name: "txgossip.disablereceiving", Usage: "Disable gossip receiving transactions from other peers", } + TxGossipSequencerHTTPFlag = &cli.StringFlag{ + Name: "txgossip.sequencerhttp", + Usage: "Sequencer mempool HTTP endpoint", + } // DA syncing settings DASyncEnabledFlag = cli.BoolFlag{ @@ -1808,6 +1812,10 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { cfg.TxGossipReceivingDisabled = ctx.GlobalBool(TxGossipReceivingDisabledFlag.Name) log.Info("Transaction gossip receiving disabled", "disabled", cfg.TxGossipReceivingDisabled) } + // Only configure sequencer http flag if we're running in verifier mode i.e. --mine is disabled. + if ctx.IsSet(TxGossipSequencerHTTPFlag.Name) && !ctx.IsSet(MiningEnabledFlag.Name) { + cfg.TxGossipSequencerHTTP = ctx.String(TxGossipSequencerHTTPFlag.Name) + } // Cap the cache allowance and tune the garbage collector mem, err := gopsutil.VirtualMemory() diff --git a/eth/api_backend.go b/eth/api_backend.go index 5aee374c3c66..d38fda095252 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -25,6 +25,7 @@ import ( "github.com/scroll-tech/go-ethereum" "github.com/scroll-tech/go-ethereum/accounts" "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/common/hexutil" "github.com/scroll-tech/go-ethereum/consensus" "github.com/scroll-tech/go-ethereum/core" "github.com/scroll-tech/go-ethereum/core/bloombits" @@ -35,6 +36,7 @@ import ( "github.com/scroll-tech/go-ethereum/eth/gasprice" "github.com/scroll-tech/go-ethereum/ethdb" "github.com/scroll-tech/go-ethereum/event" + "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/miner" "github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/rpc" @@ -44,6 +46,7 @@ import ( type EthAPIBackend struct { extRPCEnabled bool allowUnprotectedTxs bool + disableTxPool bool eth *Ethereum gpo *gasprice.Oracle } @@ -262,6 +265,38 @@ func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscri } func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error { + if signedTx.Type() == types.BlobTxType { + return types.ErrTxTypeNotSupported + } + + // OP-Stack: forward to remote sequencer RPC + var seqRPCErr error + if b.eth.seqRPCService != nil { + signedTxData, err := signedTx.MarshalBinary() + if err != nil { + return err + } + if seqRPCErr = b.eth.seqRPCService.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(signedTxData)); seqRPCErr != nil { + log.Warn("failed to send tx to sequencer", "tx", signedTx.Hash()) + if b.disableTxPool { + return seqRPCErr + } + } + } + if b.disableTxPool { + return nil + } + + // Retain tx in local tx pool after forwarding, for local RPC usage. + err := b.sendTx(signedTx) + if err != nil && b.eth.seqRPCService != nil && seqRPCErr == nil { + log.Warn("successfully sent tx to sequencer, but failed to persist in local tx pool", "err", err, "tx", signedTx.Hash()) + return nil + } + return err +} + +func (b *EthAPIBackend) sendTx(signedTx *types.Transaction) error { // will `VerifyFee` & `validateTx` in txPool.AddLocal return b.eth.txPool.AddLocal(signedTx) } diff --git a/eth/backend.go b/eth/backend.go index 0050d3853b65..2c2fe807b59f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -109,6 +109,9 @@ type Ethereum struct { p2pServer *p2p.Server lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) + + // Scroll additions + seqRPCService *rpc.Client } // New creates a new Ethereum object (including the @@ -294,7 +297,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether // Some of the extraData is used with Clique consensus (before EuclidV2). After EuclidV2 we use SystemContract consensus where this is overridden when creating a block. eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) - eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} + eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, config.TxGossipReceivingDisabled, eth, nil} if eth.APIBackend.allowUnprotectedTxs { log.Info("Unprotected transactions allowed") } @@ -305,6 +308,16 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether gpoParams.DefaultBasePrice = new(big.Int).SetUint64(config.TxPool.PriceLimit) eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) + if config.TxGossipSequencerHTTP != "" { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + client, err := rpc.DialContext(ctx, config.TxGossipSequencerHTTP) + cancel() + if err != nil { + return nil, fmt.Errorf("cannot initialize rollup sequencer client: %w", err) + } + eth.seqRPCService = client + } + // Setup DNS discovery iterators. dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) @@ -677,6 +690,9 @@ func (s *Ethereum) Stop() error { } s.blockchain.Stop() s.engine.Close() + if s.seqRPCService != nil { + s.seqRPCService.Close() + } rawdb.PopUncleanShutdownMarker(s.chainDb) s.chainDb.Close() s.eventMux.Stop() diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 0f70eb2ed6c9..4009ca6000e7 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -233,6 +233,7 @@ type Config struct { TxGossipBroadcastDisabled bool TxGossipReceivingDisabled bool + TxGossipSequencerHTTP string } // CreateConsensusEngine creates a consensus engine for the given chain configuration. diff --git a/params/version.go b/params/version.go index 9a15803210bc..d6b46fa23177 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 63 // Patch version component of the current release + VersionPatch = 64 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string )