Skip to content

feat: forward txs to sequencer #1208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ var (
utils.ShadowforkPeersFlag,
utils.TxGossipBroadcastDisabledFlag,
utils.TxGossipReceivingDisabledFlag,
utils.TxGossipSequencerHTTPFlag,
utils.DASyncEnabledFlag,
utils.DABlockNativeAPIEndpointFlag,
utils.DABlobScanAPIEndpointFlag,
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.CircuitCapacityCheckWorkersFlag,
utils.TxGossipBroadcastDisabledFlag,
utils.TxGossipReceivingDisabledFlag,
utils.TxGossipSequencerHTTPFlag,
},
},
{
Expand Down
8 changes: 8 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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()
Expand Down
35 changes: 35 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -44,6 +46,7 @@ import (
type EthAPIBackend struct {
extRPCEnabled bool
allowUnprotectedTxs bool
disableTxPool bool
eth *Ethereum
gpo *gasprice.Oracle
}
Expand Down Expand Up @@ -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)
}
Expand Down
18 changes: 17 additions & 1 deletion eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand All @@ -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...)
Expand Down Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ type Config struct {

TxGossipBroadcastDisabled bool
TxGossipReceivingDisabled bool
TxGossipSequencerHTTP string
}

// CreateConsensusEngine creates a consensus engine for the given chain configuration.
Expand Down
2 changes: 1 addition & 1 deletion params/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand Down