Skip to content

feat(rpcsmartrouter): add /debug/reset-scores endpoint for optimizer state reset#2264

Merged
Harraken merged 4 commits into
mainfrom
feat/debug_cache_flush
Apr 15, 2026
Merged

feat(rpcsmartrouter): add /debug/reset-scores endpoint for optimizer state reset#2264
Harraken merged 4 commits into
mainfrom
feat/debug_cache_flush

Conversation

@VicSheCodes

@VicSheCodes VicSheCodes commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

Closes: #1565

PR: Add POST /debug/reset-scores Debug Endpoint

What this does

Adds a new debug HTTP endpoint, POST /debug/reset-scores, in both:

  • protocol/rpcsmartrouter/rpcsmartrouter.go
  • protocol/rpcconsumer/rpcconsumer.go

The endpoint clears optimizer score state immediately by calling ProviderOptimizer.ResetState() for every chain optimizer, without changing clock offset.

This is an additive capability. Existing /debug/time-warp and /debug/time behavior remains unchanged.


Validator / Provider impact

  • Validators: no impact (no consensus/state-machine changes).
  • Providers: no impact.
  • Consumers / Smart router: no impact unless debug server is explicitly enabled via --debug-address.
  • Config changes: none required for production.

Author Checklist

  • read the contribution guide
  • included the correct type prefix in the PR title: feat
  • confirmed breaking-change marker ! is not needed (no breaking changes)
  • targeted main
  • included unit tests for new behavior in both packages
  • updated docs/comments where needed
  • CI checks passed (pending)

Changes

protocol/rpcconsumer/rpcconsumer.go

  • Extended buildDebugMux(...) with:
    • POST /debug/reset-scores
  • Handler behavior:
    • method guard: POST only
    • iterates optimizers.Range(...)
    • calls opt.ResetState() on each optimizer
    • returns JSON: {"reset":true,"chains_reset":<N>}
  • Concurrency model is unchanged from prior debug server change:
    • no mutation of currentOffsetNano
    • no mutation of NowFunc

protocol/rpcsmartrouter/rpcsmartrouter.go

  • Same POST /debug/reset-scores handler added in buildDebugMux(...).
  • Same response contract and method validation as rpcconsumer.

protocol/rpcconsumer/debug_server_test.go

  • Added:
    • TestDebugResetScores_ReturnsJSON
    • TestDebugResetScores_MethodNotAllowed
    • TestDebugResetScores_DoesNotChangeOffset

protocol/rpcsmartrouter/debug_server_test.go

  • Added:
    • TestDebugResetScores_SmartRouter_ReturnsJSON
    • TestDebugResetScores_SmartRouter_MethodNotAllowed
    • TestDebugResetScores_SmartRouter_DoesNotChangeOffset

Why this is needed

Current test flow to clear optimizer scores often uses a full clock dance:

  1. warp clock forward
  2. send relay
  3. reset clock

That flow works, but is multi-step and also changes effective time.

POST /debug/reset-scores provides a direct score reset operation for integration tests when time-shift semantics are not needed.

This endpoint is not a replacement for clock injection; it is an additional debug tool.


API

Existing (unchanged)

Shift clock:

POST /debug/time-warp
{"offset_seconds": 3600}

Read effective/real time:

GET /debug/time

New

Reset optimizer score state immediately:

POST /debug/reset-scores

Response example:

{"reset":true,"chains_reset":2}

Method guard example:

  • GET /debug/reset-scores -> 405 POST only

Tests

Executed locally:

go test ./protocol/rpcconsumer/... ./protocol/rpcsmartrouter/...

Result:

  • ok github.com/lavanet/lava/v5/protocol/rpcconsumer
  • ok github.com/lavanet/lava/v5/protocol/rpcsmartrouter

Production safety

  • Debug endpoints only exist when --debug-address is set.
  • No changes to default runtime behavior when debug server is disabled.
  • No on-chain/state-machine/protocol compatibility impact.

Example usage

# reset scores without touching clock offset
curl -i -X POST https://debug.<USERNAME>.magmadevs.com/debug/reset-scores

# verify clock offset is unchanged
curl -s https://debug.<USERNAME>.magmadevs.com/debug/time | python3 -m json.tool

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add /debug/reset-scores endpoint for optimizer state reset

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add POST /debug/reset-scores endpoint to clear optimizer scores
• Implement handler in both RPCConsumer and RPCSmartRouter packages
• Returns JSON with reset status and chain count
• Add comprehensive unit tests for new endpoint
Diagram
flowchart LR
  A["POST /debug/reset-scores"] --> B["Method Guard"]
  B --> C["Iterate Optimizers"]
  C --> D["Call ResetState"]
  D --> E["Return JSON Response"]
  E --> F["chains_reset count"]
Loading

Grey Divider

File Changes

1. protocol/rpcconsumer/rpcconsumer.go ✨ Enhancement +19/-1

Add reset-scores debug endpoint to RPCConsumer

• Add POST /debug/reset-scores handler to buildDebugMux function
• Validate POST method only, reject other HTTP methods
• Iterate through all optimizers and call ResetState on each
• Return JSON response with reset status and chain count
• Update function documentation to mention new endpoint

protocol/rpcconsumer/rpcconsumer.go


2. protocol/rpcconsumer/debug_server_test.go 🧪 Tests +48/-0

Add unit tests for reset-scores endpoint

• Add postResetScores helper function for test requests
• Add TestDebugResetScores_ReturnsJSON to verify successful response
• Add TestDebugResetScores_MethodNotAllowed to verify POST-only enforcement
• Add TestDebugResetScores_DoesNotChangeOffset to verify offset preservation

protocol/rpcconsumer/debug_server_test.go


3. protocol/rpcsmartrouter/rpcsmartrouter.go ✨ Enhancement +19/-1

Add reset-scores debug endpoint to RPCSmartRouter

• Add POST /debug/reset-scores handler to buildDebugMux function
• Validate POST method only, reject other HTTP methods
• Iterate through all optimizers and call ResetState on each
• Return JSON response with reset status and chain count
• Update function documentation to mention new endpoint

protocol/rpcsmartrouter/rpcsmartrouter.go


View more (1)
4. protocol/rpcsmartrouter/debug_server_test.go 🧪 Tests +47/-0

Add unit tests for SmartRouter reset-scores endpoint

• Add postResetScoresRouter helper function for test requests
• Add TestDebugResetScores_SmartRouter_ReturnsJSON to verify response
• Add TestDebugResetScores_SmartRouter_MethodNotAllowed to verify POST-only
• Add TestDebugResetScores_SmartRouter_DoesNotChangeOffset to verify offset

protocol/rpcsmartrouter/debug_server_test.go


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Apr 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1)   📘 Rule violations (0)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ⛨ Security (1)

Grey Divider


Remediation recommended

1. CSRFable reset-scores endpoint 🐞
Description
The new POST /debug/reset-scores handler mutates optimizer state but accepts an empty POST with no
Content-Type/body/token validation, so it can be triggered by cross-origin browser requests (e.g., a
simple HTML form) whenever the debug server is enabled. This is a meaningful security footgun
compared to /debug/time-warp, which effectively requires JSON parsing and therefore is harder to
invoke without preflight-triggering headers.
Code

protocol/rpcconsumer/rpcconsumer.go[R402-417]

+	// POST /debug/reset-scores — clears optimizer score state without changing
+	// current time offset or NowFunc.
+	mux.HandleFunc("/debug/reset-scores", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != http.MethodPost {
+			http.Error(w, "POST only", http.StatusMethodNotAllowed)
+			return
+		}
+		count := 0
+		optimizers.Range(func(chainID string, opt *provideroptimizer.ProviderOptimizer) bool {
+			opt.ResetState()
+			count++
+			return true
+		})
+		w.Header().Set("Content-Type", "application/json")
+		fmt.Fprintf(w, `{"reset":true,"chains_reset":%d}`, count)
+	})
Evidence
In both buildDebugMux copies, /debug/reset-scores only checks the HTTP method and then immediately
calls ResetState() across optimizers; there is no check for a required header/token or JSON body,
which makes it trivially invokable by "simple" cross-origin POSTs. The new tests explicitly
demonstrate that a nil-body POST with no headers succeeds (200), confirming the endpoint is designed
to be callable this way.

protocol/rpcconsumer/rpcconsumer.go[402-417]
protocol/rpcsmartrouter/rpcsmartrouter.go[417-432]
protocol/rpcconsumer/debug_server_test.go[31-37]
protocol/rpcconsumer/debug_server_test.go[186-194]
protocol/rpcconsumer/rpcconsumer.go[266-283]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`POST /debug/reset-scores` is state-changing but currently accepts an empty POST with no header/body validation. This makes it easy to trigger from untrusted browser contexts (CSRF-style) whenever the debug server is enabled.

### Issue Context
Unlike `/debug/time-warp`, this endpoint does not require JSON decoding, so it can be invoked by a "simple" cross-origin POST (e.g., HTML form) without any special headers.

### Fix Focus Areas
- Add a required header token (e.g., `X-Debug-Token`) configured via flag/env, and return 401 if missing/invalid; **and/or**
- Require `Content-Type: application/json` and decode a trivial body (e.g., `{}`) so "simple" form POSTs fail.

- protocol/rpcconsumer/rpcconsumer.go[402-417]
- protocol/rpcsmartrouter/rpcsmartrouter.go[417-432]
- protocol/rpcconsumer/debug_server_test.go[31-37]
- protocol/rpcsmartrouter/debug_server_test.go[27-32]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@codecov

codecov Bot commented Apr 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.33333% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
protocol/rpcconsumer/rpcconsumer.go 58.33% 4 Missing and 1 partial ⚠️
protocol/rpcsmartrouter/rpcsmartrouter.go 58.33% 4 Missing and 1 partial ⚠️
Flag Coverage Δ
consensus 8.98% <ø> (ø)
protocol 35.23% <58.33%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
protocol/rpcconsumer/rpcconsumer.go 7.70% <58.33%> (ø)
protocol/rpcsmartrouter/rpcsmartrouter.go 9.76% <58.33%> (ø)

... and 207 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Apr 12, 2026

Copy link
Copy Markdown

Test Results

0 tests  ±0   0 ✅ ±0   0s ⏱️ ±0s
0 suites ±0   0 💤 ±0 
7 files   ±0   0 ❌ ±0 

Results for commit e8a3f5b. ± Comparison against base commit 5741773.

♻️ This comment has been updated with latest results.

@VicSheCodes VicSheCodes self-assigned this Apr 12, 2026
@VicSheCodes VicSheCodes requested a review from NadavLevi April 15, 2026 08:37
Comment thread protocol/rpcsmartrouter/rpcsmartrouter.go
Comment thread protocol/rpcconsumer/rpcconsumer.go
@Harraken Harraken merged commit a359acc into main Apr 15, 2026
3 checks passed
@Harraken Harraken deleted the feat/debug_cache_flush branch April 15, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants