diff --git a/l2geth/cmd/geth/main.go b/l2geth/cmd/geth/main.go index e419c8d68f..d272464c58 100644 --- a/l2geth/cmd/geth/main.go +++ b/l2geth/cmd/geth/main.go @@ -162,6 +162,7 @@ var ( utils.RollupMaxCalldataSizeFlag, utils.RollupBackendFlag, utils.RollupEnforceFeesFlag, + utils.RollupReadOnlyFlag, utils.RollupFeeThresholdDownFlag, utils.RollupFeeThresholdUpFlag, utils.SequencerClientHttpFlag, diff --git a/l2geth/cmd/geth/usage.go b/l2geth/cmd/geth/usage.go index 5db6a2d19a..d1bd75551b 100644 --- a/l2geth/cmd/geth/usage.go +++ b/l2geth/cmd/geth/usage.go @@ -78,6 +78,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.RollupFeeThresholdDownFlag, utils.RollupFeeThresholdUpFlag, utils.SequencerClientHttpFlag, + utils.RollupReadOnlyFlag, }, }, { diff --git a/l2geth/cmd/utils/flags.go b/l2geth/cmd/utils/flags.go index 26d4ceebbc..2d4a115477 100644 --- a/l2geth/cmd/utils/flags.go +++ b/l2geth/cmd/utils/flags.go @@ -870,6 +870,11 @@ var ( Usage: "HTTP endpoint for the sequencer client", EnvVar: "SEQUENCER_CLIENT_HTTP", } + RollupReadOnlyFlag = cli.BoolFlag{ + Name: "rollup.readonly", + Usage: "Enable read only mode", + EnvVar: "ROLLUP_READONLY", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -1149,6 +1154,9 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) { if ctx.GlobalIsSet(SequencerClientHttpFlag.Name) { cfg.SequencerClientHttp = ctx.GlobalString(SequencerClientHttpFlag.Name) } + if ctx.GlobalIsSet(RollupReadOnlyFlag.Name) { + cfg.IsReadOnly = ctx.GlobalBool(RollupReadOnlyFlag.Name) + } } // setLes configures the les server and ultra light client settings from the command line flags. diff --git a/l2geth/eth/api_backend.go b/l2geth/eth/api_backend.go index 35de825c97..b5474aa27d 100644 --- a/l2geth/eth/api_backend.go +++ b/l2geth/eth/api_backend.go @@ -48,6 +48,7 @@ type EthAPIBackend struct { gpo *gasprice.Oracle rollupGpo *gasprice.RollupOracle verifier bool + readOnly bool gasLimit uint64 UsingOVM bool MaxCallDataSize int @@ -57,6 +58,10 @@ func (b *EthAPIBackend) IsVerifier() bool { return b.verifier } +func (b *EthAPIBackend) IsReadOnly() bool { + return b.readOnly +} + func (b *EthAPIBackend) IsSyncing() bool { return b.eth.syncService.IsSyncing() } diff --git a/l2geth/eth/backend.go b/l2geth/eth/backend.go index 0fa4241df4..56b679c4af 100644 --- a/l2geth/eth/backend.go +++ b/l2geth/eth/backend.go @@ -224,7 +224,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) log.Info("Backend Config", "max-calldata-size", config.Rollup.MaxCallDataSize, "gas-limit", config.Rollup.GasLimit, "is-verifier", config.Rollup.IsVerifier, "using-ovm", rcfg.UsingOVM) - eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, nil, config.Rollup.IsVerifier, config.Rollup.GasLimit, rcfg.UsingOVM, config.Rollup.MaxCallDataSize} + eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, nil, config.Rollup.IsVerifier, config.Rollup.IsReadOnly, config.Rollup.GasLimit, rcfg.UsingOVM, config.Rollup.MaxCallDataSize} gpoParams := config.GPO if gpoParams.Default == nil { gpoParams.Default = config.Miner.GasPrice diff --git a/l2geth/internal/ethapi/api.go b/l2geth/internal/ethapi/api.go index 2d7ad1ffb7..70f9d18e34 100644 --- a/l2geth/internal/ethapi/api.go +++ b/l2geth/internal/ethapi/api.go @@ -646,10 +646,10 @@ func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.H } // GetBlockByNumber returns the requested canonical block. -// * When blockNr is -1 the chain head is returned. -// * When blockNr is -2 the pending chain head is returned. -// * When fullTx is true all transactions in the block are returned, otherwise -// only the transaction hash is returned. +// - When blockNr is -1 the chain head is returned. +// - When blockNr is -2 the pending chain head is returned. +// - When fullTx is true all transactions in the block are returned, otherwise +// only the transaction hash is returned. func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { @@ -1765,6 +1765,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod } if s.b.IsVerifier() { + if s.b.IsReadOnly() { + return common.Hash{}, errors.New("Cannot send raw transaction in read-only mode") + } sequencerURL := s.b.SequencerClientHttp() if sequencerURL == "" { return common.Hash{}, errNoSequencerURL diff --git a/l2geth/internal/ethapi/backend.go b/l2geth/internal/ethapi/backend.go index ca2f40098d..51ed89a3ee 100644 --- a/l2geth/internal/ethapi/backend.go +++ b/l2geth/internal/ethapi/backend.go @@ -87,6 +87,7 @@ type Backend interface { // Optimism-specific API IsVerifier() bool + IsReadOnly() bool IsSyncing() bool GetEthContext() (uint64, uint64) GetRollupContext() (uint64, uint64, uint64) diff --git a/l2geth/les/api_backend.go b/l2geth/les/api_backend.go index 98e2360be3..96b1ae0cfc 100644 --- a/l2geth/les/api_backend.go +++ b/l2geth/les/api_backend.go @@ -49,6 +49,10 @@ func (b *LesApiBackend) IsVerifier() bool { return false } +func (b *LesApiBackend) IsReadOnly() bool { + return false +} + func (b *LesApiBackend) GasLimit() uint64 { panic("not implemented") } diff --git a/l2geth/rollup/config.go b/l2geth/rollup/config.go index c13e1394c7..056055bc0f 100644 --- a/l2geth/rollup/config.go +++ b/l2geth/rollup/config.go @@ -39,4 +39,6 @@ type Config struct { FeeThresholdUp *big.Float // HTTP endpoint of the sequencer SequencerClientHttp string + // Only server the data reading requests + IsReadOnly bool } diff --git a/l2geth/rollup/sync_service.go b/l2geth/rollup/sync_service.go index 6f831e0db3..e19b1afbbc 100644 --- a/l2geth/rollup/sync_service.go +++ b/l2geth/rollup/sync_service.go @@ -45,6 +45,7 @@ type SyncService struct { ctx context.Context cancel context.CancelFunc verifier bool + readOnly bool db ethdb.Database scope event.SubscriptionScope txFeed event.Feed @@ -127,6 +128,7 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co ctx: ctx, cancel: cancel, verifier: cfg.IsVerifier, + readOnly: cfg.IsReadOnly, enable: cfg.Eth1SyncServiceEnable, syncing: atomic.Value{}, bc: bc, @@ -157,7 +159,7 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co // a remote server that indexes the layer one contracts. Place this // code behind this if statement so that this can run without the // requirement of the remote server being up. - if service.enable { + if service.enable && !cfg.IsReadOnly { // Ensure that the rollup client can connect to a remote server // before starting. Retry until it can connect. tEnsure := time.NewTicker(10 * time.Second) @@ -238,6 +240,12 @@ func (s *SyncService) Start() error { log.Info("Running without syncing enabled") return nil } + + if s.readOnly { + log.Info("Running in read only mode") + return nil + } + log.Info("Initializing Sync Service") if err := s.updateGasPriceOracleCache(nil); err != nil { return err @@ -598,8 +606,8 @@ func (s *SyncService) GasPriceOracleOwnerAddress() *common.Address { return &s.gasPriceOracleOwnerAddress } -/// Update the execution context's timestamp and blocknumber -/// over time. This is only necessary for the sequencer. +// / Update the execution context's timestamp and blocknumber +// / over time. This is only necessary for the sequencer. func (s *SyncService) updateL1BlockNumber() error { context, err := s.client.GetLatestEthContext() if err != nil {