diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 6eb060e04c53..01e13361d044 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -475,6 +475,16 @@ class WalletImpl : public Wallet return m_wallet.vRewardDistributionPcts; } + bool getMintOnly() override + { + return m_wallet.fWalletUnlockMintOnly; + } + + void setMintOnly(bool f) override + { + m_wallet.fWalletUnlockMintOnly = f; + } + std::shared_ptr m_shared_wallet; CWallet& m_wallet; }; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 70a945f7439e..9fc8e169e200 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -284,6 +284,9 @@ class Wallet //! Get list of percentages of staking reward distribution. virtual std::vector> getRewardDistributionPcts() = 0; + + virtual bool getMintOnly() = 0; + virtual void setMintOnly(bool f) = 0; }; //! Tracking object returned by CreateTransaction and passed to CommitTransaction. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 606272f88ee0..c9d14198bc79 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1090,6 +1090,7 @@ void BitcoinGUI::setHDStatus(int hdEnabled) void BitcoinGUI::setEncryptionStatus(int status) { + bool mintonly; switch(status) { case WalletModel::Unencrypted: @@ -1107,8 +1108,9 @@ void BitcoinGUI::setEncryptionStatus(int status) encryptWalletAction->setChecked(true); changePassphraseAction->setEnabled(true); encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported - decryptForMintingAction->setEnabled(fWalletUnlockMintOnly); - decryptForMintingAction->setChecked(fWalletUnlockMintOnly); + mintonly = walletFrame->currentWalletView()->getWalletModel()->getMintOnly(); + decryptForMintingAction->setEnabled(mintonly); + decryptForMintingAction->setChecked(mintonly); break; case WalletModel::Locked: labelWalletEncryptionIcon->show(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 7ca403fb9dc5..844f21499d8b 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -462,7 +462,7 @@ void WalletModel::unsubscribeFromCoreSignals() WalletModel::UnlockContext WalletModel::requestUnlock() { bool was_locked = getEncryptionStatus() == Locked; - if ((!was_locked) && fWalletUnlockMintOnly) + if ((!was_locked) && getMintOnly()) { setWalletLocked(true); was_locked = getEncryptionStatus() == Locked; @@ -475,7 +475,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock() // If wallet is still locked, unlock was failed or cancelled, mark context as invalid bool valid = getEncryptionStatus() != Locked; - return UnlockContext(this, valid, was_locked && !fWalletUnlockMintOnly); + return UnlockContext(this, valid, was_locked && !getMintOnly()); } WalletModel::UnlockContext::UnlockContext(WalletModel *_wallet, bool _valid, bool _relock): @@ -600,6 +600,12 @@ bool WalletModel::isMultiwallet() return m_node.getWallets().size() > 1; } -// xpchain: optional setting to unlock wallet for block minting only; -// serves to disable the trivial sendmoney when OS account compromised -bool fWalletUnlockMintOnly = false; +bool WalletModel::getMintOnly() +{ + return m_wallet->getMintOnly(); +} + +void WalletModel::setMintOnly(bool f) +{ + m_wallet->setMintOnly(f); +} \ No newline at end of file diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index ea91b391c7fd..bc678a6dee3e 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -21,8 +21,6 @@ #include -extern bool fWalletUnlockMintOnly; - enum class OutputType; class AddressTableModel; @@ -213,6 +211,9 @@ class WalletModel : public QObject bool isMultiwallet(); AddressTableModel* getAddressTableModel() const { return addressTableModel; } + + bool getMintOnly(); + void setMintOnly(bool f); private: std::unique_ptr m_wallet; std::unique_ptr m_handler_unload; diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 4e47ae2608c4..61786a3907bd 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -274,13 +274,13 @@ void WalletView::decryptForMinting(bool status) if(walletModel->getEncryptionStatus() != WalletModel::Locked) return; - fWalletUnlockMintOnly = true; + walletModel->setMintOnly(true); AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this); dlg.setModel(walletModel); dlg.exec(); if(walletModel->getEncryptionStatus() != WalletModel::Unlocked){ - fWalletUnlockMintOnly = false; + walletModel->setMintOnly(false); updateEncryptionStatus(); return; } @@ -290,11 +290,10 @@ void WalletView::decryptForMinting(bool status) if(walletModel->getEncryptionStatus() != WalletModel::Unlocked) return; - if (!fWalletUnlockMintOnly) + if (!walletModel->getMintOnly()) return; walletModel->setWalletLocked(true); - fWalletUnlockMintOnly = false; } } diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index f277784059f2..2bc2f7c13903 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -69,6 +69,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listaccounts", 0, "minconf" }, { "listaccounts", 1, "include_watchonly" }, { "walletpassphrase", 1, "timeout" }, + { "walletpassphrase", 2, "mintonly" }, { "getblocktemplate", 0, "template_request" }, { "listsinceblock", 1, "target_confirmations" }, { "listsinceblock", 2, "include_watchonly" }, diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index eb38fce41193..66ae913cf5d7 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -90,6 +90,7 @@ enum RPCErrorCode //! Unused reserved codes, kept around for backwards compatibility. Do not reuse. RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode + RPC_WALLET_MINTONLY = -102, }; UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 418316c39872..1ad56332cfd5 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -143,7 +143,7 @@ class CCryptoKeyStore : public CBasicKeyStore bool IsCrypted() const { return fUseCrypto; } bool IsLocked() const; - bool Lock(); + virtual bool Lock(); virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 975a09e83795..d9460e7889c8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -90,6 +90,9 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet) if (pwallet->IsLocked()) { throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); } + if (pwallet->fWalletUnlockMintOnly) { + throw JSONRPCError(RPC_WALLET_MINTONLY, "Error: Wallet is unlocked for minting only."); + } } static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) @@ -2558,14 +2561,15 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() != 2) { + if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) { throw std::runtime_error( - "walletpassphrase \"passphrase\" timeout\n" + "walletpassphrase \"passphrase\" timeout ( mintonly )\n" "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" "This is needed prior to performing transactions related to private keys such as sending xpchains\n" "\nArguments:\n" "1. \"passphrase\" (string, required) The wallet passphrase\n" "2. timeout (numeric, required) The time to keep the decryption key in seconds; capped at 100000000 (~3 years).\n" + "3. mintonly (boolean, optional, default: false) allowing only block minting.\n" "\nNote:\n" "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n" "time that overrides the old one.\n" @@ -2620,6 +2624,10 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) pwallet->nRelockTime = GetTime() + nSleepTime; RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), std::bind(LockWallet, pwallet), nSleepTime); + if(request.params.size() > 2) + pwallet->fWalletUnlockMintOnly = request.params[2].get_bool(); + else + pwallet->fWalletUnlockMintOnly = false; return NullUniValue; } @@ -5011,7 +5019,7 @@ static const CRPCCommand commands[] = { "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} }, { "wallet", "walletlock", &walletlock, {} }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, - { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, + { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout","mintonly"} }, { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1924b9f2dc6d..3856f0d718f4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4567,3 +4567,8 @@ std::vector CWallet::GroupOutputs(const std::vector& outpu } return groups; } + +bool CWallet::Lock() { + fWalletUnlockMintOnly = false; + return CCryptoKeyStore::Lock(); +} \ No newline at end of file diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9551c1a44c30..5c6a58a2ac6a 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1221,6 +1221,9 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface /** Clear percentages of staking reward distribution, and erase it from database file */ bool DelRewardDistributionPcts(); + + bool fWalletUnlockMintOnly = false; + bool Lock() override; }; /** A key allocated from the key pool. */