diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -29,6 +29,8 @@ boost::optional m_confirm_target; //! Avoid partial use of funds sent to a given address bool m_avoid_partial_spends; + //! Forbids inclusion of dirty (previously used) addresses + bool m_avoid_address_reuse; CCoinControl() { SetNull(); } diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp --- a/src/wallet/coincontrol.cpp +++ b/src/wallet/coincontrol.cpp @@ -13,6 +13,7 @@ fAllowWatchOnly = false; m_avoid_partial_spends = gArgs.GetBoolArg("-avoidpartialspends", DEFAULT_AVOIDPARTIALSPENDS); + m_avoid_address_reuse = false; setSelected.clear(); m_feerate.reset(); fOverrideFeeRate = false; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -41,6 +41,20 @@ static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; +[[maybe_unused]] static inline bool GetAvoidReuseFlag(CWallet *const pwallet, + const UniValue ¶m) { + bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); + bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool(); + + if (avoid_reuse && !can_avoid_reuse) { + throw JSONRPCError( + RPC_WALLET_ERROR, + "wallet does not have the \"avoid reuse\" feature enabled"); + } + + return avoid_reuse; +} + bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name) { if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -125,6 +125,11 @@ // the wallet if flag is unknown. // Unknown wallet flags in the lower section <= (1 << 31) will be tolerated. + // will categorize coins as clean (not reused) and dirty (reused), and + // handle + // them with privacy considerations in mind + WALLET_FLAG_AVOID_REUSE = (1ULL << 0), + // Indicates that the metadata has already been upgraded to contain key // origins WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1), @@ -147,8 +152,17 @@ }; static constexpr uint64_t KNOWN_WALLET_FLAGS = - WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | - WALLET_FLAG_KEY_ORIGIN_METADATA; + WALLET_FLAG_AVOID_REUSE | WALLET_FLAG_BLANK_WALLET | + WALLET_FLAG_KEY_ORIGIN_METADATA | WALLET_FLAG_DISABLE_PRIVATE_KEYS; + +static const std::map WALLET_FLAG_MAP{ + {"avoid_reuse", WALLET_FLAG_AVOID_REUSE}, + {"blank", WALLET_FLAG_BLANK_WALLET}, + {"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA}, + {"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS}, +}; + +extern const std::map WALLET_FLAG_CAVEATS; /** * A key from a CWallet's keypool diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -44,6 +44,13 @@ #include #include +const std::map WALLET_FLAG_CAVEATS{ + {WALLET_FLAG_AVOID_REUSE, + "You need to rescan the blockchain in order to correctly mark used " + "destinations in the past. Until this is done, some destinations may " + "be considered unused, even if the opposite is the case."}, +}; + static RecursiveMutex cs_wallets; static std::vector> vpwallets GUARDED_BY(cs_wallets);