Skip to content

fix: default redundancy level#5383

Open
nugaon wants to merge 17 commits into
masterfrom
fix/default-redundancy-level
Open

fix: default redundancy level#5383
nugaon wants to merge 17 commits into
masterfrom
fix/default-redundancy-level

Conversation

@nugaon
Copy link
Copy Markdown
Member

@nugaon nugaon commented Feb 27, 2026

Resolves: #5282

Fix: Redundancy Level Validations and Default Handling

Problem Statement

The Bee API had inconsistent handling of redundancy levels across different endpoints:

  1. Missing validation: The Swarm-Redundancy-Level header was not validated, allowing invalid values to be passed through
  2. Hardcoded defaults: Many endpoints used hardcoded redundancy.DefaultLevel instead of respecting user-provided redundancy levels from request headers
  3. Incorrect semantic defaults: Upload and download operations used the same default redundancy level, despite having different safety/efficiency requirements
  4. Missing coverage: Several endpoints (stewardship, pinning, feed, ACT) had no support for the Swarm-Redundancy-Level header at all

Changes Made

1. Added Header Validation (validate:"omitempty,rLevel")

Added validation to all endpoints that accept the Swarm-Redundancy-Level header to ensure values are within the valid range (0-4):

  • pkg/api/accesscontrol.go - All 4 ACT handlers
  • pkg/api/feed.go - Feed post handler
  • pkg/api/pin.go - Pin root hash handler
  • pkg/api/stewardship.go - Both stewardship handlers

2. Introduced Semantic Default Levels

Created two distinct default redundancy levels in pkg/file/redundancy/level.go:

// DefaultDownloadLevel is the default redundancy level for downloading chunks
// expected to exist in the network (non-feed chunks)
const DefaultDownloadLevel = PARANOID  // Maximum safety for downloads

// DefaultUploadLevel is the default redundancy level for uploading chunks
const DefaultUploadLevel = MEDIUM  // Balanced efficiency for uploads

3. Fixed Hardcoded Redundancy Levels

Replaced hardcoded redundancy.DefaultLevel with appropriate context-aware defaults:

Upload Operations (use DefaultUploadLevel)

  • pkg/api/bytes.go - Bytes upload
  • pkg/api/feed.go - Feed post — manifest now carries the level encoding
  • pkg/api/accesscontrol.go - ACT grantee creation and grant/revoke
  • pkg/api/chunk.go - ACT encryption path only (hardcoded; see Notes)
  • pkg/api/soc.go - ACT encryption path only (hardcoded; see Notes)

Download Operations (use DefaultDownloadLevel)

  • pkg/api/bzz.go - BZZ download
  • pkg/api/accesscontrol.go - ACT decryption and list grantees
  • pkg/api/pin.go - Pinning operations
  • pkg/api/stewardship.go - Stewardship operations (previously no header support)

4. Moved rLevel from Traversal Struct to Traverse Method Parameter

pkg/traversal/traversal.go previously stored the redundancy level on the service struct at construction time. This was wrong because the same Traverser instance can be called from different sessions with different redundancy requirements (e.g. stewardship reupload vs. retrieval check). The level is now passed directly to Traverse(ctx, addr, fn, rLevel).

All callers updated accordingly:

  • pkg/api/pin.go
  • pkg/api/stewardship.go
  • pkg/steward/steward.go
  • pkg/traversal/traversal_test.go

5. Updated Steward Interface and Service

  • steward.Interface methods Reupload and IsRetrievable now accept a redundancy.Level parameter, forwarded from the API layer
  • pkg/steward/steward.go uses DefaultDownloadLevel as fallback when no level is provided via header
  • Steward tests updated to pass redundancy.PARANOID explicitly (previously no level was passed)
  • pkg/steward/mock/steward.go updated to match the new interface signatures

6. Added Swarm-Redundancy-Level Header to New Endpoints

The following endpoints previously had no support for the header and now accept it as an optional input:

  • POST /feeds/{owner}/{topic} — controls feed pipeline redundancy
  • GET /stewardship/{reference} — controls traversal redundancy level for retrievability check
  • PUT /stewardship/{reference} — controls traversal redundancy level for re-upload
  • POST /pins/{reference} — controls traversal redundancy level for pinning
  • POST /grantee — ACT create grantee list
  • GET /grantee/{reference} — ACT read grantee list
  • PATCH /grantee/{reference} — ACT update grantee list

7. Updated OpenAPI Documentation

Updated openapi/Swarm.yaml to document the Swarm-Redundancy-Level header across all affected endpoints. The Swarm-Redundancy-Level parameter was intentionally not added to POST /chunks and POST /soc/{owner}/{id}: ACT on those endpoints is semantically broken and will be removed (see #5469); the redundancy level for the ACT path is hardcoded to DefaultUploadLevel in the meantime.

8. Updated Tests

  • Traversal tests: traversal.New no longer takes rLevel; level now passed to Traverse()
  • Steward tests: explicit redundancy.PARANOID passed to Reupload and IsRetrievable
  • Stewardship API tests: mock updated to match new interface
  • Access control, file operation, joiner, and loadsave tests updated for new defaults

Impact

Before

// All operations used the same default, no header support on most endpoints
ls := loadsave.NewReadonly(s.storer.Download(cache), s.storer.Cache(), redundancy.DefaultLevel)

After

// Downloads use PARANOID for safety, uploads use MEDIUM for efficiency
// Header is respected when provided
rLevel := redundancy.DefaultDownloadLevel
if headers.RLevel != nil {
    rLevel = *headers.RLevel
}
ls := loadsave.NewReadonly(s.storer.Download(cache), s.storer.Cache(), rLevel)

Benefits

  1. Better UX: Users can now control redundancy levels via headers across all meaningful endpoints
  2. Validation: Invalid redundancy levels are rejected early with clear error messages
  3. Semantic Defaults: Downloads prioritise safety (PARANOID), uploads prioritise efficiency (MEDIUM)
  4. Consistency: All API endpoints handle redundancy levels uniformly where it makes sense
  5. Correct Traversal Sessions: rLevel is now per-call rather than per-service-instance, enabling correct behaviour when the traverser is reused across different request contexts

Notes

  • POST /chunks and POST /soc/{owner}/{id} do not expose Swarm-Redundancy-Level. ACT on raw chunk and SOC endpoints is semantically broken (the payload is never encrypted; ACT only wraps the reference; the SOC GET endpoint has no ACT decryption path) and will be removed in a follow-up — see Remove ACT support from SOC and chunk endpoints #5469. The redundancy level for the ACT code path is hardcoded to DefaultUploadLevel in both handlers until that cleanup is done.
  • The steward service no longer handles dispersed replica re-upload internally; the redundancy level is passed through for traversal purposes only.

Checklist

  • I have read the coding guide.
  • My change requires a documentation update, and I have done it.
  • I have added tests to cover my changes.
  • I have filled out the description and linked the related issues.

Description

Open API Spec Version Changes (if applicable)

Motivation and Context (Optional)

Related Issue (Optional)

Screenshots (if appropriate):

@nugaon nugaon force-pushed the fix/default-redundancy-level branch from 975f137 to 8c4bbb0 Compare May 4, 2026 11:39
@gacevicljubisa gacevicljubisa marked this pull request as ready for review May 19, 2026 11:24
@martinconic
Copy link
Copy Markdown
Contributor

martinconic commented May 20, 2026

I see there are 2 things , please can you check them?

  1. POST /bzz still defaults uploads to NONE. It's passed straight through to fileUploadHandler/dirUploadHandler (bzz.go:150,160). When the header is absent, the value type defaults to 0 (NONE). This might be caught if we would have a similar TestStewardshipWithRedundancy test as we do for /bytes ?

  2. POST /chunks documents the header but ignores it. OpenAPI now advertises swarm-redundancy-level on POST /chunks ("Redundancy level for ACT encryption only"), but chunkUploadHandler (pkg/api/chunk.go:35-40) has no RLevel field and hardcodes redundancy.DefaultUploadLevel into actEncryptionHandler (chunk.go:189). So the header is silently dropped. This is inconsistent with soc.go, which is described identically ("ACT encryption only") but does read the header (soc.go:55,186-190).

Comment thread openapi/Swarm.yaml Outdated
@nugaon
Copy link
Copy Markdown
Member Author

nugaon commented May 20, 2026

Thanks @martinconic for your comment, I fixed the bzz endpoint related rlevel issue, it wasn't reference type like on other endpoints...

for the chunks/soc endpoints, I just hard-coded these values now, because IMO these don't need ACT feature. I created issue for that #5469

@martinconic
Copy link
Copy Markdown
Contributor

LGTM, maybe we could add a quick test that uploads the same content to POST /bytes and POST /bzz with no header vs. explicit MEDIUM/NONE and asserts no-header == MEDIUM (and != NONE)? TestStewardshipWithRedundancy only drives POST /bytes with an explicit Swarm-Redundancy-Level header

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inconsistent Swarm-Redundancy-Level Header Handling Across API Endpoints

2 participants