Skip to content

Commit 9fd1286

Browse files
fix: add chain availability check (#5227)
1 parent dbf8c5e commit 9fd1286

File tree

6 files changed

+148
-112
lines changed

6 files changed

+148
-112
lines changed

cmd/bee/cmd/db.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131

3232
const (
3333
optionNameValidation = "validate"
34-
optionNameValidationPin = "validate-pin"
3534
optionNameCollectionPin = "pin"
3635
optionNameOutputLocation = "output"
3736
)

pkg/api/router.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/ethersphere/bee/v2/pkg/jsonhttp"
1515
"github.com/ethersphere/bee/v2/pkg/log/httpaccess"
1616
"github.com/ethersphere/bee/v2/pkg/swarm"
17+
"github.com/ethersphere/bee/v2/pkg/transaction/backendnoop"
1718
"github.com/felixge/fgprof"
1819
"github.com/gorilla/handlers"
1920
"github.com/gorilla/mux"
@@ -218,6 +219,17 @@ func (s *Service) checkStorageIncentivesAvailability(handler http.Handler) http.
218219
})
219220
}
220221

222+
func (s *Service) checkChainAvailability(handler http.Handler) http.Handler {
223+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
224+
if _, ok := s.chainBackend.(*backendnoop.Backend); ok {
225+
jsonhttp.Forbidden(w, "Chain is disabled. This endpoint is unavailable.")
226+
return
227+
}
228+
229+
handler.ServeHTTP(w, r)
230+
})
231+
}
232+
221233
func (s *Service) mountAPI() {
222234
subdomainRouter := s.router.Host("{subdomain:.*}.swarm.localhost").Subrouter()
223235

@@ -564,27 +576,31 @@ func (s *Service) mountBusinessDebug() {
564576
))
565577

566578
handle("/stamps", web.ChainHandlers(
579+
s.checkChainAvailability,
567580
s.postageSyncStatusCheckHandler,
568581
web.FinalHandler(jsonhttp.MethodHandler{
569582
"GET": http.HandlerFunc(s.postageGetStampsHandler),
570583
})),
571584
)
572585

573586
handle("/stamps/{batch_id}", web.ChainHandlers(
587+
s.checkChainAvailability,
574588
s.postageSyncStatusCheckHandler,
575589
web.FinalHandler(jsonhttp.MethodHandler{
576590
"GET": http.HandlerFunc(s.postageGetStampHandler),
577591
})),
578592
)
579593

580594
handle("/stamps/{batch_id}/buckets", web.ChainHandlers(
595+
s.checkChainAvailability,
581596
s.postageSyncStatusCheckHandler,
582597
web.FinalHandler(jsonhttp.MethodHandler{
583598
"GET": http.HandlerFunc(s.postageGetStampBucketsHandler),
584599
})),
585600
)
586601

587602
handle("/stamps/{amount}/{depth}", web.ChainHandlers(
603+
s.checkChainAvailability,
588604
s.postageAccessHandler,
589605
s.postageSyncStatusCheckHandler,
590606
s.gasConfigMiddleware("create batch"),
@@ -594,6 +610,7 @@ func (s *Service) mountBusinessDebug() {
594610
)
595611

596612
handle("/stamps/topup/{batch_id}/{amount}", web.ChainHandlers(
613+
s.checkChainAvailability,
597614
s.postageAccessHandler,
598615
s.postageSyncStatusCheckHandler,
599616
s.gasConfigMiddleware("topup batch"),
@@ -603,6 +620,7 @@ func (s *Service) mountBusinessDebug() {
603620
)
604621

605622
handle("/stamps/dilute/{batch_id}/{depth}", web.ChainHandlers(
623+
s.checkChainAvailability,
606624
s.postageAccessHandler,
607625
s.postageSyncStatusCheckHandler,
608626
s.gasConfigMiddleware("dilute batch"),

pkg/node/chain.go

Lines changed: 20 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ import (
1313
"strings"
1414
"time"
1515

16-
"github.com/ethereum/go-ethereum"
1716
"github.com/ethereum/go-ethereum/common"
18-
"github.com/ethereum/go-ethereum/core/types"
1917
"github.com/ethereum/go-ethereum/ethclient"
2018
"github.com/ethereum/go-ethereum/rpc"
2119
"github.com/ethersphere/bee/v2/pkg/config"
@@ -31,8 +29,8 @@ import (
3129
"github.com/ethersphere/bee/v2/pkg/settlement/swap/swapprotocol"
3230
"github.com/ethersphere/bee/v2/pkg/storage"
3331
"github.com/ethersphere/bee/v2/pkg/transaction"
32+
"github.com/ethersphere/bee/v2/pkg/transaction/backendnoop"
3433
"github.com/ethersphere/bee/v2/pkg/transaction/wrapped"
35-
"github.com/prometheus/client_golang/prometheus"
3634
)
3735

3836
const (
@@ -48,38 +46,42 @@ func InitChain(
4846
logger log.Logger,
4947
stateStore storage.StateStorer,
5048
endpoint string,
51-
oChainID int64,
49+
chainID int64,
5250
signer crypto.Signer,
5351
pollingInterval time.Duration,
5452
chainEnabled bool,
5553
minimumGasTipCap uint64,
5654
) (transaction.Backend, common.Address, int64, transaction.Monitor, transaction.Service, error) {
57-
var backend transaction.Backend = &noOpChainBackend{
58-
chainID: oChainID,
59-
}
55+
backend := backendnoop.New(chainID)
6056

6157
if chainEnabled {
62-
// connect to the real one
6358
rpcClient, err := rpc.DialContext(ctx, endpoint)
6459
if err != nil {
6560
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("dial blockchain client: %w", err)
6661
}
6762

6863
var versionString string
69-
err = rpcClient.CallContext(ctx, &versionString, "web3_clientVersion")
70-
if err != nil {
71-
logger.Info("could not connect to backend; in a swap-enabled network a working blockchain node (for xdai network in production, sepolia in testnet) is required; check your node or specify another node using --blockchain-rpc-endpoint.", "backend_endpoint", endpoint)
72-
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("blockchain client get version: %w", err)
64+
if err = rpcClient.CallContext(ctx, &versionString, "web3_clientVersion"); err != nil {
65+
logger.Info("could not connect to backend; "+
66+
"in a swap-enabled network a working blockchain node "+
67+
"(for xDAI network in production, SepoliaETH in testnet) is required; "+
68+
"check your node or specify another node using --blockchain-rpc-endpoint.",
69+
"blockchain-rpc-endpoint", endpoint)
70+
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("get client version: %w", err)
7371
}
7472

7573
logger.Info("connected to blockchain backend", "version", versionString)
7674

7775
backend = wrapped.NewBackend(ethclient.NewClient(rpcClient), minimumGasTipCap)
7876
}
7977

80-
chainID, err := backend.ChainID(ctx)
78+
backendChainID, err := backend.ChainID(ctx)
8179
if err != nil {
82-
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("get chain id: %w", err)
80+
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("getting chain id: %w", err)
81+
}
82+
83+
if chainID != -1 && chainID != backendChainID.Int64() {
84+
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("connected to wrong network: expected chain id %d, got %d", chainID, backendChainID.Int64())
8385
}
8486

8587
overlayEthAddress, err := signer.EthereumAddress()
@@ -89,18 +91,19 @@ func InitChain(
8991

9092
transactionMonitor := transaction.NewMonitor(logger, backend, overlayEthAddress, pollingInterval, cancellationDepth)
9193

92-
transactionService, err := transaction.NewService(logger, overlayEthAddress, backend, signer, stateStore, chainID, transactionMonitor)
94+
transactionService, err := transaction.NewService(logger, overlayEthAddress, backend, signer, stateStore, backendChainID, transactionMonitor)
9395
if err != nil {
94-
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("new transaction service: %w", err)
96+
return nil, common.Address{}, 0, nil, nil, fmt.Errorf("transaction service: %w", err)
9597
}
9698

97-
return backend, overlayEthAddress, chainID.Int64(), transactionMonitor, transactionService, nil
99+
return backend, overlayEthAddress, backendChainID.Int64(), transactionMonitor, transactionService, nil
98100
}
99101

100102
// InitChequebookFactory will initialize the chequebook factory with the given
101103
// chain backend.
102104
func InitChequebookFactory(logger log.Logger, backend transaction.Backend, chainID int64, transactionService transaction.Service, factoryAddress string) (chequebook.Factory, error) {
103105
var currentFactory common.Address
106+
104107
chainCfg, found := config.GetByChainID(chainID)
105108

106109
foundFactory := chainCfg.CurrentFactoryAddress
@@ -340,74 +343,3 @@ func (m *noOpChequebookService) LastCheque(common.Address) (*chequebook.SignedCh
340343
func (m *noOpChequebookService) LastCheques() (map[common.Address]*chequebook.SignedCheque, error) {
341344
return nil, postagecontract.ErrChainDisabled
342345
}
343-
344-
// noOpChainBackend is a noOp implementation for transaction.Backend interface.
345-
type noOpChainBackend struct {
346-
chainID int64
347-
}
348-
349-
func (m noOpChainBackend) Metrics() []prometheus.Collector {
350-
return nil
351-
}
352-
353-
func (m noOpChainBackend) CallContract(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error) {
354-
return nil, errors.New("disabled chain backend")
355-
}
356-
357-
func (m noOpChainBackend) HeaderByNumber(context.Context, *big.Int) (*types.Header, error) {
358-
h := new(types.Header)
359-
h.Time = uint64(time.Now().Unix())
360-
return h, nil
361-
}
362-
363-
func (m noOpChainBackend) PendingNonceAt(context.Context, common.Address) (uint64, error) {
364-
panic("chain no op: PendingNonceAt")
365-
}
366-
367-
func (m noOpChainBackend) SuggestedFeeAndTip(ctx context.Context, gasPrice *big.Int, boostPercent int) (*big.Int, *big.Int, error) {
368-
panic("chain no op: SuggestedFeeAndTip")
369-
}
370-
371-
func (m noOpChainBackend) SuggestGasTipCap(context.Context) (*big.Int, error) {
372-
panic("chain no op: SuggestGasTipCap")
373-
}
374-
375-
func (m noOpChainBackend) EstimateGasAtBlock(context.Context, ethereum.CallMsg, *big.Int) (uint64, error) {
376-
panic("chain no op: EstimateGasAtBlock")
377-
}
378-
379-
func (m noOpChainBackend) SendTransaction(context.Context, *types.Transaction) error {
380-
panic("chain no op: SendTransaction")
381-
}
382-
383-
func (m noOpChainBackend) TransactionReceipt(context.Context, common.Hash) (*types.Receipt, error) {
384-
r := new(types.Receipt)
385-
r.BlockNumber = big.NewInt(1)
386-
return r, nil
387-
}
388-
389-
func (m noOpChainBackend) TransactionByHash(context.Context, common.Hash) (tx *types.Transaction, isPending bool, err error) {
390-
panic("chain no op: TransactionByHash")
391-
}
392-
393-
func (m noOpChainBackend) BlockNumber(context.Context) (uint64, error) {
394-
return 4, nil
395-
}
396-
397-
func (m noOpChainBackend) BalanceAt(context.Context, common.Address, *big.Int) (*big.Int, error) {
398-
return nil, postagecontract.ErrChainDisabled
399-
}
400-
401-
func (m noOpChainBackend) NonceAt(context.Context, common.Address, *big.Int) (uint64, error) {
402-
panic("chain no op: NonceAt")
403-
}
404-
405-
func (m noOpChainBackend) FilterLogs(context.Context, ethereum.FilterQuery) ([]types.Log, error) {
406-
panic("chain no op: FilterLogs")
407-
}
408-
409-
func (m noOpChainBackend) ChainID(context.Context) (*big.Int, error) {
410-
return big.NewInt(m.chainID), nil
411-
}
412-
413-
func (m noOpChainBackend) Close() {}

pkg/node/node.go

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -363,16 +363,10 @@ func NewBee(
363363
}
364364

365365
var (
366-
chainBackend transaction.Backend
367-
overlayEthAddress common.Address
368-
chainID int64
369-
transactionService transaction.Service
370-
transactionMonitor transaction.Monitor
371-
chequebookFactory chequebook.Factory
372-
chequebookService chequebook.Service = new(noOpChequebookService)
373-
chequeStore chequebook.ChequeStore
374-
cashoutService chequebook.CashoutService
375-
erc20Service erc20.Service
366+
chequebookService chequebook.Service = new(noOpChequebookService)
367+
chequeStore chequebook.ChequeStore
368+
cashoutService chequebook.CashoutService
369+
erc20Service erc20.Service
376370
)
377371

378372
chainEnabled := isChainEnabled(o, o.BlockchainRpcEndpoint, logger)
@@ -394,7 +388,7 @@ func NewBee(
394388
}
395389
}
396390

397-
chainBackend, overlayEthAddress, chainID, transactionMonitor, transactionService, err = InitChain(
391+
chainBackend, overlayEthAddress, chainID, transactionMonitor, transactionService, err := InitChain(
398392
ctx,
399393
logger,
400394
stateStore,
@@ -408,14 +402,10 @@ func NewBee(
408402
if err != nil {
409403
return nil, fmt.Errorf("init chain: %w", err)
410404
}
411-
b.ethClientCloser = chainBackend.Close
412-
413-
logger.Info("using chain with network network", "chain_id", chainID, "network_id", networkID)
414405

415-
if o.ChainID != -1 && o.ChainID != chainID {
416-
return nil, fmt.Errorf("connected to wrong blockchain network; network chainID %d; configured chainID %d", chainID, o.ChainID)
417-
}
406+
logger.Info("using chain with network", "chain_id", chainID, "network_id", networkID)
418407

408+
b.ethClientCloser = chainBackend.Close
419409
b.transactionCloser = tracerCloser
420410
b.transactionMonitorCloser = transactionMonitor
421411

@@ -514,7 +504,7 @@ func NewBee(
514504
}
515505

516506
if o.SwapEnable {
517-
chequebookFactory, err = InitChequebookFactory(logger, chainBackend, chainID, transactionService, o.SwapFactoryAddress)
507+
chequebookFactory, err := InitChequebookFactory(logger, chainBackend, chainID, transactionService, o.SwapFactoryAddress)
518508
if err != nil {
519509
return nil, fmt.Errorf("init chequebook factory: %w", err)
520510
}
@@ -1460,12 +1450,16 @@ func isChainEnabled(o *Options, swapEndpoint string, logger log.Logger) bool {
14601450
chainDisabled := swapEndpoint == ""
14611451
lightMode := !o.FullNodeMode
14621452

1463-
if lightMode && chainDisabled { // ultra light mode is LightNode mode with chain disabled
1464-
logger.Info("starting with a disabled chain backend")
1453+
if lightMode && chainDisabled {
1454+
logger.Info("chain backend disabled - starting in ultra-light mode",
1455+
"full_node_mode", o.FullNodeMode,
1456+
"blockchain-rpc-endpoint", swapEndpoint)
14651457
return false
14661458
}
14671459

1468-
logger.Info("starting with an enabled chain backend")
1460+
logger.Info("chain backend enabled - blockchain functionality available",
1461+
"full_node_mode", o.FullNodeMode,
1462+
"blockchain-rpc-endpoint", swapEndpoint)
14691463
return true // all other modes operate require chain enabled
14701464
}
14711465

0 commit comments

Comments
 (0)