Skip to content

feat: implement JSON-RPC 2.0 server using aiohttp#98

Open
SIDDHANTCOOKIE wants to merge 3 commits into
StabilityNexus:mainfrom
SIDDHANTCOOKIE:feat/json-rpc
Open

feat: implement JSON-RPC 2.0 server using aiohttp#98
SIDDHANTCOOKIE wants to merge 3 commits into
StabilityNexus:mainfrom
SIDDHANTCOOKIE:feat/json-rpc

Conversation

@SIDDHANTCOOKIE

@SIDDHANTCOOKIE SIDDHANTCOOKIE commented Jun 14, 2026

Copy link
Copy Markdown
Member

Addressed Issues:

  • Created minichain/rpc.py configuring an asynchronous HTTP server powered by aiohttp.
  • Implemented standard endpoints mc_blockNumber, mc_getBlockByNumber, mc_getBalance, and mc_sendTransaction with proper JSON-RPC error codes.
  • Wired the JSONRPCServer into the main asyncio event loop in main.py, bound dynamically to port 8545 (or offset by base P2P port).
  • Integrated mc_sendTransaction deeply into the Mempool queue, automatically broadcasting valid payloads to the P2P network.
  • Added 3 comprehensive async integration tests in tests/test_rpc.py enforcing correct error handling and JSON parsing.

Screenshots/Recordings:

TODO: If applicable, add screenshots or recordings that demonstrate the interface before and after the changes.

Additional Notes:

AI Usage Disclosure:

We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.

Check one of the checkboxes below:

  • This PR does not contain AI-generated code at all.
  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: TODO

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with the project maintainers there
  • I have read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without review otherwise.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added JSON-RPC 2.0 HTTP endpoint for querying blockchain state, retrieving block information, checking balances, and submitting transactions.
    • Implemented automatic chain synchronization and reorganization—the node now responds to heavier competing chains from peers and updates its state accordingly.
    • Enhanced P2P protocol with chain request/response message types for improved peer synchronization.
  • Tests

    • Added chain reorganization scenario tests.
    • Added RPC endpoint integration tests.

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds chain reorganization support to Blockchain (work comparison, state replay, orphan collection), P2P chain_request/chain_response message types to P2PNetwork, a new JSONRPCServer backed by aiohttp, a refactored Mempool using a sorted list, State snapshot/restore primitives, wired together in main.py with tests.

Changes

Chain Reorg, JSON-RPC Server, P2P Sync, and Mempool Refactor

Layer / File(s) Summary
State snapshot/restore primitives
minichain/state.py
Adds State.snapshot() (deep-copy of accounts) and State.restore(snapshot_data) (deep-copy replacement) as rollback primitives consumed by the reorg flow.
Blockchain genesis snapshot, total work, and resolve_conflicts
minichain/chain.py
Blockchain.__init__ saves _genesis_state_snapshot after genesis allocation; get_total_work sums 2**difficulty across a chain list; resolve_conflicts implements work-based reorg with per-block validation, state replay from genesis snapshot, and orphaned-transaction collection.
P2P chain_request/chain_response protocol extension
minichain/p2p.py
SUPPORTED_MESSAGE_TYPES gains chain_request and chain_response; new private validators enforce payload shapes; broadcast_chain_request() and send_chain_response(blocks_dicts, writer) are added to P2PNetwork.
Mempool sorted-list refactor
minichain/mempool.py
Replaces the nested sender/nonce dict pool with a single self._list; rewrites add_transaction for ordered insertion and replacement by timestamp; simplifies get_transactions_for_block to a list prefix and remove_transactions to a filter by (sender, nonce).
JSONRPCServer implementation
minichain/rpc.py
New file implementing an aiohttp JSON-RPC 2.0 HTTP server at POST / with mc_blockNumber, mc_getBlockByNumber, mc_getBalance, mc_sendTransaction, batch request support, and standard JSON-RPC error codes.
main.py handler and RPC wiring
main.py
make_network_handler gains a network parameter and handles chain_request/chain_response for sync and reorg with orphan re-queuing; run_node constructs and starts JSONRPCServer as a background task and cancels it on shutdown.
Reorg and RPC integration tests
tests/test_reorg.py, tests/test_rpc.py
test_reorg.py covers heavier-chain acceptance, orphan collection on diverging history, and lighter-chain rejection via resolve_conflicts; test_rpc.py integration-tests mc_blockNumber, mc_getBlockByNumber, and unknown-method error against a live aiohttp server.

Sequence Diagram(s)

sequenceDiagram
  participant PeerNode
  participant P2PNetwork
  participant make_network_handler
  participant Blockchain
  participant Mempool
  participant JSONRPCClient

  PeerNode->>P2PNetwork: block message (ahead of local tip)
  P2PNetwork->>make_network_handler: dispatch block
  make_network_handler->>P2PNetwork: broadcast_chain_request()
  P2PNetwork->>PeerNode: chain_request message

  PeerNode->>P2PNetwork: chain_response{blocks:[...]}
  P2PNetwork->>make_network_handler: dispatch chain_response
  make_network_handler->>Blockchain: resolve_conflicts(new_chain_list)
  Blockchain-->>make_network_handler: (True, orphaned_txs)
  make_network_handler->>Mempool: add_transaction(orphan) for each orphan

  JSONRPCClient->>JSONRPCServer: POST / mc_sendTransaction
  JSONRPCServer->>Mempool: add_transaction(tx)
  JSONRPCServer->>P2PNetwork: broadcast tx
  JSONRPCServer-->>JSONRPCClient: JSON-RPC result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • StabilityNexus/MiniChain#70: Previously refactored minichain/mempool.py to a nested sender -> nonce -> tx structure, which this PR replaces with a sorted list.
  • StabilityNexus/MiniChain#91: Introduced receipt/receipt_root validation in minichain/chain.py that resolve_conflicts now verifies during block replay.
  • StabilityNexus/MiniChain#19: Refactored P2P handler registration in main.py, directly preceding the updated make_network_handler(chain, mempool, network) signature in this PR.

Suggested labels

Python Lang

Suggested reviewers

  • Zahnentferner

🐇 A bunny hops through blocks in a chain,
Resolving conflicts — no orphan in vain!
The mempool's a list, tidy and bright,
RPC endpoints glow in the night.
With snapshot and restore, state's safe from harm —
MiniChain grows with hop, skip, and charm! 🌟

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically summarizes the main addition: implementing a JSON-RPC 2.0 server using aiohttp, which is the primary focus of this pull request.
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 unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@main.py`:
- Around line 169-173: The chain_request handler in main.py (lines 169-173)
currently broadcasts the chain response to all connected peers via
_broadcast_raw, which is wasteful and creates an amplification attack vector.
Instead of broadcasting, the handler should send the chain response only to the
peer that requested it. Modify the handler to access the writer object for the
requesting peer (either by having it passed through the callback or by
maintaining a peer address to writer mapping in the network module), and then
call a targeted send method (such as send_chain_response) that writes directly
to that specific peer's connection rather than using _broadcast_raw. This
ensures the response reaches only the requester.
- Around line 467-470: The rpc_task.cancel() call schedules cancellation but
does not await its completion, allowing network.stop() to execute while the RPC
server is still shutting down and causing race conditions. Replace the
non-awaited rpc_task.cancel() with a proper awaited cancellation that waits for
the task to complete before proceeding. This typically involves wrapping the
cancellation in a try-except block to handle CancelledError, then awaiting the
task completion. Additionally, consider implementing a proper rpc_server.stop()
method in minichain/rpc.py that cleanly shuts down aiohttp resources before
network.stop() is called.
- Around line 438-441: The RPC port calculation using `8545 + (port - 9000)` can
produce invalid port numbers when the P2P port argument is less than 9000,
resulting in negative or unexpectedly low port values. Fix this by adding
validation to ensure the calculated rpc_port value falls within the valid port
range (1-65535), either by clamping the result to a minimum valid port or by
implementing a separate --rpc-port command-line argument instead of deriving it
from the P2P port. At minimum, clamp rpc_port to ensure it stays within valid
bounds before passing it to rpc_server.start().

In `@minichain/chain.py`:
- Around line 233-234: The assignment of new_chain_list to self.chain at the
chain update location creates an alias that exposes the blockchain to external
mutations. Instead of directly assigning new_chain_list to self.chain, create a
defensive copy of the incoming list (for example, using list slicing or the copy
module) to ensure that any future modifications to new_chain_list by the caller
will not corrupt the internal blockchain state.
- Around line 188-190: The variables state_snapshot and original_chain are
created as defensive copies but are never referenced anywhere in the code.
Remove the two lines that create these snapshots (the assignments to
state_snapshot and original_chain) since they serve no purpose when temp_state
is a fresh instance and self.state/self.chain are only reassigned on the success
path.

In `@minichain/mempool.py`:
- Around line 48-51: Replace the nested `else: if` structure with `elif` to
reduce indentation nesting in the mempool full check logic. Specifically,
convert the `else:` statement followed by `if len(self._list) >= self.max_size:`
into a single `elif len(self._list) >= self.max_size:` block, keeping the
logger.warning and return False statements at the appropriate indentation level.
- Line 53: The line `i_min = min(i_min, i_max)` silently masks a broken
invariant in the per-sender nonce ordering of `self._list`. When `i_min >
i_max`, this indicates the invariant has already been violated, but clamping the
value hides this corruption and allows the code to continue in an invalid state.
Instead of silently clamping, add a check before this line to detect when `i_min
> i_max` and either raise an assertion error or log a warning to fail fast and
make the invariant violation visible during debugging. This ensures invariant
violations are caught and reported rather than silently masked.

In `@minichain/rpc.py`:
- Around line 76-80: The asyncio.create_task() call for
self.network.broadcast_transaction(tx) creates a fire-and-forget task without
storing a reference or handling potential exceptions, which means broadcast
failures will silently fail in the background without being tracked. Store a
reference to the task (for example, in an instance variable like a set of
pending tasks) or add a done callback to the task to capture and handle any
exceptions that occur during the broadcast operation. This will ensure broadcast
failures are properly tracked and logged rather than being silently swallowed by
the asyncio event loop.
- Around line 17-22: The JSON-RPC server lacks proper graceful shutdown, causing
potential resource leaks. At minichain/rpc.py lines 17-22, in the start()
method, store the AppRunner instance created as self._runner instead of using a
local variable, then add a new async stop() method to the JSONRPCServer class
that calls await self._runner.cleanup() to properly clean up aiohttp resources.
At main.py lines 467-470, replace the rpc_task.cancel() call with proper
shutdown by awaiting the task cancellation and then calling await
rpc_server.stop() before invoking network.stop() to ensure the RPC server shuts
down gracefully before the network is stopped.

In `@tests/test_reorg.py`:
- Around line 10-12: Remove the sys.path manipulation block at the start of the
test_reorg.py file (the lines containing import sys, import os, and
sys.path.insert). These manual path adjustments are unnecessary when tests run
from the project root with pytest, which will properly discover modules from the
standard project structure. If sys and os are not used elsewhere in the file,
remove those import statements as well.

In `@tests/test_rpc.py`:
- Line 41: In the unpacking assignment where rpc_server is destructured, prefix
the unused variables with an underscore to follow Python conventions. Keep only
the `port` variable without an underscore since it is actually used, and rename
`server`, `chain`, and `mempool` to `_server`, `_chain`, and `_mempool`
respectively.
- Line 29: In the tuple unpacking statement at the rpc_server assignment, only
the `port` variable is used in the subsequent code. Prefix the unused variables
(`server`, `chain`, and `mempool`) with an underscore (e.g., `_server`,
`_chain`, `_mempool`) to explicitly signal that these variables are
intentionally unused, which will satisfy linter requirements and improve code
clarity. Keep `port` without the underscore prefix since it is actively used.
- Line 53: In the unpacking assignment where `server, port, chain, mempool =
rpc_server`, only the `port` variable is used in the function. Prefix the unused
variables `server`, `chain`, and `mempool` with an underscore to follow Python
convention for unused variables. Change the line to `_server, port, _chain,
_mempool = rpc_server`.
- Around line 9-11: The anyio_backend fixture and `@pytest.mark.anyio` decorator
used in the test file require the pytest-anyio package, but this dependency is
not currently included in the project's dependencies file. Add pytest-anyio to
the project's dependency list (requirements.txt or equivalent dependency
management file) to ensure the test suite has access to the necessary
pytest-anyio plugin.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a0100f89-ca57-4136-95e0-c35fd05e30c8

📥 Commits

Reviewing files that changed from the base of the PR and between eb8e75d and 398d1fb.

📒 Files selected for processing (8)
  • main.py
  • minichain/chain.py
  • minichain/mempool.py
  • minichain/p2p.py
  • minichain/rpc.py
  • minichain/state.py
  • tests/test_reorg.py
  • tests/test_rpc.py

Comment thread main.py
Comment on lines +169 to +173
elif msg_type == "chain_request":
logger.info("📡 Peer requested chain sync. Broadcasting our chain...")
blocks_dicts = [b.to_dict() for b in chain.chain]
payload = {"type": "chain_response", "data": {"blocks": blocks_dicts}}
asyncio.create_task(network._broadcast_raw(payload))

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 | 🟠 Major | 🏗️ Heavy lift

Chain response broadcasts to all peers instead of just the requester — amplification risk.

When handling chain_request, the code broadcasts the entire chain to all connected peers via _broadcast_raw, not just the peer who requested it. This is:

  1. Wasteful — peers who didn't request the chain receive it anyway
  2. Potentially exploitable — a malicious peer could trigger large broadcasts to all other peers (amplification attack)

The root cause is that the handler only receives _peer_addr (a string), not the writer object needed to call send_chain_response. Consider passing the writer through the handler callback or storing a peer address → writer mapping.

🧰 Tools
🪛 Ruff (0.15.15)

[warning] 173-173: Store a reference to the return value of asyncio.create_task

(RUF006)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.py` around lines 169 - 173, The chain_request handler in main.py (lines
169-173) currently broadcasts the chain response to all connected peers via
_broadcast_raw, which is wasteful and creates an amplification attack vector.
Instead of broadcasting, the handler should send the chain response only to the
peer that requested it. Modify the handler to access the writer object for the
requesting peer (either by having it passed through the callback or by
maintaining a peer address to writer mapping in the network module), and then
call a targeted send method (such as send_chain_response) that writes directly
to that specific peer's connection rather than using _broadcast_raw. This
ensures the response reaches only the requester.

Comment thread main.py
Comment on lines +438 to +441

# Start RPC server on a port correlated to the node port (e.g. 8545 if P2P is 9000)
rpc_port = 8545 + (port - 9000)
rpc_task = asyncio.create_task(rpc_server.start(host="127.0.0.1", port=rpc_port))

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

RPC port calculation can produce invalid or unexpected ports.

The formula 8545 + (port - 9000) assumes P2P port is ≥9000. If a user runs with --port 100, the RPC port becomes -355, which will fail. Even valid-but-low ports like --port 8000 yield 7545, which may not match user expectations.

Consider adding a separate --rpc-port argument or at minimum clamping the port to a valid range.

Proposed fix with validation
     # Start RPC server on a port correlated to the node port (e.g. 8545 if P2P is 9000)
     rpc_port = 8545 + (port - 9000)
+    if rpc_port < 1 or rpc_port > 65535:
+        rpc_port = 8545  # fallback to default
+        logger.warning("Computed RPC port out of range, using default %d", rpc_port)
     rpc_task = asyncio.create_task(rpc_server.start(host="127.0.0.1", port=rpc_port))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.py` around lines 438 - 441, The RPC port calculation using `8545 + (port
- 9000)` can produce invalid port numbers when the P2P port argument is less
than 9000, resulting in negative or unexpectedly low port values. Fix this by
adding validation to ensure the calculated rpc_port value falls within the valid
port range (1-65535), either by clamping the result to a minimum valid port or
by implementing a separate --rpc-port command-line argument instead of deriving
it from the P2P port. At minimum, clamp rpc_port to ensure it stays within valid
bounds before passing it to rpc_server.start().

Comment thread main.py
Comment on lines +467 to 470

if rpc_task:
rpc_task.cancel()
await network.stop()

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

RPC task cancellation is not awaited — incomplete cleanup.

Calling rpc_task.cancel() schedules cancellation but doesn't wait for it to complete. The network.stop() call may execute while the RPC server is still running, leading to race conditions during shutdown.

Proposed fix
         if rpc_task:
             rpc_task.cancel()
+            try:
+                await rpc_task
+            except asyncio.CancelledError:
+                pass
         await network.stop()

Ideally, combine this with a proper rpc_server.stop() method that cleans up aiohttp resources (see related comment in minichain/rpc.py).

📝 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 rpc_task:
rpc_task.cancel()
await network.stop()
if rpc_task:
rpc_task.cancel()
try:
await rpc_task
except asyncio.CancelledError:
pass
await network.stop()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.py` around lines 467 - 470, The rpc_task.cancel() call schedules
cancellation but does not await its completion, allowing network.stop() to
execute while the RPC server is still shutting down and causing race conditions.
Replace the non-awaited rpc_task.cancel() with a proper awaited cancellation
that waits for the task to complete before proceeding. This typically involves
wrapping the cancellation in a try-except block to handle CancelledError, then
awaiting the task completion. Additionally, consider implementing a proper
rpc_server.stop() method in minichain/rpc.py that cleanly shuts down aiohttp
resources before network.stop() is called.

Comment thread minichain/chain.py
Comment on lines +188 to +190
# 2. Snapshot current state and chain in case reorg fails validation
state_snapshot = self.state.snapshot()
original_chain = list(self.chain)

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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Unused snapshots can be removed.

state_snapshot and original_chain are captured but never used. Since temp_state is a fresh instance and self.state/self.chain are only reassigned on the success path (lines 233-234), these defensive copies serve no purpose.

🧹 Remove dead code
             logger.info("Incoming chain is heavier (%s > %s). Attempting reorg...", new_work, current_work)

-            # 2. Snapshot current state and chain in case reorg fails validation
-            state_snapshot = self.state.snapshot()
-            original_chain = list(self.chain)
-
-            # 3. Rebuild state entirely from genesis using the new chain
+            # 2. Rebuild state entirely from genesis using the new chain
             temp_state = State()
             temp_state.restore(self._genesis_state_snapshot)
📝 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
# 2. Snapshot current state and chain in case reorg fails validation
state_snapshot = self.state.snapshot()
original_chain = list(self.chain)
# 2. Rebuild state entirely from genesis using the new chain
temp_state = State()
temp_state.restore(self._genesis_state_snapshot)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@minichain/chain.py` around lines 188 - 190, The variables state_snapshot and
original_chain are created as defensive copies but are never referenced anywhere
in the code. Remove the two lines that create these snapshots (the assignments
to state_snapshot and original_chain) since they serve no purpose when
temp_state is a fresh instance and self.state/self.chain are only reassigned on
the success path.

Comment thread minichain/chain.py
Comment on lines +233 to +234
self.chain = new_chain_list
self.state = temp_state

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

Consider copying the incoming chain to avoid aliasing.

Directly assigning new_chain_list to self.chain creates a shared reference. If the caller retains and later mutates new_chain_list, it would corrupt the blockchain state. A defensive copy is cheap and eliminates this risk.

🛡️ Proposed fix
-            self.chain = new_chain_list
+            self.chain = list(new_chain_list)
             self.state = temp_state
📝 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
self.chain = new_chain_list
self.state = temp_state
self.chain = list(new_chain_list)
self.state = temp_state
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@minichain/chain.py` around lines 233 - 234, The assignment of new_chain_list
to self.chain at the chain update location creates an alias that exposes the
blockchain to external mutations. Instead of directly assigning new_chain_list
to self.chain, create a defensive copy of the incoming list (for example, using
list slicing or the copy module) to ensure that any future modifications to
new_chain_list by the caller will not corrupt the internal blockchain state.

Comment thread tests/test_reorg.py
Comment on lines +10 to +12
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Remove sys.path manipulation; rely on proper project structure.

Manual path manipulation is unnecessary when tests run from the project root. Pytest will discover main.py if the project follows standard Python package structure.

♻️ Proposed fix
-import sys
-import os
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
 from main import mine_and_process_block
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_reorg.py` around lines 10 - 12, Remove the sys.path manipulation
block at the start of the test_reorg.py file (the lines containing import sys,
import os, and sys.path.insert). These manual path adjustments are unnecessary
when tests run from the project root with pytest, which will properly discover
modules from the standard project structure. If sys and os are not used
elsewhere in the file, remove those import statements as well.

Comment thread tests/test_rpc.py
Comment on lines +9 to +11
@pytest.fixture
def anyio_backend():
return 'asyncio'

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if pytest-anyio is declared in project dependencies

# Search for pytest-anyio in common dependency files
rg -i 'pytest-anyio' -g 'requirements*.txt' -g 'pyproject.toml' -g 'setup.py' -g 'setup.cfg' -g 'Pipfile'

Repository: StabilityNexus/MiniChain

Length of output: 50


🏁 Script executed:

# Check what dependencies are actually declared
fd -e 'pyproject.toml' -o -e 'setup.py' -o -e 'requirements.txt' | head -20

Repository: StabilityNexus/MiniChain

Length of output: 185


🏁 Script executed:

# Look for content of main dependency files
cat pyproject.toml 2>/dev/null || cat setup.py 2>/dev/null || cat requirements.txt 2>/dev/null

Repository: StabilityNexus/MiniChain

Length of output: 94


🏁 Script executed:

# Search for anyio imports and pytest_anyio references in the codebase
rg 'import.*anyio|from.*anyio|pytest.mark.anyio|pytest_anyio' --type python -i

Repository: StabilityNexus/MiniChain

Length of output: 99


🏁 Script executed:

# Check if conftest.py exists and what's in it
find . -name 'conftest.py' -exec head -30 {} \;

Repository: StabilityNexus/MiniChain

Length of output: 152


🏁 Script executed:

# Search for anyio-related imports correctly
rg 'import.*anyio|from.*anyio|pytest\.mark\.anyio' --type-list

Repository: StabilityNexus/MiniChain

Length of output: 458


🏁 Script executed:

# Check test_rpc.py content
cat tests/test_rpc.py | head -50

Repository: StabilityNexus/MiniChain

Length of output: 1650


🏁 Script executed:

# Search for anyio or pytest_anyio in all files
rg 'anyio|pytest_anyio' -i

Repository: StabilityNexus/MiniChain

Length of output: 218


🏁 Script executed:

# Check if anyio is in any dependency file
rg 'anyio' requirements*.txt pyproject.toml setup.py setup.cfg 2>/dev/null

Repository: StabilityNexus/MiniChain

Length of output: 50


Add pytest-anyio to project dependencies.

The @pytest.mark.anyio decorator and anyio_backend fixture in test_rpc.py require the pytest-anyio package, which is not listed in requirements.txt. These tests will fail without it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_rpc.py` around lines 9 - 11, The anyio_backend fixture and
`@pytest.mark.anyio` decorator used in the test file require the pytest-anyio
package, but this dependency is not currently included in the project's
dependencies file. Add pytest-anyio to the project's dependency list
(requirements.txt or equivalent dependency management file) to ensure the test
suite has access to the necessary pytest-anyio plugin.

Comment thread tests/test_rpc.py

@pytest.mark.anyio
async def test_rpc_blockNumber(rpc_server):
server, port, chain, mempool = rpc_server

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use underscore prefix for unused unpacked variables.

Only port is used; prefix unused variables with _ to signal intent and silence linter warnings.

♻️ Proposed fix
-    server, port, chain, mempool = rpc_server
+    _server, port, _chain, _mempool = rpc_server
📝 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
server, port, chain, mempool = rpc_server
_server, port, _chain, _mempool = rpc_server
🧰 Tools
🪛 Ruff (0.15.15)

[warning] 29-29: Unpacked variable server is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 29-29: Unpacked variable chain is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 29-29: Unpacked variable mempool is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_rpc.py` at line 29, In the tuple unpacking statement at the
rpc_server assignment, only the `port` variable is used in the subsequent code.
Prefix the unused variables (`server`, `chain`, and `mempool`) with an
underscore (e.g., `_server`, `_chain`, `_mempool`) to explicitly signal that
these variables are intentionally unused, which will satisfy linter requirements
and improve code clarity. Keep `port` without the underscore prefix since it is
actively used.

Source: Linters/SAST tools

Comment thread tests/test_rpc.py

@pytest.mark.anyio
async def test_rpc_getBlockByNumber(rpc_server):
server, port, chain, mempool = rpc_server

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use underscore prefix for unused unpacked variables.

Only port is used; prefix unused variables with _.

♻️ Proposed fix
-    server, port, chain, mempool = rpc_server
+    _server, port, _chain, _mempool = rpc_server
📝 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
server, port, chain, mempool = rpc_server
_server, port, _chain, _mempool = rpc_server
🧰 Tools
🪛 Ruff (0.15.15)

[warning] 41-41: Unpacked variable server is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 41-41: Unpacked variable chain is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 41-41: Unpacked variable mempool is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_rpc.py` at line 41, In the unpacking assignment where rpc_server
is destructured, prefix the unused variables with an underscore to follow Python
conventions. Keep only the `port` variable without an underscore since it is
actually used, and rename `server`, `chain`, and `mempool` to `_server`,
`_chain`, and `_mempool` respectively.

Source: Linters/SAST tools

Comment thread tests/test_rpc.py

@pytest.mark.anyio
async def test_rpc_invalid_method(rpc_server):
server, port, chain, mempool = rpc_server

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use underscore prefix for unused unpacked variables.

Only port is used; prefix unused variables with _.

♻️ Proposed fix
-    server, port, chain, mempool = rpc_server
+    _server, port, _chain, _mempool = rpc_server
🧰 Tools
🪛 Ruff (0.15.15)

[warning] 53-53: Unpacked variable server is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 53-53: Unpacked variable chain is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)


[warning] 53-53: Unpacked variable mempool is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_rpc.py` at line 53, In the unpacking assignment where `server,
port, chain, mempool = rpc_server`, only the `port` variable is used in the
function. Prefix the unused variables `server`, `chain`, and `mempool` with an
underscore to follow Python convention for unused variables. Change the line to
`_server, port, _chain, _mempool = rpc_server`.

Source: Linters/SAST tools

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant