Add GetNewDestination to CWallet to fetch new destinations

Instead of having the same multiple lines of code everywhere
that new destinations are fetched, introduce GetNewDestination as
a member function of CWallet which does the key fetching, label
setting, script generation, and destination generation.
This commit is contained in:
Andrew Chow 2019-06-18 15:19:13 -04:00
parent 0853d8d2fd
commit 172213be5b
9 changed files with 52 additions and 41 deletions

View file

@ -140,9 +140,11 @@ public:
void abortRescan() override { m_wallet->AbortRescan(); }
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
std::string getWalletName() override { return m_wallet->GetName(); }
bool getKeyFromPool(bool internal, CPubKey& pub_key) override
bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
{
return m_wallet->GetKeyFromPool(pub_key, internal);
LOCK(m_wallet->cs_wallet);
std::string error;
return m_wallet->GetNewDestination(type, label, dest, error);
}
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetPubKey(address, pub_key); }
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetKey(address, key); }

View file

@ -76,8 +76,8 @@ public:
//! Get wallet name.
virtual std::string getWalletName() = 0;
// Get key from pool.
virtual bool getKeyFromPool(bool internal, CPubKey& pub_key) = 0;
// Get a new address.
virtual bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) = 0;
//! Get public key.
virtual bool getPubKey(const CKeyID& address, CPubKey& pub_key) = 0;

View file

@ -358,12 +358,15 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
// Add entry
walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel, "send");
}
else if(type == Receive)
{
// Generate a new address to associate with given label
CPubKey newKey;
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
CTxDestination dest;
if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
{
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
if(!ctx.isValid())
@ -372,23 +375,18 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
editStatus = WALLET_UNLOCK_FAILURE;
return QString();
}
if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
{
editStatus = KEY_GENERATION_FAILURE;
return QString();
}
}
walletModel->wallet().learnRelatedScripts(newKey, address_type);
strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type));
strAddress = EncodeDestination(dest);
}
else
{
return QString();
}
// Add entry
walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel,
(type == Send ? "send" : "receive"));
return QString::fromStdString(strAddress);
}

View file

@ -666,16 +666,14 @@ void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRec
payment.add_transactions(transaction.data(), transaction.size());
// Create a new refund address, or re-use:
CPubKey newKey;
if (walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) {
CTxDestination dest;
const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
if (walletModel->wallet().getNewDestination(change_type, "", dest)) {
// BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
// types supported by the receiver. As a result, we choose the address format we also
// use for change. Despite an actual payment and not change, this is a close match:
// it's the output type we use subject to privacy issues, but not restricted by what
// other software supports.
const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
walletModel->wallet().learnRelatedScripts(newKey, change_type);
CTxDestination dest = GetDestinationForKey(newKey, change_type);
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
walletModel->wallet().setAddressBook(dest, label, "refund");

View file

@ -25,14 +25,9 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
std::string getnewaddress(CWallet& w)
{
constexpr auto output_type = OutputType::BECH32;
CPubKey new_key;
if (!w.GetKeyFromPool(new_key)) assert(false);
w.LearnRelatedScripts(new_key, output_type);
const auto dest = GetDestinationForKey(new_key, output_type);
w.SetAddressBook(dest, /* label */ "", "receive");
CTxDestination dest;
std::string error;
if (!w.GetNewDestination(output_type, "", dest, error)) assert(false);
return EncodeDestination(dest);
}

View file

@ -185,20 +185,12 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
}
}
if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
CTxDestination dest;
std::string error;
if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
}
// Generate a new key that is added to wallet
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
pwallet->LearnRelatedScripts(newKey, output_type);
CTxDestination dest = GetDestinationForKey(newKey, output_type);
pwallet->SetAddressBook(dest, label, "receive");
return EncodeDestination(dest);
}

View file

@ -466,8 +466,9 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
CPubKey pubkey;
BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
CTxDestination dest;
std::string error;
BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
}
// Explicit calculation which is used to test the wallet constant

View file

@ -3513,6 +3513,27 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
return true;
}
bool CWallet::GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error)
{
LOCK(cs_wallet);
error.clear();
if (!IsLocked()) {
TopUpKeyPool();
}
// Generate a new key that is added to wallet
CPubKey new_key;
if (!GetKeyFromPool(new_key)) {
error = "Error: Keypool ran out, please call keypoolrefill first";
return false;
}
LearnRelatedScripts(new_key, type);
dest = GetDestinationForKey(new_key, type);
SetAddressBook(dest, label, "receive");
return true;
}
static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, WalletBatch& batch) {
if (setKeyPool.empty()) {
return GetTime();

View file

@ -815,6 +815,9 @@ private:
*/
uint256 m_last_block_processed GUARDED_BY(cs_wallet);
//! Fetches a key from the keypool
bool GetKeyFromPool(CPubKey &key, bool internal = false);
public:
/*
* Main wallet lock.
@ -1110,7 +1113,6 @@ public:
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
/**
* Marks all keys in the keypool up to and including reserve_key as used.
@ -1123,6 +1125,8 @@ public:
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error);
isminetype IsMine(const CTxIn& txin) const;
/**
* Returns amount of debit if the input matches the