feat(network): a clear auth-failed node banner with a fix-it action

When the node rejects the wallet's RPC login (bad rpcuser/rpcpassword), the
status bar showed developer jargon ("Auth failed — check rpcuser/rpcpassword")
and the only action was Reconnect, which just repeats the failure. Now a
dedicated AuthFailed banner reason surfaces "Wallet can't sign in to the node"
with a plain-language detail and a real fix: Restart node for the embedded
daemon (regenerates its cookie creds) or Open config folder for an external one
(to fix DRAGONX.conf). Driven by a new rpc_auth_failed_ flag (set on the auth
path, cleared on each connect attempt), with evaluator unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 11:53:29 -05:00
co-authored by Claude Opus 4.8
parent adf61e43d6
commit 0101cc707c
6 changed files with 66 additions and 7 deletions
+23
View File
@@ -3559,6 +3559,29 @@ void testNodeStatusBanner()
EXPECT_TRUE(s.action == NodeBannerAction::RestartNode);
EXPECT_TRUE(s.detail.empty());
}
// Auth failure (bad rpcuser/rpcpassword): embedded → Restart (regenerates creds), external → Open
// config folder. A hard error, detail cleared (App renders a translated actionable hint).
{
NodeBannerInputs in; in.auth_failed = true;
in.using_embedded_daemon = true; in.has_daemon_controller = true;
NodeBannerState s = evaluateNodeStatusBanner(in);
EXPECT_TRUE(s.reason == NodeBannerReason::AuthFailed);
EXPECT_TRUE(s.severity == NodeBannerSeverity::Error);
EXPECT_TRUE(s.action == NodeBannerAction::RestartNode);
EXPECT_TRUE(s.detail.empty());
}
{
NodeBannerInputs in; in.auth_failed = true; // external node
NodeBannerState s = evaluateNodeStatusBanner(in);
EXPECT_TRUE(s.reason == NodeBannerReason::AuthFailed);
EXPECT_TRUE(s.action == NodeBannerAction::OpenConfigFolder);
}
// A connected wallet never shows the auth banner (the connected branch returns earlier).
{
NodeBannerInputs in; in.connected = true; in.tip_known = true; in.blocks = 100;
in.auth_failed = true;
EXPECT_TRUE(!evaluateNodeStatusBanner(in).show);
}
// Connected, tip unknown, but no chain info yet (blocks==0) → no banner (avoid startup flicker).
{
NodeBannerInputs in; in.connected = true; in.tip_known = false; in.blocks = 0;