Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions openapi/Swarm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2436,6 +2436,36 @@ paths:
$ref: "SwarmCommon.yaml#/components/responses/500"
default:
description: Default response
patch:
summary: Enable or disable participation in new redistribution rounds
description: >
Controls whether the node will commit in a new redistribution round.
Sampling still runs while disabled so that a later re-enable can commit
in the following commit phase. Disabling does not abort an in-flight
commit and does not skip reveal or claim for a round that already committed.
Re-enabling during a commit phase that was already skipped does not retry
that round. After a node restart participation is enabled again.
tags:
- RedistributionState
requestBody:
required: true
content:
application/json:
schema:
$ref: "SwarmCommon.yaml#/components/schemas/RedistributionEnableRequest"
responses:
"200":
description: Participation flag updated
content:
application/json:
schema:
$ref: "SwarmCommon.yaml#/components/schemas/RedistributionEnableResponse"
"400":
$ref: "SwarmCommon.yaml#/components/responses/400"
"500":
$ref: "SwarmCommon.yaml#/components/responses/500"
default:
description: Default response
"/wallet":
get:
summary: Get wallet balance for BZZ and xDAI
Expand Down
24 changes: 24 additions & 0 deletions openapi/SwarmCommon.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,15 @@ components:
type: boolean
isHealthy:
type: boolean
enabled:
type: boolean
description: Whether the node will commit in new redistribution rounds. Sampling still runs while disabled. A disabled node still finishes a round that already has an on-chain commit. Re-enabling during a commit phase that was already skipped does not retry that round.
hasCommittedThisRound:
type: boolean
description: Whether the node has already committed in the current round. Operators can shut down without freeze risk when this is false.
hasRevealedThisRound:
type: boolean
description: Whether the node has revealed in the current round. After a commit, the node must reveal before it is safe to shut down.
phase:
type: string
round:
Expand All @@ -858,6 +867,21 @@ components:
fees:
$ref: "#/components/schemas/BigInt"

RedistributionEnableRequest:
type: object
required:
- enabled
properties:
enabled:
type: boolean
description: Whether the node should commit in new redistribution rounds. Sampling still runs while disabled.

RedistributionEnableResponse:
type: object
properties:
enabled:
type: boolean

PendingTransactionsResponse:
type: object
properties:
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ func (s *Service) corsHandler(h http.Handler) http.Handler {
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Origin", o)
w.Header().Set("Access-Control-Allow-Headers", allowedHeadersStr)
w.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE")
w.Header().Set("Access-Control-Max-Age", "3600")
}
h.ServeHTTP(w, r)
Expand Down
38 changes: 21 additions & 17 deletions pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/websocket"
"resenje.org/web"

"github.com/ethersphere/bee/v2/pkg/accesscontrol"
mockac "github.com/ethersphere/bee/v2/pkg/accesscontrol/mock"
accountingmock "github.com/ethersphere/bee/v2/pkg/accounting/mock"
Expand Down Expand Up @@ -70,8 +73,6 @@ import (
"github.com/ethersphere/bee/v2/pkg/transaction/backendmock"
transactionmock "github.com/ethersphere/bee/v2/pkg/transaction/mock"
"github.com/ethersphere/bee/v2/pkg/util/testutil"
"github.com/gorilla/websocket"
"resenje.org/web"
)

var (
Expand Down Expand Up @@ -126,17 +127,18 @@ type testServerOptions struct {
BatchStore postage.Storer
SyncStatus func() (bool, error)

BackendOpts []backendmock.Option
Erc20Opts []erc20mock.Option
BeeMode api.BeeNodeMode
RedistributionAgent *storageincentives.Agent
NodeStatus *status.Service
PinIntegrity api.PinIntegrity
WhitelistedAddr string
FullAPIDisabled bool
ChequebookDisabled bool
SwapDisabled bool
Erc20ServiceNil bool
BackendOpts []backendmock.Option
Erc20Opts []erc20mock.Option
BeeMode api.BeeNodeMode
RedistributionAgent *storageincentives.Agent
RedistributionAgentDisabled bool
NodeStatus *status.Service
PinIntegrity api.PinIntegrity
WhitelistedAddr string
FullAPIDisabled bool
ChequebookDisabled bool
SwapDisabled bool
Erc20ServiceNil bool
}

func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.Conn, string, *chanStorer) {
Expand Down Expand Up @@ -223,11 +225,13 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.

s.SetP2P(o.P2P)

if o.RedistributionAgent == nil {
o.RedistributionAgent, _ = createRedistributionAgentService(t, o.Overlay, o.StateStorer, erc20, transaction, backend, o.BatchStore)
s.SetRedistributionAgent(o.RedistributionAgent)
if !o.RedistributionAgentDisabled {
if o.RedistributionAgent == nil {
o.RedistributionAgent, _ = createRedistributionAgentService(t, o.Overlay, o.StateStorer, erc20, transaction, backend, o.BatchStore)
s.SetRedistributionAgent(o.RedistributionAgent)
}
testutil.CleanupCloser(t, o.RedistributionAgent)
}
testutil.CleanupCloser(t, o.RedistributionAgent)

s.SetSwarmAddress(&o.Overlay)
s.SetProbe(o.Probe)
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/cors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ func TestCors(t *testing.T) {
endpoint: "tags",
expectedMethods: "GET, POST",
},
{
endpoint: "redistributionstate",
expectedMethods: "GET, PATCH",
},
{
endpoint: "bzz",
expectedMethods: "POST",
Expand Down Expand Up @@ -184,6 +188,11 @@ func TestCorsStatus(t *testing.T) {
notAllowedMethods: http.MethodDelete,
allowedMethods: "GET, POST",
},
{
endpoint: "redistributionstate",
notAllowedMethods: http.MethodPut,
allowedMethods: "GET, PATCH",
},
{
endpoint: "bzz",
notAllowedMethods: http.MethodDelete,
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ type (
StakeTransactionReponse = stakeTransactionReponse
StatusSnapshotResponse = statusSnapshotResponse
StatusResponse = statusResponse
RedistributionStatusResponse = redistributionStatusResponse
RedistributionToggleResponse = redistributionToggleResponse
)

var (
Expand Down
40 changes: 40 additions & 0 deletions pkg/api/redistribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package api

import (
"encoding/json"
"net/http"

"github.com/ethersphere/bee/v2/pkg/bigint"
Expand All @@ -28,6 +29,17 @@ type redistributionStatusResponse struct {
Reward *bigint.BigInt `json:"reward"`
Fees *bigint.BigInt `json:"fees"`
IsHealthy bool `json:"isHealthy"`
Enabled bool `json:"enabled"`
HasCommittedThisRound bool `json:"hasCommittedThisRound"`
HasRevealedThisRound bool `json:"hasRevealedThisRound"`
}

type redistributionToggleRequest struct {
Enabled *bool `json:"enabled"`
}

type redistributionToggleResponse struct {
Enabled bool `json:"enabled"`
}

func (s *Service) redistributionStatusHandler(w http.ResponseWriter, r *http.Request) {
Expand All @@ -54,6 +66,7 @@ func (s *Service) redistributionStatusHandler(w http.ResponseWriter, r *http.Req
return
}

rd := status.RoundData[status.Round]
jsonhttp.OK(w, redistributionStatusResponse{
MinimumGasFunds: bigint.Wrap(minGasFunds),
HasSufficientFunds: hasSufficientFunds,
Expand All @@ -70,5 +83,32 @@ func (s *Service) redistributionStatusHandler(w http.ResponseWriter, r *http.Req
Reward: bigint.Wrap(status.Reward),
Fees: bigint.Wrap(status.Fees),
IsHealthy: status.IsHealthy,
Enabled: s.redistributionAgent.IsEnabled(),
HasCommittedThisRound: rd.CommitKey != nil,
HasRevealedThisRound: rd.HasRevealed,
})
}

func (s *Service) redistributionToggleHandler(w http.ResponseWriter, r *http.Request) {
logger := tracing.NewLoggerWithTraceID(r.Context(), s.logger.WithName("patch_redistributionstate").Build())

if s.beeMode != FullMode {
jsonhttp.BadRequest(w, errOperationSupportedOnlyInFullMode)
return
}

var body redistributionToggleRequest
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
logger.Debug("decode body failed", "error", err)
logger.Error(nil, "decode body failed")
jsonhttp.BadRequest(w, "invalid request body")
return
}
if body.Enabled == nil {
jsonhttp.BadRequest(w, "enabled is required")
return
}

s.redistributionAgent.SetEnabled(*body.Enabled)
jsonhttp.OK(w, redistributionToggleResponse{Enabled: *body.Enabled})
}
Loading
Loading