From e2f88175abfb94b4d71d2caae3cb556311a91780 Mon Sep 17 00:00:00 2001 From: DanS Date: Sun, 23 Aug 2026 03:22:55 +0200 Subject: [PATCH] wallet: default -autoshield ON only when the HD seed is known-recoverable Autoshield moves mined coinbase into a z-address that only this wallet's HD seed can re-derive. Defaulting that ON is only defensible where the user can actually restore that seed. Two cases fail that test. A seedless legacy wallet has a seed minted onto it silently at first start, so no backup the user already holds contains it. And a wallet seeded by an earlier build predates provenance recording, so we cannot tell which case it was. Both are now classified as not-known-recoverable and autoshield stays off there until the operator backs the seed up and passes -autoshield=1. An explicit -autoshield=0/1 still wins in either direction. Wallets this software created on an empty datadir, or restored from a user-supplied -mnemonic/-hdseed, keep the ON default: in both cases the user either has the phrase or supplied the seed themselves. Verified on real wallets: a wallet carrying no origin record is classified unknown and logs "autoshield left OFF by default: HD seed origin 4"; a wallet created by the previous commit logs "autoshield enabled" with no re-classification, confirming the record persists rather than being recomputed. Co-Authored-By: Claude Opus 5 (1M context) --- src/init.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9a3e48458..7384ebf1c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -489,7 +489,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-zsweepexternal", _("Enable sweeping to an external wallet (default false)")); strUsage += HelpMessageOpt("-zsweepexclude", _("Addresses to exclude from sweeping (default none)")); - strUsage += HelpMessageOpt("-autoshield", _("Automatically shield matured coinbase (mining rewards) into a wallet z-address (default: true). No-op when not mining or wallet is locked.")); + strUsage += HelpMessageOpt("-autoshield", _("Automatically shield matured coinbase (mining rewards) into a seed-derived wallet z-address (default: true for wallets created or restored by this software, false when the HD seed provenance is unknown). No-op when not mining or wallet is locked.")); strUsage += HelpMessageOpt("-autoshieldinterval", strprintf(_("Block interval between automatic coinbase-shielding rounds (default: %i, min 5)"), 25)); strUsage += HelpMessageOpt("-autoshieldaddress=", _("Destination Sapling z-address for auto-shielded coinbase (default: reuse or create a wallet z-address). Must be spendable by this wallet.")); strUsage += HelpMessageOpt("-autoshieldfee", strprintf(_("Fee in puposhis for automatic coinbase-shielding transactions (default: %i)"), 10000)); @@ -2499,7 +2499,21 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) //Set Automatic Coinbase Shielding (default ON, conditional: self-guards //on nodes where it cannot act - no owned coinbase, external mineraddress, //or locked wallet). Closes the transparent-coinbase leak for miners. - pwalletMain->fAutoShieldEnabled = GetBoolArg("-autoshield", true); + // Default ON only when this wallet's HD seed provenance says the + // destination is genuinely recoverable. Autoshield sends mined coinbase to + // a seed-derived z-address (resolveDestination), so for a seed retrofitted + // onto a pre-existing wallet - or one predating provenance recording - we + // cannot assume the user holds it. Those wallets opt in with -autoshield=1 + // after backing the seed up. + const bool fAutoShieldSeedKnown = + (pwalletMain->hdSeedOrigin == CWallet::HDSEED_ORIGIN_CREATED || + pwalletMain->hdSeedOrigin == CWallet::HDSEED_ORIGIN_RESTORED); + pwalletMain->fAutoShieldEnabled = GetBoolArg("-autoshield", fAutoShieldSeedKnown); + if (!fAutoShieldSeedKnown && !mapArgs.count("-autoshield")) { + LogPrintf("%s: autoshield left OFF by default: HD seed origin %d is not known-recoverable. " + "Back the seed up (z_exportwallet, or z_exportmnemonic on a mnemonic wallet) and " + "pass -autoshield=1 to enable.\n", __func__, pwalletMain->hdSeedOrigin); + } if (pwalletMain->fAutoShieldEnabled) { int autoShieldInterval = GetArg("-autoshieldinterval", 25); if (autoShieldInterval < 5) {