Skip to content

Comments

Fix NullReferenceException in Web3.BlockHash() and AwaitWsRpcConnection()#261

Open
nikolaysamoil0ff wants to merge 3 commits intomagicblock-labs:mainfrom
nikolaysamoil0ff:patch-1
Open

Fix NullReferenceException in Web3.BlockHash() and AwaitWsRpcConnection()#261
nikolaysamoil0ff wants to merge 3 commits intomagicblock-labs:mainfrom
nikolaysamoil0ff:patch-1

Conversation

@nikolaysamoil0ff
Copy link

@nikolaysamoil0ff nikolaysamoil0ff commented Feb 23, 2026

Problem

Web3.BlockHash() could return null instead of a Task, causing NullReferenceException when awaited.

WalletBase.AwaitWsRpcConnection() could access _webSocketConnection.Task while _webSocketConnection is null, causing NullReferenceException.

Solution

Web3.BlockHash() now returns a completed Task<string?> with null result if Instance is not initialized.

Added explicit null check in AwaitWsRpcConnection() to throw a clear InvalidOperationException if _webSocketConnection is not initialized.

Before & After Screenshots

Insert screenshots of example code output

BEFORE:
image
image

AFTER:
image
image

Other changes (e.g. bug fixes, small refactors)

N/A

Deploy Notes

Notes regarding deployment of the contained body of work. These should note any
new dependencies, new scripts, etc.

New scripts:

  • script : script details

New dependencies:

  • dependency : dependency details

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error handling for WebSocket connection initialization with clear error messaging.
  • Changes

    • Updated BlockHash method to properly handle cases where block hash is unavailable.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Walkthrough

The changes add null-handling safeguards across two runtime files: a guard clause in WalletBase that throws when WebSocket connection is uninitialized, and a nullable return type update in Web3's BlockHash method with corresponding async implementation adjustments.

Changes

Cohort / File(s) Summary
WebSocket Connection Guard
Runtime/codebase/WalletBase.cs
Added null check in AwaitWsRpcConnection that throws InvalidOperationException when _webSocketConnection is null, ensuring explicit error signaling for uninitialized WebSocket state.
Nullable Return Type
Runtime/codebase/Web3.cs
Updated BlockHash method signature from Task<string> to Task<string?> and adjusted null-return branch to use Task.FromResult<string?>(null) for proper asynchronous semantics.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main changes: fixing NullReferenceException in two specific methods (Web3.BlockHash() and AwaitWsRpcConnection()).
Description check ✅ Passed The description includes all required sections: Problem (clear explanation of two issues), Solution (specific fixes for each), Before & After Screenshots (four code images provided), and deploy notes placeholder.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

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

Copy link

@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: 3

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cedf547 and eeb1e05.

📒 Files selected for processing (2)
  • Runtime/codebase/WalletBase.cs
  • Runtime/codebase/Web3.cs
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Runtime/codebase/WalletBase.cs`:
- Around line 392-395: The method AwaitWsRpcConnection currently throws
synchronously when _webSocketConnection is null; change it to return a faulted
Task instead so callers observe the error via TAP. In AwaitWsRpcConnection,
replace the synchronous throw with returning
Task.FromException<Task>(_webSocketConnection == null ? new
InvalidOperationException("WebSocket connection is not initialized.") : /* keep
existing return */) — more specifically return Task.FromException(new
InvalidOperationException("WebSocket connection is not initialized.")) when
_webSocketConnection is null, otherwise continue to return
_webSocketConnection.Task; this keeps AwaitWsRpcConnection non-async while
producing a faulted Task for uniform exception propagation.

In `@Runtime/codebase/Web3.cs`:
- Around line 319-321: The current static helper checks only Instance != null
but still dereferences Instance.WalletBase when calling
Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds), which can
cause an NRE if WalletBase is null; update the guard to ensure WalletBase is
non-null (e.g., Instance != null && Instance.WalletBase != null or using a
null-conditional) and return Task.FromResult<string?>(null) when WalletBase is
null so the call to GetBlockHash is only invoked on a valid WalletBase instance.
- Line 315: The public API method BlockHash was changed from Task<string> to
Task<string?> to reflect that WalletBase.GetBlockHash actually returns null in
some cases (when Instance is null or blockhash is null), which is
source-breaking for nullable-aware consumers; update the declaration and any
related usages to return Task<string?> and ensure callers handle a possible null
result, and audit WalletBase.GetBlockHash, the BlockHash method, and any call
sites that use Instance or check blockhash to consistently propagate or handle
the nullable string return.

Comment on lines +392 to 395
if (_webSocketConnection == null)
throw new InvalidOperationException("WebSocket connection is not initialized.");

return _webSocketConnection.Task;
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optional: Return a faulted Task instead of throwing synchronously for uniform TAP exception propagation.

AwaitWsRpcConnection() is a non-async Task-returning method. A synchronous throw is observable differently from a faulted Task when callers don't immediately await the return value (e.g., Task.WhenAll, .ContinueWith, or storing the Task before awaiting). In cases like parallel processing (Task.WhenAll), the difference between throwing directly and returning a failed task becomes important.

♻️ Proposed refactor
-            if (_webSocketConnection == null)
-                throw new InvalidOperationException("WebSocket connection is not initialized.");
-            
-            return _webSocketConnection.Task;
+            return _webSocketConnection?.Task
+                ?? Task.FromException(new InvalidOperationException("WebSocket connection is not initialized."));
📝 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
if (_webSocketConnection == null)
throw new InvalidOperationException("WebSocket connection is not initialized.");
return _webSocketConnection.Task;
return _webSocketConnection?.Task
?? Task.FromException(new InvalidOperationException("WebSocket connection is not initialized."));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Runtime/codebase/WalletBase.cs` around lines 392 - 395, The method
AwaitWsRpcConnection currently throws synchronously when _webSocketConnection is
null; change it to return a faulted Task instead so callers observe the error
via TAP. In AwaitWsRpcConnection, replace the synchronous throw with returning
Task.FromException<Task>(_webSocketConnection == null ? new
InvalidOperationException("WebSocket connection is not initialized.") : /* keep
existing return */) — more specifically return Task.FromException(new
InvalidOperationException("WebSocket connection is not initialized.")) when
_webSocketConnection is null, otherwise continue to return
_webSocketConnection.Task; this keeps AwaitWsRpcConnection non-async while
producing a faulted Task for uniform exception propagation.

/// https://docs.solana.com/developing/transaction_confirmation#how-does-transaction-expiration-work</param>
/// <returns></returns>
public static Task<string> BlockHash(
public static Task<string?> BlockHash(
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for nullable enable in csproj and Directory.Build.props
rg -n "Nullable" --include="*.csproj" --include="*.props" --include="Directory.Build.*" -i

# Check for file-level nullable enable directives in C# files
rg -n "#nullable enable" --type=cs

# Also check the actual BlockHash method and its usages
echo "=== BlockHash method definition ==="
rg -n "BlockHash" --type=cs -A 2 -B 2

# Check if there are any callers of BlockHash
echo "=== BlockHash usages/callers ==="
rg -n "BlockHash\(" --type=cs

Repository: magicblock-labs/Solana.Unity-SDK

Length of output: 21917


🏁 Script executed:

#!/bin/bash

# Find and inspect .csproj files for Nullable settings
echo "=== Finding .csproj files ==="
find . -name "*.csproj" -type f | head -5

# Check the main csproj for Nullable setting
echo -e "\n=== Checking for Nullable in csproj files ==="
find . -name "*.csproj" -exec grep -l "Nullable" {} \;

# Check Web3.cs for file-level nullable directives and full method signature
echo -e "\n=== Web3.cs nullable directives and BlockHash method ==="
head -20 Runtime/codebase/Web3.cs
tail -n +310 Runtime/codebase/Web3.cs | head -20

# Check WalletBase.cs GetBlockHash implementation fully
echo -e "\n=== WalletBase GetBlockHash implementation ==="
sed -n '287,315p' Runtime/codebase/WalletBase.cs

Repository: magicblock-labs/Solana.Unity-SDK

Length of output: 3002


API change is breaking for external SDK consumers, but semantically necessary.

Changing Task<string> to Task<string?> is source-breaking for external callers with #nullable enable. However, this project itself doesn't enable nullable reference types, and the underlying implementation of WalletBase.GetBlockHash already returns null in multiple places despite its non-nullable return type declaration. This change makes the API contract accurately reflect the actual nullability behavior (when Instance is null or when blockhash is null). While external SDK consumers will need to adjust their type handling, this is a necessary correction rather than an unintended breaking change.

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

In `@Runtime/codebase/Web3.cs` at line 315, The public API method BlockHash was
changed from Task<string> to Task<string?> to reflect that
WalletBase.GetBlockHash actually returns null in some cases (when Instance is
null or blockhash is null), which is source-breaking for nullable-aware
consumers; update the declaration and any related usages to return Task<string?>
and ensure callers handle a possible null result, and audit
WalletBase.GetBlockHash, the BlockHash method, and any call sites that use
Instance or check blockhash to consistently propagate or handle the nullable
string return.

Comment on lines +319 to +321
Instance != null
? Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds)
: Task.FromResult<string?>(null);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Instance.WalletBase is not null-guarded — NRE still possible after logout or before wallet initialization.

The guard on line 319 only checks Instance != null. When Instance exists but Instance.WalletBase is null (e.g., after Logout() sets WalletBase = null, or before any wallet is set), line 320 dereferences a null reference and throws NullReferenceException. All other static helpers in this class (Rpc, WsRpc, Account) guard against both nulls — this one should too.

🐛 Proposed fix
-            Instance != null 
-                ? Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds) 
-                : Task.FromResult<string?>(null);
+            Instance != null && Instance.WalletBase != null
+                ? Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds)
+                : Task.FromResult<string?>(null);
📝 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
Instance != null
? Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds)
: Task.FromResult<string?>(null);
Instance != null && Instance.WalletBase != null
? Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds)
: Task.FromResult<string?>(null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Runtime/codebase/Web3.cs` around lines 319 - 321, The current static helper
checks only Instance != null but still dereferences Instance.WalletBase when
calling Instance.WalletBase.GetBlockHash(commitment, useCache, maxSeconds),
which can cause an NRE if WalletBase is null; update the guard to ensure
WalletBase is non-null (e.g., Instance != null && Instance.WalletBase != null or
using a null-conditional) and return Task.FromResult<string?>(null) when
WalletBase is null so the call to GetBlockHash is only invoked on a valid
WalletBase instance.

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