From 54fc16e6278ccb0b67908193bcf1bd12e2048d43 Mon Sep 17 00:00:00 2001 From: fusion44 Date: Wed, 8 Jul 2026 13:47:11 +0200 Subject: [PATCH] test(bitcoind): lock JSON-RPC 2.0 success handling (no error key) Bitcoin Core 28+ replies to a JSON-RPC 2.0 request with a strict 2.0 response: a success has a 'result' key but no 'error' key. The v1.11 code did 'if result["error"] is not None' and crashed with KeyError: 'error'. The getters are already guarded on dev with 'if "error" in result and ...'; add regression tests for get_network_info / get_blockchain_info so that guard can't be dropped again (verified they fail against the old unguarded form). Fixes #277 Co-Authored-By: Claude Fable 5 --- tests/test_bitcoin_rpc_success.py | 41 +++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_bitcoin_rpc_success.py diff --git a/tests/test_bitcoin_rpc_success.py b/tests/test_bitcoin_rpc_success.py new file mode 100644 index 0000000..ebdfe16 --- /dev/null +++ b/tests/test_bitcoin_rpc_success.py @@ -0,0 +1,41 @@ +""" +Regression test for blitz_api#277. + +Bitcoin Core 28+ answers a JSON-RPC 2.0 request with a strict 2.0 response: +a successful reply contains a "result" key but no "error" key. The old code +did `if result["error"] is not None` and crashed with KeyError: 'error'. +get_network_info / get_blockchain_info must handle a success response that +has no "error" key. +""" + +from app.bitcoind import service + + +async def test_get_network_info_success_without_error_key(monkeypatch): + # strict JSON-RPC 2.0 success payload: note there is NO "error" key + async def fake_rpc(method, params=[]): + return {"jsonrpc": "2.0", "result": {"stub": "networkinfo"}, "id": 1} + + monkeypatch.setattr(service, "bitcoin_rpc_async", fake_rpc) + monkeypatch.setattr( + service.NetworkInfo, "from_rpc", staticmethod(lambda result: result) + ) + + # must not raise / swallow-to-None on the missing "error" key + out = await service.get_network_info() + + assert out == {"stub": "networkinfo"} + + +async def test_get_blockchain_info_success_without_error_key(monkeypatch): + async def fake_rpc(method, params=[]): + return {"jsonrpc": "2.0", "result": {"stub": "blockchaininfo"}, "id": 1} + + monkeypatch.setattr(service, "bitcoin_rpc_async", fake_rpc) + monkeypatch.setattr( + service.BlockchainInfo, "from_rpc", staticmethod(lambda result: result) + ) + + out = await service.get_blockchain_info() + + assert out == {"stub": "blockchaininfo"}