From c75fa3fe6ea3885f76bfd61e358fb69089cf643a Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:23:59 +0300 Subject: [PATCH 1/6] fix: update height if staked when height decreases (#4873) --- pkg/node/node.go | 34 ++++----- pkg/storageincentives/staking/contract.go | 4 + .../staking/contract_test.go | 73 +++++++++++++++++-- 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 1fad6195e26..37500cb2a37 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -1006,12 +1006,14 @@ func NewBee( if chainEnabled { - if changedOverlay { - stake, err := stakingContract.GetPotentialStake(ctx) - if err != nil { - return nil, err - } - if stake.Cmp(big.NewInt(0)) > 0 { + stake, err := stakingContract.GetPotentialStake(ctx) + if err != nil { + return nil, err + } + + if stake.Cmp(big.NewInt(0)) > 0 { + + if changedOverlay { logger.Debug("changing overlay address in staking contract") tx, err := stakingContract.ChangeStakeOverlay(ctx, common.BytesToHash(nonce)) if err != nil { @@ -1019,23 +1021,17 @@ func NewBee( } logger.Info("overlay address changed in staking contract", "transaction", tx) } - } - - // make sure that the staking contract has the up to date height - tx, updated, err := stakingContract.UpdateHeight(ctx) - if err != nil { - return nil, err - } - if updated { - logger.Info("updated new reserve capacity doubling height in the staking contract", "transaction", tx, "new_height", o.ReserveCapacityDoubling) - } - if o.ReserveCapacityDoubling > 0 { - stake, err := stakingContract.GetPotentialStake(ctx) + // make sure that the staking contract has the up to date height + tx, updated, err := stakingContract.UpdateHeight(ctx) if err != nil { return nil, err } - if stake.Cmp(big.NewInt(0)) > 0 { + if updated { + logger.Info("updated new reserve capacity doubling height in the staking contract", "transaction", tx, "new_height", o.ReserveCapacityDoubling) + } + + if o.ReserveCapacityDoubling > 0 { // Check if the staked amount is sufficient to cover the additional neighborhoods. // The staked amount must be at least 2^h * MinimumStake. if stake.Cmp(big.NewInt(0).Mul(big.NewInt(1< Date: Tue, 22 Oct 2024 15:49:01 -0400 Subject: [PATCH 2/6] fix: blocklist (#4871) --- pkg/p2p/libp2p/connections_test.go | 28 ++++++++++++++++++++++++++++ pkg/p2p/libp2p/libp2p.go | 1 + 2 files changed, 29 insertions(+) diff --git a/pkg/p2p/libp2p/connections_test.go b/pkg/p2p/libp2p/connections_test.go index 3cee5072b96..22d3c0ab58d 100644 --- a/pkg/p2p/libp2p/connections_test.go +++ b/pkg/p2p/libp2p/connections_test.go @@ -599,6 +599,34 @@ func TestBlocklisting(t *testing.T) { expectPeers(t, s2) } +func TestReverseBlocklist(t *testing.T) { + t.Parallel() + + s1, overlay1 := newService(t, 1, libp2pServiceOpts{libp2pOpts: libp2p.Options{ + FullNode: true, + }}) + s2, overlay2 := newService(t, 1, libp2pServiceOpts{libp2pOpts: libp2p.Options{ + FullNode: true, + }}) + + s1Addr := serviceUnderlayAddress(t, s1) + + _, err := s2.Connect(context.Background(), s1Addr) + if err != nil { + t.Fatal(err) + } + + expectPeers(t, s1, overlay2) + expectPeersEventually(t, s2, overlay1) + + if err := s1.Blocklist(overlay2, 0, testBlocklistMsg); err != nil { + t.Fatal(err) + } + + expectPeers(t, s1) + expectPeersEventually(t, s2) +} + func TestBlocklistedPeers(t *testing.T) { t.Parallel() s1, overlay1 := newService(t, 1, libp2pServiceOpts{libp2pOpts: libp2p.Options{ diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index c96a67e99cf..da620430fb6 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -542,6 +542,7 @@ func (s *Service) handleIncoming(stream network.Stream) { } peerUserAgent := appendSpace(s.peerUserAgent(s.ctx, peerID)) + s.networkStatus.Store(int32(p2p.NetworkStatusAvailable)) loggerV1.Debug("stream handler: successfully connected to peer (inbound)", "addresses", i.BzzAddress.ShortString(), "light", i.LightString(), "user_agent", peerUserAgent) s.logger.Debug("stream handler: successfully connected to peer (inbound)", "address", i.BzzAddress.Overlay, "light", i.LightString(), "user_agent", peerUserAgent) From c127b31f2ae1f29a8ed828f7e7fe30bb7f5d1003 Mon Sep 17 00:00:00 2001 From: Calin Martinconi Date: Wed, 23 Oct 2024 07:48:02 +0300 Subject: [PATCH 3/6] fix: rename ethereum in log (#4875) --- pkg/transaction/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/transaction/backend.go b/pkg/transaction/backend.go index be1f958b317..19e6ec7e8ec 100644 --- a/pkg/transaction/backend.go +++ b/pkg/transaction/backend.go @@ -75,7 +75,7 @@ func WaitSynced(ctx context.Context, logger log.Logger, backend Backend, maxDela return nil } - logger.Info("still waiting for Ethereum to sync", "block_time", blockTime) + logger.Info("still waiting for blockchain RPC to sync", "block_time", blockTime) select { case <-ctx.Done(): From 13fc473fbb04dd0dce3dc5ad7f900056c31bf993 Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Wed, 23 Oct 2024 19:29:16 +0300 Subject: [PATCH 4/6] fix: various swip21 fixes (#4874) --- pkg/node/node.go | 10 ++++------ pkg/storageincentives/agent.go | 3 ++- pkg/storer/reserve.go | 4 ++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 37500cb2a37..6db098c78b6 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -1031,12 +1031,10 @@ func NewBee( logger.Info("updated new reserve capacity doubling height in the staking contract", "transaction", tx, "new_height", o.ReserveCapacityDoubling) } - if o.ReserveCapacityDoubling > 0 { - // Check if the staked amount is sufficient to cover the additional neighborhoods. - // The staked amount must be at least 2^h * MinimumStake. - if stake.Cmp(big.NewInt(0).Mul(big.NewInt(1< 0 && stake.Cmp(big.NewInt(0).Mul(big.NewInt(1< Date: Tue, 29 Oct 2024 10:18:19 +0100 Subject: [PATCH 5/6] fix(api): add api initialization notice (#4869) --- pkg/api/api.go | 1 + pkg/api/api_test.go | 23 +- pkg/api/router.go | 309 ++++++++++++++------------- pkg/api/router_test.go | 448 +++++++++++++++++++++++++++++++++++++++ pkg/jsonhttp/handlers.go | 1 - pkg/node/devnode.go | 23 +- pkg/node/node.go | 6 +- 7 files changed, 633 insertions(+), 178 deletions(-) create mode 100644 pkg/api/router_test.go diff --git a/pkg/api/api.go b/pkg/api/api.go index 4568ad96bf5..ce90a1004f6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -179,6 +179,7 @@ type Service struct { ethereumAddress common.Address chequebookEnabled bool swapEnabled bool + fullAPIEnabled bool topologyDriver topology.Driver p2p p2p.DebugService diff --git a/pkg/api/api_test.go b/pkg/api/api_test.go index 7bd20c07e87..596327783e6 100644 --- a/pkg/api/api_test.go +++ b/pkg/api/api_test.go @@ -131,6 +131,9 @@ type testServerOptions struct { NodeStatus *status.Service PinIntegrity api.PinIntegrity WhitelistedAddr string + FullAPIDisabled bool + ChequebookDisabled bool + SwapDisabled bool } func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.Conn, string, *chanStorer) { @@ -179,7 +182,7 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket. erc20 := erc20mock.New(o.Erc20Opts...) backend := backendmock.New(o.BackendOpts...) - var extraOpts = api.ExtraOptions{ + extraOpts := api.ExtraOptions{ TopologyDriver: topologyDriver, Accounting: acc, Pseudosettle: recipient, @@ -207,7 +210,7 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket. o.BeeMode = api.FullMode } - s := api.New(o.PublicKey, o.PSSPublicKey, o.EthereumAddress, []string{o.WhitelistedAddr}, o.Logger, transaction, o.BatchStore, o.BeeMode, true, true, backend, o.CORSAllowedOrigins, inmemstore.New()) + s := api.New(o.PublicKey, o.PSSPublicKey, o.EthereumAddress, []string{o.WhitelistedAddr}, o.Logger, transaction, o.BatchStore, o.BeeMode, !o.ChequebookDisabled, !o.SwapDisabled, backend, o.CORSAllowedOrigins, inmemstore.New()) testutil.CleanupCloser(t, s) s.SetP2P(o.P2P) @@ -231,9 +234,10 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket. WsPingPeriod: o.WsPingPeriod, }, extraOpts, 1, erc20) - s.MountTechnicalDebug() - s.MountDebug() - s.MountAPI() + s.Mount() + if !o.FullAPIDisabled { + s.EnableFullAPI() + } if o.DirectUpload { chanStore = newChanStore(o.Storer.PusherFeed()) @@ -316,7 +320,7 @@ func TestParseName(t *testing.T) { const bzzHash = "89c17d0d8018a19057314aa035e61c9d23c47581a61dd3a79a7839692c617e4d" log := log.Noop - var errInvalidNameOrAddress = errors.New("invalid name or bzz address") + errInvalidNameOrAddress := errors.New("invalid name or bzz address") testCases := []struct { desc string @@ -377,7 +381,8 @@ func TestParseName(t *testing.T) { s := api.New(pk.PublicKey, pk.PublicKey, common.Address{}, nil, log, nil, nil, 1, false, false, nil, []string{"*"}, inmemstore.New()) s.Configure(signer, nil, api.Options{}, api.ExtraOptions{Resolver: tC.res}, 1, nil) - s.MountAPI() + s.Mount() + s.EnableFullAPI() tC := tC t.Run(tC.desc, func(t *testing.T) { @@ -503,9 +508,7 @@ func TestPostageHeaderError(t *testing.T) { func TestOptions(t *testing.T) { t.Parallel() - var ( - client, _, _, _ = newTestServer(t, testServerOptions{}) - ) + client, _, _, _ := newTestServer(t, testServerOptions{}) for _, tc := range []struct { endpoint string expectedMethods string // expectedMethods contains HTTP methods like GET, POST, HEAD, PATCH, DELETE, OPTIONS. These are in alphabetical sorted order diff --git a/pkg/api/router.go b/pkg/api/router.go index d7511c1c52e..14c9ab05ee6 100644 --- a/pkg/api/router.go +++ b/pkg/api/router.go @@ -25,41 +25,37 @@ const ( rootPath = "/" + apiVersion ) -func (s *Service) MountTechnicalDebug() { +func (s *Service) Mount() { + if s == nil { + return + } + router := mux.NewRouter() + router.NotFoundHandler = http.HandlerFunc(jsonhttp.NotFoundHandler) + s.router = router s.mountTechnicalDebug() - - s.Handler = web.ChainHandlers( - httpaccess.NewHTTPAccessLogHandler(s.logger, s.tracer, "api access"), - handlers.CompressHandler, - s.corsHandler, - web.NoCacheHeadersHandler, - web.FinalHandler(router), - ) -} - -func (s *Service) MountDebug() { s.mountBusinessDebug() + s.mountAPI() s.Handler = web.ChainHandlers( httpaccess.NewHTTPAccessLogHandler(s.logger, s.tracer, "api access"), handlers.CompressHandler, s.corsHandler, web.NoCacheHeadersHandler, - web.FinalHandler(s.router), + web.FinalHandler(router), ) } -func (s *Service) MountAPI() { - if s.router == nil { - s.router = mux.NewRouter() - s.router.NotFoundHandler = http.HandlerFunc(jsonhttp.NotFoundHandler) +// EnableFullAPI will enable all available endpoints, because some endpoints are not available during syncing. +func (s *Service) EnableFullAPI() { + if s == nil { + return } - s.mountAPI() + s.fullAPIEnabled = true compressHandler := func(h http.Handler) http.Handler { downloadEndpoints := []string{ @@ -140,11 +136,11 @@ func (s *Service) mountTechnicalDebug() { u.Path += "/" http.Redirect(w, r, u.String(), http.StatusPermanentRedirect) })) + s.router.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline)) s.router.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) s.router.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) s.router.Handle("/debug/pprof/trace", http.HandlerFunc(pprof.Trace)) - s.router.PathPrefix("/debug/pprof/").Handler(http.HandlerFunc(pprof.Index)) s.router.Handle("/debug/vars", expvar.Handler()) @@ -154,12 +150,14 @@ func (s *Service) mountTechnicalDebug() { web.FinalHandlerFunc(s.loggerGetHandler), ), }) + s.router.Handle("/loggers/{exp}", jsonhttp.MethodHandler{ "GET": web.ChainHandlers( httpaccess.NewHTTPAccessSuppressLogHandler(), web.FinalHandlerFunc(s.loggerGetHandler), ), }) + s.router.Handle("/loggers/{exp}/{verbosity}", jsonhttp.MethodHandler{ "PUT": web.ChainHandlers( httpaccess.NewHTTPAccessSuppressLogHandler(), @@ -178,6 +176,36 @@ func (s *Service) mountTechnicalDebug() { )) } +func (s *Service) checkRouteAvailability(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !s.fullAPIEnabled { + jsonhttp.ServiceUnavailable(w, "Node is syncing. This endpoint is unavailable. Try again later.") + return + } + handler.ServeHTTP(w, r) + }) +} + +func (s *Service) checkSwapAvailability(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !s.swapEnabled { + jsonhttp.NotImplemented(w, "Swap is disabled. This endpoint is unavailable.") + return + } + handler.ServeHTTP(w, r) + }) +} + +func (s *Service) checkChequebookAvailability(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !s.chequebookEnabled { + jsonhttp.NotImplemented(w, "Chequebook is disabled. This endpoint is unavailable.") + return + } + handler.ServeHTTP(w, r) + }) +} + func (s *Service) mountAPI() { subdomainRouter := s.router.Host("{subdomain:.*}.swarm.localhost").Subrouter() @@ -197,8 +225,9 @@ func (s *Service) mountAPI() { // handle is a helper closure which simplifies the router setup. handle := func(path string, handler http.Handler) { - s.router.Handle(path, handler) - s.router.Handle(rootPath+path, handler) + routeHandler := s.checkRouteAvailability(handler) + s.router.Handle(path, routeHandler) + s.router.Handle(rootPath+path, routeHandler) } handle("/bytes", jsonhttp.MethodHandler{ @@ -275,18 +304,12 @@ func (s *Service) mountAPI() { }) handle("/grantee", jsonhttp.MethodHandler{ - "POST": web.ChainHandlers( - web.FinalHandlerFunc(s.actCreateGranteesHandler), - ), + "POST": http.HandlerFunc(s.actCreateGranteesHandler), }) handle("/grantee/{address}", jsonhttp.MethodHandler{ - "GET": web.ChainHandlers( - web.FinalHandlerFunc(s.actListGranteesHandler), - ), - "PATCH": web.ChainHandlers( - web.FinalHandlerFunc(s.actGrantRevokeHandler), - ), + "GET": http.HandlerFunc(s.actListGranteesHandler), + "PATCH": http.HandlerFunc(s.actGrantRevokeHandler), }) handle("/bzz/{address}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -308,90 +331,65 @@ func (s *Service) mountAPI() { ), }) - handle("/pss/send/{topic}/{targets}", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "POST": web.ChainHandlers( - jsonhttp.NewMaxBodyBytesHandler(swarm.ChunkSize), - web.FinalHandlerFunc(s.pssPostHandler), - ), - })), - ) + handle("/pss/send/{topic}/{targets}", jsonhttp.MethodHandler{ + "POST": web.ChainHandlers( + jsonhttp.NewMaxBodyBytesHandler(swarm.ChunkSize), + web.FinalHandlerFunc(s.pssPostHandler), + ), + }) - handle("/pss/subscribe/{topic}", web.ChainHandlers( - web.FinalHandlerFunc(s.pssWsHandler), - )) + handle("/pss/subscribe/{topic}", http.HandlerFunc(s.pssWsHandler)) - handle("/tags", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.listTagsHandler), - "POST": web.ChainHandlers( - jsonhttp.NewMaxBodyBytesHandler(1024), - web.FinalHandlerFunc(s.createTagHandler), - ), - })), - ) + handle("/tags", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.listTagsHandler), + "POST": web.ChainHandlers( + jsonhttp.NewMaxBodyBytesHandler(1024), + web.FinalHandlerFunc(s.createTagHandler), + ), + }) - handle("/tags/{id}", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.getTagHandler), - "DELETE": http.HandlerFunc(s.deleteTagHandler), - "PATCH": web.ChainHandlers( - jsonhttp.NewMaxBodyBytesHandler(1024), - web.FinalHandlerFunc(s.doneSplitHandler), - ), - })), - ) + handle("/tags/{id}", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.getTagHandler), + "DELETE": http.HandlerFunc(s.deleteTagHandler), + "PATCH": web.ChainHandlers( + jsonhttp.NewMaxBodyBytesHandler(1024), + web.FinalHandlerFunc(s.doneSplitHandler), + ), + }) - handle("/pins", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.listPinnedRootHashes), - })), - ) + handle("/pins", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.listPinnedRootHashes), + }) - handle("/pins/check", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.pinIntegrityHandler), - }), - )) + handle("/pins/check", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.pinIntegrityHandler), + }) - handle("/pins/{reference}", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.getPinnedRootHash), - "POST": http.HandlerFunc(s.pinRootHash), - "DELETE": http.HandlerFunc(s.unpinRootHash), - })), + handle("/pins/{reference}", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.getPinnedRootHash), + "POST": http.HandlerFunc(s.pinRootHash), + "DELETE": http.HandlerFunc(s.unpinRootHash), + }, ) handle("/stewardship/{address}", jsonhttp.MethodHandler{ - "GET": web.ChainHandlers( - web.FinalHandlerFunc(s.stewardshipGetHandler), - ), - "PUT": web.ChainHandlers( - web.FinalHandlerFunc(s.stewardshipPutHandler), - ), + "GET": http.HandlerFunc(s.stewardshipGetHandler), + "PUT": http.HandlerFunc(s.stewardshipPutHandler), }) - - handle("/readiness", web.ChainHandlers( - httpaccess.NewHTTPAccessSuppressLogHandler(), - web.FinalHandlerFunc(s.readinessHandler), - )) - - handle("/health", web.ChainHandlers( - httpaccess.NewHTTPAccessSuppressLogHandler(), - web.FinalHandlerFunc(s.healthHandler), - )) } func (s *Service) mountBusinessDebug() { handle := func(path string, handler http.Handler) { - s.router.Handle(path, handler) - s.router.Handle(rootPath+path, handler) + routeHandler := s.checkRouteAvailability(handler) + s.router.Handle(path, routeHandler) + s.router.Handle(rootPath+path, routeHandler) } if s.transaction != nil { handle("/transactions", jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.transactionListHandler), }) + handle("/transactions/{hash}", jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.transactionDetailHandler), "POST": http.HandlerFunc(s.transactionResendHandler), @@ -423,10 +421,6 @@ func (s *Service) mountBusinessDebug() { "DELETE": http.HandlerFunc(s.peerDisconnectHandler), }) - //handle("/chunks/{address}", jsonhttp.MethodHandler{ - // "GET": http.HandlerFunc(s.hasChunkHandler), - //}) - handle("/topology", jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.topologyHandler), }) @@ -459,67 +453,96 @@ func (s *Service) mountBusinessDebug() { "GET": http.HandlerFunc(s.settlementsHandlerPseudosettle), }) - if s.swapEnabled { - handle("/settlements", jsonhttp.MethodHandler{ + handle("/settlements", web.ChainHandlers( + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.settlementsHandler), - }) + }), + )) - handle("/settlements/{peer}", jsonhttp.MethodHandler{ + handle("/settlements/{peer}", web.ChainHandlers( + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.peerSettlementsHandler), - }) + }), + )) - handle("/chequebook/cheque/{peer}", jsonhttp.MethodHandler{ + handle("/chequebook/cheque/{peer}", web.ChainHandlers( + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.chequebookLastPeerHandler), - }) + }), + )) - handle("/chequebook/cheque", jsonhttp.MethodHandler{ + handle("/chequebook/cheque", web.ChainHandlers( + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.chequebookAllLastHandler), - }) + }), + )) - handle("/chequebook/cashout/{peer}", jsonhttp.MethodHandler{ + handle("/chequebook/cashout/{peer}", web.ChainHandlers( + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.swapCashoutStatusHandler), "POST": web.ChainHandlers( s.gasConfigMiddleware("swap cashout"), web.FinalHandlerFunc(s.swapCashoutHandler), ), - }) - } + }), + )) - if s.chequebookEnabled { - handle("/chequebook/balance", jsonhttp.MethodHandler{ + handle("/chequebook/balance", web.ChainHandlers( + s.checkChequebookAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.chequebookBalanceHandler), - }) + }), + )) - handle("/chequebook/address", jsonhttp.MethodHandler{ + handle("/chequebook/address", web.ChainHandlers( + s.checkChequebookAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.chequebookAddressHandler), - }) + }), + )) - handle("/chequebook/deposit", jsonhttp.MethodHandler{ + handle("/chequebook/deposit", web.ChainHandlers( + s.checkChequebookAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "POST": web.ChainHandlers( s.gasConfigMiddleware("chequebook deposit"), web.FinalHandlerFunc(s.chequebookDepositHandler), ), - }) + }), + )) - handle("/chequebook/withdraw", jsonhttp.MethodHandler{ + handle("/chequebook/withdraw", web.ChainHandlers( + s.checkChequebookAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "POST": web.ChainHandlers( s.gasConfigMiddleware("chequebook withdraw"), web.FinalHandlerFunc(s.chequebookWithdrawHandler), ), - }) + }), + )) - handle("/wallet", jsonhttp.MethodHandler{ + handle("/wallet", web.ChainHandlers( + s.checkChequebookAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.walletHandler), - }) - if s.swapEnabled { - handle("/wallet/withdraw/{coin}", jsonhttp.MethodHandler{ - "POST": web.ChainHandlers( - s.gasConfigMiddleware("wallet withdraw"), - web.FinalHandlerFunc(s.walletWithdrawHandler), - ), - }) - } - } + }), + )) + + handle("/wallet/withdraw/{coin}", web.ChainHandlers( + s.checkChequebookAvailability, + s.checkSwapAvailability, + web.FinalHandler(jsonhttp.MethodHandler{ + "POST": web.ChainHandlers( + s.gasConfigMiddleware("wallet withdraw"), + web.FinalHandlerFunc(s.walletWithdrawHandler), + ), + }), + )) handle("/stamps", web.ChainHandlers( s.postageSyncStatusCheckHandler, @@ -569,26 +592,14 @@ func (s *Service) mountBusinessDebug() { })), ) - handle("/batches", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.postageGetAllBatchesHandler), - })), - ) + handle("/batches", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.postageGetAllBatchesHandler), + }) handle("/accounting", jsonhttp.MethodHandler{ "GET": http.HandlerFunc(s.accountingInfoHandler), }) - handle("/readiness", web.ChainHandlers( - httpaccess.NewHTTPAccessSuppressLogHandler(), - web.FinalHandlerFunc(s.readinessHandler), - )) - - handle("/health", web.ChainHandlers( - httpaccess.NewHTTPAccessSuppressLogHandler(), - web.FinalHandlerFunc(s.healthHandler), - )) - handle("/stake/withdrawable", web.ChainHandlers( s.stakingAccessHandler, s.gasConfigMiddleware("get or withdraw withdrawable stake"), @@ -642,9 +653,7 @@ func (s *Service) mountBusinessDebug() { ), }) - handle("/rchash/{depth}/{anchor1}/{anchor2}", web.ChainHandlers( - web.FinalHandler(jsonhttp.MethodHandler{ - "GET": http.HandlerFunc(s.rchash), - }), - )) + handle("/rchash/{depth}/{anchor1}/{anchor2}", jsonhttp.MethodHandler{ + "GET": http.HandlerFunc(s.rchash), + }) } diff --git a/pkg/api/router_test.go b/pkg/api/router_test.go new file mode 100644 index 00000000000..6f3e89d5eeb --- /dev/null +++ b/pkg/api/router_test.go @@ -0,0 +1,448 @@ +// Copyright 2024 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package api_test + +import ( + "net/http" + "strings" + "testing" + + "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" +) + +func TestEndpointOptions(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + serverOptions testServerOptions + expectedStatuses []struct { + route string + expectedMethods []string + expectedStatus int + } + }{ + { + name: "full_api_enabled", + serverOptions: testServerOptions{ + FullAPIDisabled: false, + SwapDisabled: false, + ChequebookDisabled: false, + }, + expectedStatuses: []struct { + route string + expectedMethods []string + expectedStatus int + }{ + // routes from mountTechnicalDebug + {"/node", []string{"GET"}, http.StatusNoContent}, + {"/addresses", []string{"GET"}, http.StatusNoContent}, + {"/chainstate", []string{"GET"}, http.StatusNoContent}, + {"/debugstore", []string{"GET"}, http.StatusNoContent}, + {"/loggers", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp/1", []string{"PUT"}, http.StatusNoContent}, + {"/readiness", nil, http.StatusBadRequest}, + {"/health", nil, http.StatusOK}, + {"/metrics", nil, http.StatusOK}, + {"/not_found", nil, http.StatusNotFound}, + + // routes from mountAPI + {"/", nil, http.StatusOK}, + {"/robots.txt", nil, http.StatusOK}, + {"/bytes", []string{"POST"}, http.StatusNoContent}, + {"/bytes/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/chunks", []string{"POST"}, http.StatusNoContent}, + {"/chunks/stream", nil, http.StatusBadRequest}, + {"/chunks/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/envelope/{address}", []string{"POST"}, http.StatusNoContent}, + {"/soc/{owner}/{id}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/feeds/{owner}/{topic}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/bzz", []string{"POST"}, http.StatusNoContent}, + {"/grantee", []string{"POST"}, http.StatusNoContent}, + {"/grantee/{address}", []string{"GET", "PATCH"}, http.StatusNoContent}, + {"/bzz/{address}", []string{"GET"}, http.StatusNoContent}, + {"/bzz/{address}/{path:.*}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/pss/send/{topic}/{targets}", []string{"POST"}, http.StatusNoContent}, + {"/pss/subscribe/{topic}", nil, http.StatusBadRequest}, + {"/tags", []string{"GET", "POST"}, http.StatusNoContent}, + {"/tags/{id}", []string{"GET", "DELETE", "PATCH"}, http.StatusNoContent}, + {"/pins", []string{"GET"}, http.StatusNoContent}, + {"/pins/check", []string{"GET"}, http.StatusNoContent}, + {"/pins/{reference}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/stewardship/{address}", []string{"GET", "PUT"}, http.StatusNoContent}, + + // routes from mountBusinessDebug + {"/transactions", []string{"GET"}, http.StatusNoContent}, + {"/transactions/{hash}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/peers", []string{"GET"}, http.StatusNoContent}, + {"/pingpong/{address}", []string{"POST"}, http.StatusNoContent}, + {"/reservestate", []string{"GET"}, http.StatusNoContent}, + {"/connect/{multi-address:.+}", []string{"POST"}, http.StatusNoContent}, + {"/blocklist", []string{"GET"}, http.StatusNoContent}, + {"/peers/{address}", []string{"DELETE"}, http.StatusNoContent}, + {"/topology", []string{"GET"}, http.StatusNoContent}, + {"/welcome-message", []string{"GET", "POST"}, http.StatusNoContent}, + {"/balances", []string{"GET"}, http.StatusNoContent}, + {"/balances/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/consumed", []string{"GET"}, http.StatusNoContent}, + {"/consumed/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/timesettlements", []string{"GET"}, http.StatusNoContent}, + {"/settlements", []string{"GET"}, http.StatusNoContent}, + {"/settlements/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cheque/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cheque", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cashout/{peer}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/chequebook/balance", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/address", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/deposit", []string{"POST"}, http.StatusNoContent}, + {"/chequebook/withdraw", []string{"POST"}, http.StatusNoContent}, + {"/wallet", []string{"GET"}, http.StatusNoContent}, + {"/wallet/withdraw/{coin}", []string{"POST"}, http.StatusNoContent}, + {"/stamps", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}/buckets", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{amount}/{depth}", []string{"POST"}, http.StatusNoContent}, + {"/stamps/topup/{batch_id}/{amount}", []string{"PATCH"}, http.StatusNoContent}, + {"/stamps/dilute/{batch_id}/{depth}", []string{"PATCH"}, http.StatusNoContent}, + {"/batches", []string{"GET"}, http.StatusNoContent}, + {"/accounting", []string{"GET"}, http.StatusNoContent}, + {"/stake/withdrawable", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/stake/{amount}", []string{"POST"}, http.StatusNoContent}, + {"/stake", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/redistributionstate", []string{"GET"}, http.StatusNoContent}, + {"/status", []string{"GET"}, http.StatusNoContent}, + {"/status/peers", []string{"GET"}, http.StatusNoContent}, + {"/status/neighborhoods", []string{"GET"}, http.StatusNoContent}, + {"/rchash/{depth}/{anchor1}/{anchor2}", []string{"GET"}, http.StatusNoContent}, + }, + }, + { + name: "full_api_disabled", + serverOptions: testServerOptions{ + FullAPIDisabled: true, + SwapDisabled: false, + ChequebookDisabled: false, + }, + expectedStatuses: []struct { + route string + expectedMethods []string + expectedStatus int + }{ + // routes from mountTechnicalDebug + {"/node", []string{"GET"}, http.StatusNoContent}, + {"/addresses", []string{"GET"}, http.StatusNoContent}, + {"/chainstate", []string{"GET"}, http.StatusNoContent}, + {"/debugstore", []string{"GET"}, http.StatusNoContent}, + {"/loggers", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp/1", []string{"PUT"}, http.StatusNoContent}, + {"/readiness", nil, http.StatusBadRequest}, + {"/health", nil, http.StatusOK}, + {"/metrics", nil, http.StatusOK}, + {"/not_found", nil, http.StatusNotFound}, + + // routes from mountAPI + {"/", nil, http.StatusOK}, + {"/robots.txt", nil, http.StatusOK}, + {"/bytes", nil, http.StatusServiceUnavailable}, + {"/bytes/{address}", nil, http.StatusServiceUnavailable}, + {"/chunks", nil, http.StatusServiceUnavailable}, + {"/chunks/stream", nil, http.StatusServiceUnavailable}, + {"/chunks/{address}", nil, http.StatusServiceUnavailable}, + {"/envelope/{address}", nil, http.StatusServiceUnavailable}, + {"/soc/{owner}/{id}", nil, http.StatusServiceUnavailable}, + {"/feeds/{owner}/{topic}", nil, http.StatusServiceUnavailable}, + {"/bzz", nil, http.StatusServiceUnavailable}, + {"/grantee", nil, http.StatusServiceUnavailable}, + {"/grantee/{address}", nil, http.StatusServiceUnavailable}, + {"/bzz/{address}", nil, http.StatusServiceUnavailable}, + {"/bzz/{address}/{path:.*}", nil, http.StatusServiceUnavailable}, + {"/pss/send/{topic}/{targets}", nil, http.StatusServiceUnavailable}, + {"/pss/subscribe/{topic}", nil, http.StatusServiceUnavailable}, + {"/tags", nil, http.StatusServiceUnavailable}, + {"/tags/{id}", nil, http.StatusServiceUnavailable}, + {"/pins", nil, http.StatusServiceUnavailable}, + {"/pins/check", nil, http.StatusServiceUnavailable}, + {"/pins/{reference}", nil, http.StatusServiceUnavailable}, + {"/stewardship/{address}", nil, http.StatusServiceUnavailable}, + + // routes from mountBusinessDebug + {"/transactions", nil, http.StatusServiceUnavailable}, + {"/transactions/{hash}", nil, http.StatusServiceUnavailable}, + {"/peers", nil, http.StatusServiceUnavailable}, + {"/pingpong/{address}", nil, http.StatusServiceUnavailable}, + {"/reservestate", nil, http.StatusServiceUnavailable}, + {"/connect/{multi-address:.+}", nil, http.StatusServiceUnavailable}, + {"/blocklist", nil, http.StatusServiceUnavailable}, + {"/peers/{address}", nil, http.StatusServiceUnavailable}, + {"/topology", nil, http.StatusServiceUnavailable}, + {"/welcome-message", nil, http.StatusServiceUnavailable}, + {"/balances", nil, http.StatusServiceUnavailable}, + {"/balances/{peer}", nil, http.StatusServiceUnavailable}, + {"/consumed", nil, http.StatusServiceUnavailable}, + {"/consumed/{peer}", nil, http.StatusServiceUnavailable}, + {"/timesettlements", nil, http.StatusServiceUnavailable}, + {"/settlements", nil, http.StatusServiceUnavailable}, + {"/settlements/{peer}", nil, http.StatusServiceUnavailable}, + {"/chequebook/cheque/{peer}", nil, http.StatusServiceUnavailable}, + {"/chequebook/cheque", nil, http.StatusServiceUnavailable}, + {"/chequebook/cashout/{peer}", nil, http.StatusServiceUnavailable}, + {"/chequebook/balance", nil, http.StatusServiceUnavailable}, + {"/chequebook/address", nil, http.StatusServiceUnavailable}, + {"/chequebook/deposit", nil, http.StatusServiceUnavailable}, + {"/chequebook/withdraw", nil, http.StatusServiceUnavailable}, + {"/wallet", nil, http.StatusServiceUnavailable}, + {"/wallet/withdraw/{coin}", nil, http.StatusServiceUnavailable}, + {"/stamps", nil, http.StatusServiceUnavailable}, + {"/stamps/{batch_id}", nil, http.StatusServiceUnavailable}, + {"/stamps/{batch_id}/buckets", nil, http.StatusServiceUnavailable}, + {"/stamps/{amount}/{depth}", nil, http.StatusServiceUnavailable}, + {"/stamps/topup/{batch_id}/{amount}", nil, http.StatusServiceUnavailable}, + {"/stamps/dilute/{batch_id}/{depth}", nil, http.StatusServiceUnavailable}, + {"/batches", nil, http.StatusServiceUnavailable}, + {"/accounting", nil, http.StatusServiceUnavailable}, + {"/stake/withdrawable", nil, http.StatusServiceUnavailable}, + {"/stake/{amount}", nil, http.StatusServiceUnavailable}, + {"/stake", nil, http.StatusServiceUnavailable}, + {"/redistributionstate", nil, http.StatusServiceUnavailable}, + {"/status", nil, http.StatusServiceUnavailable}, + {"/status/peers", nil, http.StatusServiceUnavailable}, + {"/status/neighborhoods", nil, http.StatusServiceUnavailable}, + {"/rchash/{depth}/{anchor1}/{anchor2}", nil, http.StatusServiceUnavailable}, + }, + }, + { + name: "swap_disabled", + serverOptions: testServerOptions{ + FullAPIDisabled: false, + SwapDisabled: true, + ChequebookDisabled: false, + }, + expectedStatuses: []struct { + route string + expectedMethods []string + expectedStatus int + }{ + // routes from mountTechnicalDebug + {"/node", []string{"GET"}, http.StatusNoContent}, + {"/addresses", []string{"GET"}, http.StatusNoContent}, + {"/chainstate", []string{"GET"}, http.StatusNoContent}, + {"/debugstore", []string{"GET"}, http.StatusNoContent}, + {"/loggers", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp/1", []string{"PUT"}, http.StatusNoContent}, + {"/readiness", nil, http.StatusBadRequest}, + {"/health", nil, http.StatusOK}, + {"/metrics", nil, http.StatusOK}, + {"/not_found", nil, http.StatusNotFound}, + + // routes from mountAPI + {"/", nil, http.StatusOK}, + {"/robots.txt", nil, http.StatusOK}, + {"/bytes", []string{"POST"}, http.StatusNoContent}, + {"/bytes/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/chunks", []string{"POST"}, http.StatusNoContent}, + {"/chunks/stream", nil, http.StatusBadRequest}, + {"/chunks/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/envelope/{address}", []string{"POST"}, http.StatusNoContent}, + {"/soc/{owner}/{id}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/feeds/{owner}/{topic}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/bzz", []string{"POST"}, http.StatusNoContent}, + {"/grantee", []string{"POST"}, http.StatusNoContent}, + {"/grantee/{address}", []string{"GET", "PATCH"}, http.StatusNoContent}, + {"/bzz/{address}", []string{"GET"}, http.StatusNoContent}, + {"/bzz/{address}/{path:.*}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/pss/send/{topic}/{targets}", []string{"POST"}, http.StatusNoContent}, + {"/pss/subscribe/{topic}", nil, http.StatusBadRequest}, + {"/tags", []string{"GET", "POST"}, http.StatusNoContent}, + {"/tags/{id}", []string{"GET", "DELETE", "PATCH"}, http.StatusNoContent}, + {"/pins", []string{"GET"}, http.StatusNoContent}, + {"/pins/check", []string{"GET"}, http.StatusNoContent}, + {"/pins/{reference}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/stewardship/{address}", []string{"GET", "PUT"}, http.StatusNoContent}, + + // routes from mountBusinessDebug + {"/transactions", []string{"GET"}, http.StatusNoContent}, + {"/transactions/{hash}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/peers", []string{"GET"}, http.StatusNoContent}, + {"/pingpong/{address}", []string{"POST"}, http.StatusNoContent}, + {"/reservestate", []string{"GET"}, http.StatusNoContent}, + {"/connect/{multi-address:.+}", []string{"POST"}, http.StatusNoContent}, + {"/blocklist", []string{"GET"}, http.StatusNoContent}, + {"/peers/{address}", []string{"DELETE"}, http.StatusNoContent}, + {"/topology", []string{"GET"}, http.StatusNoContent}, + {"/welcome-message", []string{"GET", "POST"}, http.StatusNoContent}, + {"/balances", []string{"GET"}, http.StatusNoContent}, + {"/balances/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/consumed", []string{"GET"}, http.StatusNoContent}, + {"/consumed/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/timesettlements", []string{"GET"}, http.StatusNoContent}, + {"/settlements", nil, http.StatusNotImplemented}, + {"/settlements/{peer}", nil, http.StatusNotImplemented}, + {"/chequebook/cheque/{peer}", nil, http.StatusNotImplemented}, + {"/chequebook/cheque", nil, http.StatusNotImplemented}, + {"/chequebook/cashout/{peer}", nil, http.StatusNotImplemented}, + {"/chequebook/balance", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/address", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/deposit", []string{"POST"}, http.StatusNoContent}, + {"/chequebook/withdraw", []string{"POST"}, http.StatusNoContent}, + {"/wallet", []string{"GET"}, http.StatusNoContent}, + {"/wallet/withdraw/{coin}", nil, http.StatusNotImplemented}, + {"/stamps", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}/buckets", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{amount}/{depth}", []string{"POST"}, http.StatusNoContent}, + {"/stamps/topup/{batch_id}/{amount}", []string{"PATCH"}, http.StatusNoContent}, + {"/stamps/dilute/{batch_id}/{depth}", []string{"PATCH"}, http.StatusNoContent}, + {"/batches", []string{"GET"}, http.StatusNoContent}, + {"/accounting", []string{"GET"}, http.StatusNoContent}, + {"/stake/withdrawable", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/stake/{amount}", []string{"POST"}, http.StatusNoContent}, + {"/stake", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/redistributionstate", []string{"GET"}, http.StatusNoContent}, + {"/status", []string{"GET"}, http.StatusNoContent}, + {"/status/peers", []string{"GET"}, http.StatusNoContent}, + {"/status/neighborhoods", []string{"GET"}, http.StatusNoContent}, + {"/rchash/{depth}/{anchor1}/{anchor2}", []string{"GET"}, http.StatusNoContent}, + }, + }, + { + name: "chechebook_disabled", + serverOptions: testServerOptions{ + FullAPIDisabled: false, + SwapDisabled: false, + ChequebookDisabled: true, + }, + expectedStatuses: []struct { + route string + expectedMethods []string + expectedStatus int + }{ + // routes from mountTechnicalDebug + {"/node", []string{"GET"}, http.StatusNoContent}, + {"/addresses", []string{"GET"}, http.StatusNoContent}, + {"/chainstate", []string{"GET"}, http.StatusNoContent}, + {"/debugstore", []string{"GET"}, http.StatusNoContent}, + {"/loggers", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp", []string{"GET"}, http.StatusNoContent}, + {"/loggers/some-exp/1", []string{"PUT"}, http.StatusNoContent}, + {"/readiness", nil, http.StatusBadRequest}, + {"/health", nil, http.StatusOK}, + {"/metrics", nil, http.StatusOK}, + {"/not_found", nil, http.StatusNotFound}, + + // routes from mountAPI + {"/", nil, http.StatusOK}, + {"/robots.txt", nil, http.StatusOK}, + {"/bytes", []string{"POST"}, http.StatusNoContent}, + {"/bytes/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/chunks", []string{"POST"}, http.StatusNoContent}, + {"/chunks/stream", nil, http.StatusBadRequest}, + {"/chunks/{address}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/envelope/{address}", []string{"POST"}, http.StatusNoContent}, + {"/soc/{owner}/{id}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/feeds/{owner}/{topic}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/bzz", []string{"POST"}, http.StatusNoContent}, + {"/grantee", []string{"POST"}, http.StatusNoContent}, + {"/grantee/{address}", []string{"GET", "PATCH"}, http.StatusNoContent}, + {"/bzz/{address}", []string{"GET"}, http.StatusNoContent}, + {"/bzz/{address}/{path:.*}", []string{"GET", "HEAD"}, http.StatusNoContent}, + {"/pss/send/{topic}/{targets}", []string{"POST"}, http.StatusNoContent}, + {"/pss/subscribe/{topic}", nil, http.StatusBadRequest}, + {"/tags", []string{"GET", "POST"}, http.StatusNoContent}, + {"/tags/{id}", []string{"GET", "DELETE", "PATCH"}, http.StatusNoContent}, + {"/pins", []string{"GET"}, http.StatusNoContent}, + {"/pins/check", []string{"GET"}, http.StatusNoContent}, + {"/pins/{reference}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/stewardship/{address}", []string{"GET", "PUT"}, http.StatusNoContent}, + + // routes from mountBusinessDebug + {"/transactions", []string{"GET"}, http.StatusNoContent}, + {"/transactions/{hash}", []string{"GET", "POST", "DELETE"}, http.StatusNoContent}, + {"/peers", []string{"GET"}, http.StatusNoContent}, + {"/pingpong/{address}", []string{"POST"}, http.StatusNoContent}, + {"/reservestate", []string{"GET"}, http.StatusNoContent}, + {"/connect/{multi-address:.+}", []string{"POST"}, http.StatusNoContent}, + {"/blocklist", []string{"GET"}, http.StatusNoContent}, + {"/peers/{address}", []string{"DELETE"}, http.StatusNoContent}, + {"/topology", []string{"GET"}, http.StatusNoContent}, + {"/welcome-message", []string{"GET", "POST"}, http.StatusNoContent}, + {"/balances", []string{"GET"}, http.StatusNoContent}, + {"/balances/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/consumed", []string{"GET"}, http.StatusNoContent}, + {"/consumed/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/timesettlements", []string{"GET"}, http.StatusNoContent}, + {"/settlements", []string{"GET"}, http.StatusNoContent}, + {"/settlements/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cheque/{peer}", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cheque", []string{"GET"}, http.StatusNoContent}, + {"/chequebook/cashout/{peer}", []string{"GET", "POST"}, http.StatusNoContent}, + {"/chequebook/balance", nil, http.StatusNotImplemented}, + {"/chequebook/address", nil, http.StatusNotImplemented}, + {"/chequebook/deposit", nil, http.StatusNotImplemented}, + {"/chequebook/withdraw", nil, http.StatusNotImplemented}, + {"/wallet", nil, http.StatusNotImplemented}, + {"/wallet/withdraw/{coin}", nil, http.StatusNotImplemented}, + {"/stamps", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{batch_id}/buckets", []string{"GET"}, http.StatusNoContent}, + {"/stamps/{amount}/{depth}", []string{"POST"}, http.StatusNoContent}, + {"/stamps/topup/{batch_id}/{amount}", []string{"PATCH"}, http.StatusNoContent}, + {"/stamps/dilute/{batch_id}/{depth}", []string{"PATCH"}, http.StatusNoContent}, + {"/batches", []string{"GET"}, http.StatusNoContent}, + {"/accounting", []string{"GET"}, http.StatusNoContent}, + {"/stake/withdrawable", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/stake/{amount}", []string{"POST"}, http.StatusNoContent}, + {"/stake", []string{"GET", "DELETE"}, http.StatusNoContent}, + {"/redistributionstate", []string{"GET"}, http.StatusNoContent}, + {"/status", []string{"GET"}, http.StatusNoContent}, + {"/status/peers", []string{"GET"}, http.StatusNoContent}, + {"/status/neighborhoods", []string{"GET"}, http.StatusNoContent}, + {"/rchash/{depth}/{anchor1}/{anchor2}", []string{"GET"}, http.StatusNoContent}, + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + testServer, _, _, _ := newTestServer(t, tc.serverOptions) + + routeToName := func(route string) string { + if route == "/" { + return "root" + } + return strings.ReplaceAll(route, "/", "_") + } + + for _, tt := range tc.expectedStatuses { + t.Run(tc.name+routeToName(tt.route), func(t *testing.T) { + resp := jsonhttptest.Request(t, testServer, http.MethodOptions, tt.route, tt.expectedStatus) + + allowHeader := resp.Get("Allow") + actualMethods := strings.Split(allowHeader, ", ") + + for _, expectedMethod := range tt.expectedMethods { + if !contains(actualMethods, expectedMethod) { + t.Errorf("expected method %s not found for route %s", expectedMethod, tt.route) + } + } + }) + } + }) + } +} + +func contains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} diff --git a/pkg/jsonhttp/handlers.go b/pkg/jsonhttp/handlers.go index 5a954b9d26a..77e63d20f13 100644 --- a/pkg/jsonhttp/handlers.go +++ b/pkg/jsonhttp/handlers.go @@ -45,7 +45,6 @@ func HandleMethods(methods map[string]http.Handler, body string, contentType str w.Header().Set("Content-Type", contentType) w.WriteHeader(http.StatusMethodNotAllowed) fmt.Fprintln(w, body) - } func NotFoundHandler(w http.ResponseWriter, _ *http.Request) { diff --git a/pkg/node/devnode.go b/pkg/node/devnode.go index 5439fe2d2a7..9d34f1aaa57 100644 --- a/pkg/node/devnode.go +++ b/pkg/node/devnode.go @@ -137,7 +137,7 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) { return nil, fmt.Errorf("blockchain address: %w", err) } - var mockTransaction = transactionmock.New(transactionmock.WithPendingTransactionsFunc(func() ([]common.Hash, error) { + mockTransaction := transactionmock.New(transactionmock.WithPendingTransactionsFunc(func() ([]common.Hash, error) { return []common.Hash{common.HexToHash("abcd")}, nil }), transactionmock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error { return nil @@ -303,13 +303,11 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) { )) ) - var ( - // syncStatusFn mocks sync status because complete sync is required in order to curl certain apis e.g. /stamps. - // this allows accessing those apis by passing true to isDone in devNode. - syncStatusFn = func() (isDone bool, err error) { - return true, nil - } - ) + // syncStatusFn mocks sync status because complete sync is required in order to curl certain apis e.g. /stamps. + // this allows accessing those apis by passing true to isDone in devNode. + syncStatusFn := func() (isDone bool, err error) { + return true, nil + } mockFeeds := factory.New(localStore.Download(true)) mockResolver := resolverMock.NewResolver() @@ -351,7 +349,7 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) { SyncStatus: syncStatusFn, } - var erc20 = erc20mock.New( + erc20 := erc20mock.New( erc20mock.WithBalanceOfFunc(func(ctx context.Context, address common.Address) (*big.Int, error) { return big.NewInt(0), nil }), @@ -366,10 +364,9 @@ func NewDevBee(logger log.Logger, o *DevOptions) (b *DevBee, err error) { CORSAllowedOrigins: o.CORSAllowedOrigins, WsPingPeriod: 60 * time.Second, }, debugOpts, 1, erc20) - apiService.MountTechnicalDebug() - apiService.MountDebug() - apiService.MountAPI() + apiService.Mount() + apiService.EnableFullAPI() apiService.SetProbe(probe) apiService.SetP2P(p2ps) apiService.SetSwarmAddress(&swarmAddress) @@ -444,7 +441,6 @@ func pong(_ context.Context, _ swarm.Address, _ ...string) (rtt time.Duration, e } func randomAddress() (swarm.Address, error) { - b := make([]byte, 32) _, err := rand.Read(b) @@ -453,5 +449,4 @@ func randomAddress() (swarm.Address, error) { } return swarm.NewAddress(b), nil - } diff --git a/pkg/node/node.go b/pkg/node/node.go index 6db098c78b6..09f24712056 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -450,7 +450,8 @@ func NewBee( o.CORSAllowedOrigins, stamperStore, ) - apiService.MountTechnicalDebug() + + apiService.Mount() apiService.SetProbe(probe) apiService.SetSwarmAddress(&swarmAddress) @@ -1178,8 +1179,7 @@ func NewBee( WsPingPeriod: 60 * time.Second, }, extraOpts, chainID, erc20Service) - apiService.MountDebug() - apiService.MountAPI() + apiService.EnableFullAPI() apiService.SetRedistributionAgent(agent) } From 243bd3c4a1d5e504a0b48056cc364164fccbf316 Mon Sep 17 00:00:00 2001 From: istae <14264581+istae@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:42:41 +0300 Subject: [PATCH 6/6] chore: upgrade abi (#4879) --- .github/workflows/beekeeper.yml | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/beekeeper.yml b/.github/workflows/beekeeper.yml index 6b56f48e515..9fff6e646a8 100644 --- a/.github/workflows/beekeeper.yml +++ b/.github/workflows/beekeeper.yml @@ -12,7 +12,7 @@ env: REPLICA: 3 RUN_TYPE: "PR RUN" SETUP_CONTRACT_IMAGE: "ethersphere/bee-localchain" - SETUP_CONTRACT_IMAGE_TAG: "0.9.2-rc1" + SETUP_CONTRACT_IMAGE_TAG: "0.9.2-rc5" BEELOCAL_BRANCH: "main" BEEKEEPER_BRANCH: "master" BEEKEEPER_METRICS_ENABLED: false diff --git a/go.mod b/go.mod index f37fc36bebc..38a8ce09fbd 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/coreos/go-semver v0.3.0 github.com/ethereum/go-ethereum v1.14.3 github.com/ethersphere/go-price-oracle-abi v0.2.0 - github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc1 + github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc5 github.com/ethersphere/go-sw3-abi v0.6.5 github.com/ethersphere/langos v1.0.0 github.com/go-playground/validator/v10 v10.11.1 diff --git a/go.sum b/go.sum index b837278926d..1a206f61c2a 100644 --- a/go.sum +++ b/go.sum @@ -236,8 +236,8 @@ github.com/ethereum/go-ethereum v1.14.3 h1:5zvnAqLtnCZrU9uod1JCvHWJbPMURzYFHfc2e github.com/ethereum/go-ethereum v1.14.3/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= github.com/ethersphere/go-price-oracle-abi v0.2.0 h1:wtIcYLgNZHY4BjYwJCnu93SvJdVAZVvBaKinspyyHvQ= github.com/ethersphere/go-price-oracle-abi v0.2.0/go.mod h1:sI/Qj4/zJ23/b1enzwMMv0/hLTpPNVNacEwCWjo6yBk= -github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc1 h1:Cf3LFlz87FqlTqcuN4q4Hry4iUaAbbroaFxpCgHVhtY= -github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc1/go.mod h1:SXvJVtM4sEsaSKD0jc1ClpDLw8ErPoROZDme4Wrc/Nc= +github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc5 h1:orVNqoeAQTavuKmYSJYJF+nfy4wHBL9ZzS3vV1z2K9o= +github.com/ethersphere/go-storage-incentives-abi v0.9.2-rc5/go.mod h1:SXvJVtM4sEsaSKD0jc1ClpDLw8ErPoROZDme4Wrc/Nc= github.com/ethersphere/go-sw3-abi v0.6.5 h1:M5dcIe1zQYvGpY2K07UNkNU9Obc4U+A1fz68Ho/Q+XE= github.com/ethersphere/go-sw3-abi v0.6.5/go.mod h1:BmpsvJ8idQZdYEtWnvxA8POYQ8Rl/NhyCdF0zLMOOJU= github.com/ethersphere/langos v1.0.0 h1:NBtNKzXTTRSue95uOlzPN4py7Aofs0xWPzyj4AI1Vcc=