Skip to content

Stratum improv#28

Merged
WantClue merged 5 commits into
mainfrom
stratum-improv
May 3, 2026
Merged

Stratum improv#28
WantClue merged 5 commits into
mainfrom
stratum-improv

Conversation

@WantClue
Copy link
Copy Markdown
Owner

@WantClue WantClue commented May 2, 2026

improvs connects with certain pools

Summary by CodeRabbit

  • New Features

    • Pool configuration now accepts full URLs (including protocol and port) with automatic parsing and normalization.
    • Added configuration option to control stratum difficulty suggestion behavior.
  • Improvements

    • Enhanced IPv6 address resolution for stratum connections, including link-local address support.
    • Improved port validation and URL field handling.
    • Optimized queue management with better status tracking and work processing.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 2, 2026

📝 Walkthrough

Walkthrough

The PR enhances Stratum pool configuration by adding a compile-time option to conditionally send mining.suggest_difficulty, allowing full URL input (with protocol and port) in the pool UI, parsing and normalizing URLs at both frontend and backend, improving hostname resolution with IPv6 support, refining job queue management synchronization, and updating job generation logic to use new queue inspection functions.

Changes

Stratum URL Handling & Job Queue Management

Layer / File(s) Summary
Configuration & Work Queue API
main/Kconfig.projbuild, main/work_queue.h, main/work_queue.c
New STRATUM_SUGGEST_DIFFICULTY config option (default disabled) added. Work queue API extended with queue_dequeue_if_full() and queue_count() functions for queue state inspection.
Pool UI Input
main/http_server/forge-os/src/app/components/pool/pool.component.html, main/http_server/forge-os/src/app/components/pool/pool.component.ts
Pool component accepts full Stratum URLs with protocol (stratum+tcp://, stratum+tls://, stratum+ssl://) and port. New onUrlChange() method strips protocol, detects TLS mode, extracts port, and normalizes the URL. Port validation extended to full range (0–65535).
Backend URL Normalization
main/http_server/http_server.c
New save_stratum_url() and parse_port() helpers parse incoming URLs, extract protocol-based TLS settings and ports, and normalize values before storage in NVS. Updates to stratumURL and fallbackStratumURL now apply parsed extraction logic; direct port and TLS fields only apply when URL parsing did not already extract them.
Stratum Connection & Job Logic
main/tasks/stratum_task.c, main/tasks/create_jobs_task.c
New resolve_stratum_address() helper performs hostname resolution with getaddrinfo(), selects IPv4 or IPv6, auto-fills IPv6 link-local scope ID via esp_netif, and logs the resolved address. mining.suggest_difficulty is now conditional on CONFIG_STRATUM_SUGGEST_DIFFICULTY and runtime STRATUM_DIFFICULTY > 0. TLS common-name set only when TLS is enabled. mining.notify clean_jobs logic updated to check stratum queue, ASIC queue, and active jobs; ASIC queue cleared under mutex when clean_jobs is false. Create jobs task uses new queue_count() API and strengthened synchronization for abandon-work handling.

Sequence Diagram

sequenceDiagram
    actor User as User
    participant UI as Pool Component UI
    participant HTTP as HTTP Server
    participant NVS as NVS Storage
    participant Stratum as Stratum Task
    participant Pool as Stratum Pool Server

    User->>UI: Paste full URL (e.g., stratum+tls://pool.com:3333)
    UI->>UI: onUrlChange() detects protocol, extracts port, strips prefix
    UI->>HTTP: updateSystem() sends normalized URL + extracted TLS + Port
    HTTP->>HTTP: save_stratum_url() parses URL, verifies port, detects TLS scheme
    HTTP->>NVS: Write normalized URL, port, TLS mode
    NVS-->>HTTP: Stored
    
    Stratum->>NVS: Read stratumURL, stratumPort, stratumTLS
    Stratum->>Stratum: resolve_stratum_address() calls getaddrinfo()
    Stratum->>Stratum: Select AF_INET/AF_INET6, populate sockaddr, set scope_id if needed
    Stratum->>Pool: Connect using resolved host_ip
    Pool-->>Stratum: Connected (TCP or TLS)
    
    alt CONFIG_STRATUM_SUGGEST_DIFFICULTY enabled and STRATUM_DIFFICULTY > 0
        Stratum->>Pool: Send mining.suggest_difficulty
    end
    
    Pool-->>Stratum: Confirm/Response
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly Related PRs

  • Cleanup #25: Modifies main/tasks/stratum_task.c for message ownership and pointer nullifications, overlapping with this PR's stratum task refactoring.
  • red queue and clear jobs #27: Modifies queue management internals and create_jobs_task.c, directly related to the work queue API additions and job management synchronization changes in this PR.
  • double vardiff #26: Affects Stratum difficulty handling representation, related to the conditional mining.suggest_difficulty gating introduced here.

Suggested Labels

enhancement

Poem

🐰 A rabbit hops through URLs bright,
Parsing protocol and port with might,
Hostnames resolved from east to west,
IPv6 scopes put to the test,
Job queues dance in sync, so right! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Stratum improv' is vague and generic, using a non-descriptive abbreviation ('improv') that does not clearly convey the specific changes in the changeset. Replace with a more specific title that describes the main change, such as 'Improve stratum pool connection and job queue management' or 'Enhance stratum URL parsing and queue handling logic'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stratum-improv

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get your free trial and get 200 agent minutes per Slack user (a $50 value).


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/stratum/stratum_api.c (1)

145-175: ⚠️ Potential issue | 🟠 Major

Remove the busy-wait concern; the real issue is the missing timeout/retry limit when nbytes == 0.

When esp_transport_read returns 0 (timeout after 5 seconds with no data), the loop continues and blocks for another 5 seconds. While this is not a busy-wait since esp_transport_read blocks, the function has no maximum retry limit. If the peer closes the connection gracefully or stops sending data, the loop waits indefinitely in 5-second intervals without attempting reconnection.

The proposed fix to track consecutive timeouts and return NULL after a threshold (triggering reconnection logic in the caller) is reasonable for defensive programming, though it should be verified whether this behavior represents a regression from previous implementation or is expected.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/stratum/stratum_api.c` around lines 145 - 175, The loop that reads
into json_rpc_buffer via esp_transport_read currently treats nbytes==0 as a
benign repeat and can block forever in TRANSPORT_TIMEOUT_MS intervals; modify
the read loop in the function that uses recv_buffer/json_rpc_buffer and
esp_transport_read to count consecutive zero-byte timeouts, free json_rpc_buffer
and return NULL after a small configurable threshold (e.g., 3) to trigger
reconnection, reset the counter to 0 on any nbytes>0, and keep the existing
error handling for negative nbytes; ensure realloc_json_buffer is still called
only when nbytes>0 and include the timeout-counter variable scoped to the
function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@components/stratum/stratum_api.c`:
- Around line 145-175: The loop that reads into json_rpc_buffer via
esp_transport_read currently treats nbytes==0 as a benign repeat and can block
forever in TRANSPORT_TIMEOUT_MS intervals; modify the read loop in the function
that uses recv_buffer/json_rpc_buffer and esp_transport_read to count
consecutive zero-byte timeouts, free json_rpc_buffer and return NULL after a
small configurable threshold (e.g., 3) to trigger reconnection, reset the
counter to 0 on any nbytes>0, and keep the existing error handling for negative
nbytes; ensure realloc_json_buffer is still called only when nbytes>0 and
include the timeout-counter variable scoped to the function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 08acb5e1-aa06-432c-a719-a1a3733c746d

📥 Commits

Reviewing files that changed from the base of the PR and between d5a0266 and b06dadc.

📒 Files selected for processing (6)
  • components/stratum/stratum_api.c
  • main/Kconfig.projbuild
  • main/http_server/forge-os/src/app/components/pool/pool.component.html
  • main/http_server/forge-os/src/app/components/pool/pool.component.ts
  • main/http_server/http_server.c
  • main/tasks/stratum_task.c

- Adjusted QUEUE_LOW_WATER_MARK to 1 for more responsive job generation.
- Implemented abandonment handling in create_jobs_task to clear ASIC jobs when work is abandoned.
- Replaced direct access to queue counts with queue_count function for better encapsulation.
- Added has_active_jobs function to check for active jobs in valid_jobs array.
- Enhanced cleanQueue logic to consider active jobs before clearing queues.
- Introduced queue_dequeue_if_full function to handle dequeuing only when the queue is full.
- Updated stratum_task to utilize new queue management functions for improved clarity and maintainability.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
main/tasks/create_jobs_task.c (1)

35-42: 💤 Low value

Consider extracting duplicate abandonment handling into a helper function.

The abandon_work handling logic at lines 35-42 and 68-75 is nearly identical. Extracting this into a static helper would reduce duplication and ensure both paths stay in sync.

♻️ Suggested refactor
+static void handle_abandon_work(GlobalState *GLOBAL_STATE)
+{
+    if (GLOBAL_STATE->abandon_work == 1) {
+        GLOBAL_STATE->abandon_work = 0;
+        pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock);
+        ASIC_jobs_queue_clear(&GLOBAL_STATE->ASIC_jobs_queue);
+        pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
+        xSemaphoreGive(GLOBAL_STATE->ASIC_TASK_MODULE.semaphore);
+    }
+}

Then replace both blocks with handle_abandon_work(GLOBAL_STATE);

Also applies to: 68-75

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/tasks/create_jobs_task.c` around lines 35 - 42, Extract the duplicated
abandon handling into a static helper (e.g., static void
handle_abandon_work(GlobalState *state) or static void handle_abandon_work(void)
if using GLOBAL_STATE directly) and move the logic that checks/clears
state->abandon_work, resets it to 0, locks/unlocks state->valid_jobs_lock, calls
ASIC_jobs_queue_clear(&state->ASIC_jobs_queue) and
xSemaphoreGive(state->ASIC_TASK_MODULE.semaphore) into that helper; then replace
both duplicated blocks (the ones referencing GLOBAL_STATE->abandon_work,
pthread_mutex_lock/unlock, ASIC_jobs_queue_clear, and xSemaphoreGive) with a
single call to handle_abandon_work(GLOBAL_STATE) (or handle_abandon_work()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@main/tasks/stratum_task.c`:
- Around line 206-220: The loops in has_active_jobs() and stratum_reset_uid()
currently step by 4 and only examine every 4th slot of GLOBAL_STATE->valid_jobs;
update both loops (in the functions has_active_jobs and stratum_reset_uid) to
iterate over every index by changing the loop increment from i = i + 4 to i++ so
all 128 uint8_t slots (indices 0..127) are checked under the existing
pthread_mutex_lock sections.

In `@main/work_queue.c`:
- Around line 50-68: The function queue_dequeue_if_full lacks a NULL check for
the out-parameter work and will dereference *work causing a crash if NULL is
passed; add a guard at the start of queue_dequeue_if_full (e.g., if (work ==
NULL) { return false; } or assert) before locking or before any dereference,
then proceed with the existing logic that reads from queue->buffer[queue->head],
updates queue->head and queue->count, signals queue->not_full and returns
dequeued; ensure you return false when work is NULL to preserve behavior and
avoid modifying the queue.

---

Nitpick comments:
In `@main/tasks/create_jobs_task.c`:
- Around line 35-42: Extract the duplicated abandon handling into a static
helper (e.g., static void handle_abandon_work(GlobalState *state) or static void
handle_abandon_work(void) if using GLOBAL_STATE directly) and move the logic
that checks/clears state->abandon_work, resets it to 0, locks/unlocks
state->valid_jobs_lock, calls ASIC_jobs_queue_clear(&state->ASIC_jobs_queue) and
xSemaphoreGive(state->ASIC_TASK_MODULE.semaphore) into that helper; then replace
both duplicated blocks (the ones referencing GLOBAL_STATE->abandon_work,
pthread_mutex_lock/unlock, ASIC_jobs_queue_clear, and xSemaphoreGive) with a
single call to handle_abandon_work(GLOBAL_STATE) (or handle_abandon_work()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5037140-7dc0-42e8-8056-e0084e14bb05

📥 Commits

Reviewing files that changed from the base of the PR and between b06dadc and bd5350a.

⛔ Files ignored due to path filters (1)
  • main/http_server/forge-os/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • main/tasks/create_jobs_task.c
  • main/tasks/stratum_task.c
  • main/work_queue.c
  • main/work_queue.h

Comment thread main/tasks/stratum_task.c
Comment thread main/work_queue.c
Comment on lines +50 to +68
bool queue_dequeue_if_full(work_queue *queue, void **work)
{
bool dequeued = false;

pthread_mutex_lock(&queue->lock);

if (queue->count == QUEUE_SIZE)
{
*work = queue->buffer[queue->head];
queue->head = (queue->head + 1) % QUEUE_SIZE;
queue->count--;
pthread_cond_signal(&queue->not_full);
dequeued = true;
}

pthread_mutex_unlock(&queue->lock);

return dequeued;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing NULL check for work parameter.

If a caller passes NULL for the work out-parameter, dereferencing *work on line 58 will crash. Add a guard or document that work must not be NULL.

🛡️ Proposed fix
 bool queue_dequeue_if_full(work_queue *queue, void **work)
 {
+    if (queue == NULL || work == NULL) {
+        return false;
+    }
+
     bool dequeued = false;
 
     pthread_mutex_lock(&queue->lock);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool queue_dequeue_if_full(work_queue *queue, void **work)
{
bool dequeued = false;
pthread_mutex_lock(&queue->lock);
if (queue->count == QUEUE_SIZE)
{
*work = queue->buffer[queue->head];
queue->head = (queue->head + 1) % QUEUE_SIZE;
queue->count--;
pthread_cond_signal(&queue->not_full);
dequeued = true;
}
pthread_mutex_unlock(&queue->lock);
return dequeued;
}
bool queue_dequeue_if_full(work_queue *queue, void **work)
{
if (queue == NULL || work == NULL) {
return false;
}
bool dequeued = false;
pthread_mutex_lock(&queue->lock);
if (queue->count == QUEUE_SIZE)
{
*work = queue->buffer[queue->head];
queue->head = (queue->head + 1) % QUEUE_SIZE;
queue->count--;
pthread_cond_signal(&queue->not_full);
dequeued = true;
}
pthread_mutex_unlock(&queue->lock);
return dequeued;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/work_queue.c` around lines 50 - 68, The function queue_dequeue_if_full
lacks a NULL check for the out-parameter work and will dereference *work causing
a crash if NULL is passed; add a guard at the start of queue_dequeue_if_full
(e.g., if (work == NULL) { return false; } or assert) before locking or before
any dereference, then proceed with the existing logic that reads from
queue->buffer[queue->head], updates queue->head and queue->count, signals
queue->not_full and returns dequeued; ensure you return false when work is NULL
to preserve behavior and avoid modifying the queue.

@WantClue WantClue merged commit 68494f1 into main May 3, 2026
2 of 4 checks passed
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.

1 participant