Skip to content

Comments

fix: handle mining.extranonce.subscribe and prevent nil pointer crash#83

Merged
abs2023 merged 1 commit intodevfrom
fix/extranonce-subscribe-crash
Feb 10, 2026
Merged

fix: handle mining.extranonce.subscribe and prevent nil pointer crash#83
abs2023 merged 1 commit intodevfrom
fix/extranonce-subscribe-crash

Conversation

@abs2023
Copy link
Contributor

@abs2023 abs2023 commented Feb 10, 2026

Summary

Fixes crash loop caused by miners sending unexpected protocol messages during handshake phase before destination connection is initialized.

Root Causes (2 issues found)

Issue #1: Nil Pointer in logWithContext()

New miners added to seller node on 2026-02-10 send mining.extranonce.subscribe Stratum extension message during initial handshake. This legitimate protocol message wasn't explicitly handled, causing it to fall through to the default case.

The default case attempted to log a warning, which called logWithContext(). This logging function accessed p.dest.conn.conn.LocalAddr() which was nil during early handshake, triggering panic at proxy.go:453.

Issue #2: Nil Pointer in dest.Write()

After fixing the logging, a second nil pointer issue was discovered: when unknown/unexpected messages arrive before the destination is initialized (e.g., eth_submitLogin from Ethereum miners connecting to Bitcoin proxy), the code attempts to forward the message via p.proxy.dest.Write() which is nil, causing panic at conn_dest.go:139 via handler_first_connect.go:83.

Changes Made

1. Defensive Logging (proxy.go) - Commit 3d2a337

Made logWithContext() nil-safe by checking all pointer levels before accessing:

  • Checks if p.dest is nil
  • Checks if p.dest.conn is nil
  • Checks if p.dest.conn.conn is nil
  • Returns "not-connected" or "not-initialized" instead of panicking

2. Handle mining.extranonce.subscribe (handler_first_connect.go) - Commit 3d2a337

Added explicit case for MiningExtranonceSubscribe messages:

  • Logs at debug level for visibility
  • Forwards message transparently to pool if dest is initialized
  • Prevents falling through to unknown message handler

3. Nil Checks Before Writing (handler_first_connect.go) - Commit 94aba98

Added defensive nil checks before writing to dest:

  • Both MiningExtranonceSubscribe case and default case now check if p.proxy.dest != nil
  • Messages arriving before destination initialization are safely dropped
  • Prevents panic when forwarding unexpected protocol messages

Impact

Testing

  • Code compiles successfully
  • Crash pattern analysis confirms both fixes address exact panic locations
  • First fix deployed to production, revealed second issue
  • Second fix addresses newly discovered crash pattern

CloudWatch Evidence

First crash pattern (fixed in 3d2a337):

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x110 pc=0x90b25f]
at proxy.go:453 in logWithContext()

Preceded by unknown message logs showing mining.extranonce.subscribe.

Second crash pattern (fixed in 94aba98):

panic: runtime error: invalid memory address or nil pointer dereference  
[signal SIGSEGV: segmentation violation code=0x1 addr=0x110 pc=0x8feae6]
at conn_dest.go:139 via handler_first_connect.go:83

Triggered by eth_submitLogin message with our logging showing:
"DstAddr":"not-initialized","DstPort":"not-connected"

Fixes crash loop caused by new miners sending mining.extranonce.subscribe
messages during handshake phase.

Changes:
1. Made logWithContext() defensive against nil destination connections
   - Prevents panic when logging before connection fully established
   - Returns "not-connected" instead of crashing on nil pointer dereference

2. Added explicit handling for MiningExtranonceSubscribe messages
   - Properly forwards extranonce subscription requests to pool
   - Logs at debug level for visibility
   - Prevents falling through to unknown message handler

Root Cause:
New miners added to seller node send mining.extranonce.subscribe during
initial handshake. This legitimate Stratum extension message wasn't
explicitly handled, causing it to fall through to default case. The
logging in default case attempted to access p.dest.conn.conn.LocalAddr()
which was nil during early handshake, triggering panic and container
restart every 5-6 minutes.

Impact:
- Resolves continuous crash loop since 2026-02-10 13:16 ET
- Enables modern miners with extranonce support to connect properly
- Future-proofs logging against similar edge cases

Co-authored-by: Cursor <cursoragent@cursor.com>
@abs2023 abs2023 requested a review from shev-titan February 10, 2026 20:20
@abs2023 abs2023 merged commit 04c4d0a into dev Feb 10, 2026
11 checks passed
abs2023 added a commit that referenced this pull request Feb 10, 2026
## Summary
Fixes secondary crash discovered after PR #83 deployment. Adds defensive
nil checks before attempting to write to destination during handshake
phase.

## Root Cause
After deploying PR #83 (which fixed the logging crash), a second nil
pointer issue was discovered at 2026-02-10 20:56 UTC:

When miners send unexpected protocol messages before the destination
connection is initialized (e.g., `eth_submitLogin` from Ethereum miners
connecting to Bitcoin proxy), the code attempts to forward the message
via `p.proxy.dest.Write()`. However, `p.proxy.dest` is nil during early
handshake, causing panic at `conn_dest.go:139` via
`handler_first_connect.go:83`.

## Changes Made
Added defensive nil checks in `handler_first_connect.go` before writing
to dest:

1. **MiningExtranonceSubscribe case:**
   - Check if `p.proxy.dest != nil` before forwarding
   - Return nil, nil if dest not ready (safe drop)

2. **Default case (unknown messages):**
   - Check if `p.proxy.dest != nil` before forwarding  
   - Return nil, nil if dest not ready (safe drop)
   - Updated comment to clarify behavior

## Impact
- ✅ Resolves secondary crash pattern at conn_dest.go:139
- ✅ Handles protocol mismatches gracefully (e.g., Ethereum miners on
Bitcoin proxy)
- ✅ Complements PR #83 to fully stabilize handshake phase
- ✅ No performance impact (just pointer checks)

## Evidence
**Crash pattern:**
```
panic: runtime error: invalid memory address or nil pointer dereference  
[signal SIGSEGV: segmentation violation code=0x1 addr=0x110 pc=0x8feae6]
at conn_dest.go:139 via handler_first_connect.go:83
```

**Trigger log (showing PR #83 logging fix working):**
```json
{"level":"warn","logger":"PRX","msg":"unknown handshake message from source: {\"id\":2,\"method\":\"eth_submitLogin\"...}",
"SrcAddr":"188.166.37.58:47284","DstAddr":"not-initialized","DstPort":"not-connected"}
```

The logging successfully showed "not-initialized" and "not-connected"
(PR #83 fix working), but then crashed trying to forward the message.

## Dependencies
- Requires PR #83 to be merged first (already done)
- This is a follow-up fix discovered during production monitoring


Made with [Cursor](https://cursor.com)
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.

2 participants