Merge #15225: GUI: Change the receive button to respond to keypool state changing

2bc4c3eaf9 Notify the GUI that the keypool has changed to set the receive button (Andrew Chow)
14bcdbe09c Check for more than private keys disabled to show receive button (Andrew Chow)

Pull request description:

  Currently the Receive button in the GUI is displayed enabled or disabled by the initial state of the wallet when the wallet is first loaded. The button is only enabled or disabled depending on whether the disable private keys flag is set when the wallet is loaded. However, future changes to the wallet means that this initial state and check may no longer be accurate. #14938 introduces empty wallets which do not have private keys. An empty wallet that is loaded should have the Receive button disabled, and then it should become enabled once `sethdseed` is used so that a keypool can be generated and new keys generated. Likewise, with #14075, a wallet can be loaded with no keypool initially, so the button should be disabled. Later, public keys can be imported into the keypool, at which time the button should become enabled. When the keypool runs out again (no new keys are generated as the keypool only consists of imports), the button should become disabled.

  This PR makes it so that the button becomes enabled and disabled as the keypool state changes. The check for whether to enable or disable the receive button has changed to checking whether it is possible to get new keys. It now checks for whether the wallet has an HD seed and, if not, whether the private keys are disabled. When an action happens which would make it possible for a new address to be retrieved or make it possible for a no more addresses to be retrieved, a signal is emitted which has the GUI recheck the conditions for the Receive button. These actions are setting a new HD seed, topping up the keypool, retrieving a key from the keypool, and returning a key to the keypool.

Tree-SHA512: eff15a5337f4c64ecd7169414fb47053c04f6a0f0130341b6dd9799ac4d79f451e25284701c668971fca33f0909d5352a474a2c12349375bedfdb59b63077d50
This commit is contained in:
Wladimir J. van der Laan 2019-01-31 15:03:37 +01:00
commit 7c09e209ef
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
7 changed files with 44 additions and 2 deletions

View file

@ -493,6 +493,10 @@ public:
{ {
return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn)); return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn));
} }
std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
{
return MakeHandler(m_wallet.NotifyCanGetAddressesChanged.connect(fn));
}
std::shared_ptr<CWallet> m_shared_wallet; std::shared_ptr<CWallet> m_shared_wallet;
CWallet& m_wallet; CWallet& m_wallet;

View file

@ -271,6 +271,10 @@ public:
//! Register handler for watchonly changed messages. //! Register handler for watchonly changed messages.
using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>; using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>;
virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0; virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0;
//! Register handler for keypool changed messages.
using CanGetAddressesChangedFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0;
}; };
//! Tracking object returned by CreateTransaction and passed to CommitTransaction. //! Tracking object returned by CreateTransaction and passed to CommitTransaction.

View file

@ -100,8 +100,13 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
ui->useBech32->setCheckState(Qt::Unchecked); ui->useBech32->setCheckState(Qt::Unchecked);
} }
// eventually disable the main receive button if private key operations are disabled // Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
ui->receiveButton->setEnabled(!model->privateKeysDisabled()); ui->receiveButton->setEnabled(model->canGetAddresses());
// Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
connect(model, &WalletModel::canGetAddressesChanged, [this] {
ui->receiveButton->setEnabled(model->canGetAddresses());
});
} }
} }

View file

@ -423,6 +423,11 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
Q_ARG(bool, fHaveWatchonly)); Q_ARG(bool, fHaveWatchonly));
} }
static void NotifyCanGetAddressesChanged(WalletModel* walletmodel)
{
QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
}
void WalletModel::subscribeToCoreSignals() void WalletModel::subscribeToCoreSignals()
{ {
// Connect signals to wallet // Connect signals to wallet
@ -432,6 +437,7 @@ void WalletModel::subscribeToCoreSignals()
m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2)); m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2)); m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1)); m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1));
m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(boost::bind(NotifyCanGetAddressesChanged, this));
} }
void WalletModel::unsubscribeFromCoreSignals() void WalletModel::unsubscribeFromCoreSignals()
@ -443,6 +449,7 @@ void WalletModel::unsubscribeFromCoreSignals()
m_handler_transaction_changed->disconnect(); m_handler_transaction_changed->disconnect();
m_handler_show_progress->disconnect(); m_handler_show_progress->disconnect();
m_handler_watch_only_changed->disconnect(); m_handler_watch_only_changed->disconnect();
m_handler_can_get_addrs_changed->disconnect();
} }
// WalletModel::UnlockContext implementation // WalletModel::UnlockContext implementation
@ -571,6 +578,16 @@ bool WalletModel::privateKeysDisabled() const
return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
} }
bool WalletModel::canGetAddresses() const
{
// The wallet can provide a fresh address if:
// * hdEnabled(): an HD seed is present; or
// * it is a legacy wallet, because:
// * !hdEnabled(): an HD seed is not present; and
// * !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS): private keys have not been disabled (which results in hdEnabled() == true)
return m_wallet->hdEnabled() || (!m_wallet->hdEnabled() && !m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
}
QString WalletModel::getWalletName() const QString WalletModel::getWalletName() const
{ {
return QString::fromStdString(m_wallet->getWalletName()); return QString::fromStdString(m_wallet->getWalletName());

View file

@ -214,6 +214,7 @@ public:
static bool isWalletEnabled(); static bool isWalletEnabled();
bool privateKeysDisabled() const; bool privateKeysDisabled() const;
bool canGetAddresses() const;
interfaces::Node& node() const { return m_node; } interfaces::Node& node() const { return m_node; }
interfaces::Wallet& wallet() const { return *m_wallet; } interfaces::Wallet& wallet() const { return *m_wallet; }
@ -232,6 +233,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_transaction_changed; std::unique_ptr<interfaces::Handler> m_handler_transaction_changed;
std::unique_ptr<interfaces::Handler> m_handler_show_progress; std::unique_ptr<interfaces::Handler> m_handler_show_progress;
std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed; std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed;
std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed;
interfaces::Node& m_node; interfaces::Node& m_node;
bool fHaveWatchOnly; bool fHaveWatchOnly;
@ -283,6 +285,9 @@ Q_SIGNALS:
// Signal that wallet is about to be removed // Signal that wallet is about to be removed
void unload(); void unload();
// Notify that there are now keys in the keypool
void canGetAddressesChanged();
public Q_SLOTS: public Q_SLOTS:
/* Wallet status might have changed */ /* Wallet status might have changed */
void updateStatus(); void updateStatus();

View file

@ -1398,6 +1398,7 @@ void CWallet::SetHDSeed(const CPubKey& seed)
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE; newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.seed_id = seed.GetID(); newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false); SetHDChain(newHdChain, false);
NotifyCanGetAddressesChanged();
} }
void CWallet::SetHDChain(const CHDChain& chain, bool memonly) void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
@ -3335,6 +3336,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size()); WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
} }
} }
NotifyCanGetAddressesChanged();
return true; return true;
} }
@ -3379,6 +3381,7 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
WalletLogPrintf("keypool reserve %d\n", nIndex); WalletLogPrintf("keypool reserve %d\n", nIndex);
} }
NotifyCanGetAddressesChanged();
return true; return true;
} }
@ -3403,6 +3406,7 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
setExternalKeyPool.insert(nIndex); setExternalKeyPool.insert(nIndex);
} }
m_pool_key_to_index[pubkey.GetID()] = nIndex; m_pool_key_to_index[pubkey.GetID()] = nIndex;
NotifyCanGetAddressesChanged();
} }
WalletLogPrintf("keypool return %d\n", nIndex); WalletLogPrintf("keypool return %d\n", nIndex);
} }

View file

@ -1094,6 +1094,9 @@ public:
/** Watch-only address added */ /** Watch-only address added */
boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged; boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
/** Keypool has new keys */
boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
/** Inquire whether this wallet broadcasts transactions. */ /** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; } bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */ /** Set whether this wallet broadcasts transactions. */