Skip to content

Commit c808050

Browse files
authored
Merge pull request #15 from janb84/fix/RPC_Bitcoin_v31_fixes
Fix RPC compatibility with Bitcoin Core v31
2 parents 670df81 + 6d4b23a commit c808050

File tree

7 files changed

+26
-8
lines changed

7 files changed

+26
-8
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to bitcoin-tui are documented here.
44

5+
## [0.7.1] - 2026-03-17
6+
7+
### Changed
8+
- RPC client now uses HTTP/1.1 with `Connection: close` to fix empty-response errors against Bitcoin Core
9+
- Default RPC timeout increased from 10s to 30s to accommodate slow responses during initial startup (mempool load, IBD catch-up)
10+
- Removed `Start height` field from peer detail overlay — `startingheight` is deprecated in Bitcoin Core v31 and will be removed in v32
11+
12+
### Fixed
13+
- Improved RPC error messages: timeout and connection-closed failures are now reported distinctly instead of both showing as "Empty response from Bitcoin Core"
14+
515
## [0.7.0] - 2026-03-09
616

717
### Added

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.14)
2-
project(bitcoin-tui VERSION 0.7.0 LANGUAGES CXX)
2+
project(bitcoin-tui VERSION 0.7.1 LANGUAGES CXX)
33

44
set(CMAKE_CXX_STANDARD 20)
55
set(CMAKE_CXX_STANDARD_REQUIRED ON)

src/poll.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ void poll_rpc(RpcClient& rpc, AppState& state, std::mutex& mtx,
7373
peer.version = p.value("version", 0);
7474
peer.synced_blocks = p.value("synced_blocks", 0LL);
7575
peer.conntime = p.value("conntime", 0LL);
76-
peer.startingheight = p.value("startingheight", 0LL);
7776
peer.connection_type = p.value("connection_type", "");
7877
peer.transport = p.value("transport_protocol_type", "");
7978
peer.addr_processed = p.value("addr_processed", 0LL);

src/render.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,6 @@ Element render_peer_detail(const PeerInfo& p, const PeerActionResult& action, in
376376
label_value(" Recv : ", fmt_bytes(p.bytes_recv)),
377377
label_value(" Sent : ", fmt_bytes(p.bytes_sent)),
378378
label_value(" Height : ", fmt_height(p.synced_blocks)),
379-
label_value(" Start height: ", fmt_height(p.startingheight)),
380379
label_value(" HB compact : ", hb),
381380
label_value(" Addrs proc : ", fmt_int(p.addr_processed)),
382381
};

src/rpc_client.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <sys/socket.h>
66
#include <unistd.h>
77

8+
#include <cerrno>
89
#include <cstring>
910

1011
RpcClient::RpcClient(RpcConfig config) : config_(std::move(config)) {}
@@ -81,9 +82,10 @@ std::string RpcClient::http_post(const std::string& body) {
8182
}
8283
freeaddrinfo(res);
8384

84-
// Build HTTP/1.0 request (avoids chunked transfer encoding)
85+
// Build HTTP/1.1 request with Connection: close so the server closes after
86+
// responding, allowing recv() to reach EOF without waiting for a timeout.
8587
const std::string auth = base64_encode(config_.user + ":" + config_.password);
86-
const std::string request = "POST / HTTP/1.0\r\n"
88+
const std::string request = "POST / HTTP/1.1\r\n"
8789
"Host: " +
8890
config_.host +
8991
"\r\n"
@@ -94,6 +96,7 @@ std::string RpcClient::http_post(const std::string& body) {
9496
"Content-Length: " +
9597
std::to_string(body.size()) +
9698
"\r\n"
99+
"Connection: close\r\n"
97100
"\r\n" +
98101
body;
99102

@@ -115,10 +118,18 @@ std::string RpcClient::http_post(const std::string& body) {
115118
while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
116119
response.append(buf, static_cast<size_t>(n));
117120
}
121+
const int recv_errno = errno;
118122
close(sock);
119123

120124
if (response.empty()) {
121-
throw RpcError("Empty response from Bitcoin Core");
125+
if (n < 0 && (recv_errno == EAGAIN || recv_errno == EWOULDBLOCK))
126+
throw RpcError("RPC timeout — Bitcoin Core did not respond within " +
127+
std::to_string(config_.timeout_seconds) + "s");
128+
else if (n < 0)
129+
throw RpcError("recv() failed: " + std::string(strerror(recv_errno)));
130+
else
131+
throw RpcError(
132+
"Empty response from Bitcoin Core — connection closed before any data was sent");
122133
}
123134

124135
// Extract HTTP status

src/rpc_client.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ struct RpcConfig {
1717
int port = 8332;
1818
std::string user;
1919
std::string password;
20-
int timeout_seconds = 10;
20+
int timeout_seconds = 30;
2121
};
2222

2323
class RpcClient {

src/state.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ struct PeerInfo {
3636
int64_t synced_blocks = 0;
3737
int64_t conntime = 0;
3838
std::string services;
39-
int64_t startingheight = 0;
4039
bool bip152_hb_from = false;
4140
bool bip152_hb_to = false;
4241
std::string connection_type;

0 commit comments

Comments
 (0)