fix(rpc): drop a stale connect result after teardown; don't let open() erase a pending abort
Concurrency audit, connect-lifecycle races (no fund-path call touched — connect-result gating + abort-flag lifetime only): - The connect task's MainCb ran onConnected() on any successful probe without re-checking that a wallet switch / adopt / restore / shutdown had already torn the connection down — so a probe that succeeded against the old daemon could start a refresh against one about to be stopped. Capture rpc_session_ when posting (main thread) and, in the MainCb, drop the result (requestAbort + disconnect, not a blocking bare disconnect) when the session changed or daemon_restarting_/shutting_down_ is set. Same guard on the cookie-auth retry post. - RPCClient::open() called clearAbort(), so a requestAbort() issued while a connect was still queued was erased, stalling teardown/shutdown. open() no longer clears it; the two reconnect entry points (tryConnect for rpc_, onConnected for fast_rpc_) clear it on the main thread first, skipped while shutting_down_ so a shutdown abort survives. A fresh client defaults to not-aborted, so first connects are unaffected. HELD (not in this commit): making abortMaintenanceCalls() abort unconditionally (the UI-freeze-on-disconnect finding) — it would also abort an in-flight user send during teardown, a send-lifecycle behaviour change that wants explicit sign-off (it is fund-safe via the lost-reply "outcome unknown" handling, but still a behaviour change). Threading fix — clean build + ctest; the races are runtime-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -216,7 +216,8 @@ bool RPCClient::open(const std::string& host, const std::string& port,
|
||||
curl_easy_setopt(impl_->curl, CURLOPT_HTTPHEADER, impl_->headers);
|
||||
curl_easy_setopt(impl_->curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
// Progress callback so requestAbort() can unblock an in-flight curl_easy_perform.
|
||||
clearAbort(); // a fresh connection must not start in the aborted state
|
||||
// NOTE: abort is deliberately NOT cleared here: a requestAbort() issued while this connect was queued
|
||||
// must still cut it short. Reconnect callers (App::tryConnect / onConnected) call clearAbort() first.
|
||||
curl_easy_setopt(impl_->curl, CURLOPT_NOPROGRESS, 0L);
|
||||
curl_easy_setopt(impl_->curl, CURLOPT_XFERINFOFUNCTION, xferInfoCallback);
|
||||
curl_easy_setopt(impl_->curl, CURLOPT_XFERINFODATA, this);
|
||||
|
||||
Reference in New Issue
Block a user