mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-20 12:39:47 +01:00
Merge #16237: Have the wallet give out destinations instead of keys
8e7f930828Add GetNewChangeDestination for getting new change Destinations (Andrew Chow)33d13edd2bReplace CReserveKey with ReserveDestinatoin (Andrew Chow)172213be5bAdd GetNewDestination to CWallet to fetch new destinations (Andrew Chow) Pull request description: The wallet should give out destinations instead of keys. It should be the one that handles the conversion from key to destination and the setting of the label, not the caller. In order to do this, two new member functions are introduced `GetNewDestination()` and `GetNewChangeDestination()`. Additionally, `CReserveKey` is changed to be `ReserveDestination` and represents destinations whose keys can be returned to the keypool. ACKs for top commit: instagibbs: re-utACK8e7f930828sipa: ACK8e7f930828. Concept ACK as this gives a much cleaner abstraction to work with, and light code review ACK. laanwj: ACK8e7f930828Tree-SHA512: 5be7051409232b71e0ef2c1fd1a3e76964ed2f5b14d47d06edc2ad3b3687abd0be2803a1adc45c0433aa2c3bed172e14f8a7e9f4a23bff70f86260b5a0497500
This commit is contained in:
@@ -2666,9 +2666,9 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
|
||||
auto locked_chain = chain().lock();
|
||||
LOCK(cs_wallet);
|
||||
|
||||
CReserveKey reservekey(this);
|
||||
ReserveDestination reservedest(this);
|
||||
CTransactionRef tx_new;
|
||||
if (!CreateTransaction(*locked_chain, vecSend, tx_new, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
|
||||
if (!CreateTransaction(*locked_chain, vecSend, tx_new, reservedest, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2676,7 +2676,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
|
||||
tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]);
|
||||
// We don't have the normal Create/Commit cycle, and don't want to risk
|
||||
// reusing change, so just remove the key from the keypool here.
|
||||
reservekey.KeepKey();
|
||||
reservedest.KeepDestination();
|
||||
}
|
||||
|
||||
// Copy output sizes from new transaction; they may have had the fee
|
||||
@@ -2792,7 +2792,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
|
||||
return m_default_address_type;
|
||||
}
|
||||
|
||||
bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
|
||||
bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, ReserveDestination& reservedest, CAmount& nFeeRet,
|
||||
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
|
||||
{
|
||||
CAmount nValue = 0;
|
||||
@@ -2833,7 +2833,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
||||
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
|
||||
|
||||
// Create change script that will be used if we need change
|
||||
// TODO: pass in scriptChange instead of reservekey so
|
||||
// TODO: pass in scriptChange instead of reservedest so
|
||||
// change transaction isn't always pay-to-bitcoin-address
|
||||
CScript scriptChange;
|
||||
|
||||
@@ -2853,19 +2853,16 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
||||
strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.");
|
||||
return false;
|
||||
}
|
||||
CPubKey vchPubKey;
|
||||
bool ret;
|
||||
ret = reservekey.GetReservedKey(vchPubKey, true);
|
||||
CTxDestination dest;
|
||||
const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
|
||||
bool ret = reservedest.GetReservedDestination(change_type, dest, true);
|
||||
if (!ret)
|
||||
{
|
||||
strFailReason = _("Keypool ran out, please call keypoolrefill first");
|
||||
strFailReason = "Keypool ran out, please call keypoolrefill first";
|
||||
return false;
|
||||
}
|
||||
|
||||
const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
|
||||
|
||||
LearnRelatedScripts(vchPubKey, change_type);
|
||||
scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type));
|
||||
scriptChange = GetScriptForDestination(dest);
|
||||
}
|
||||
CTxOut change_prototype_txout(0, scriptChange);
|
||||
coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
|
||||
@@ -3086,7 +3083,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
||||
}
|
||||
}
|
||||
|
||||
if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change
|
||||
if (nChangePosInOut == -1) reservedest.ReturnDestination(); // Return any reserved address if we don't have change
|
||||
|
||||
// Shuffle selected coins and fill in final vin
|
||||
txNew.vin.clear();
|
||||
@@ -3159,7 +3156,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
|
||||
/**
|
||||
* Call after CreateTransaction unless you want to abort
|
||||
*/
|
||||
bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CValidationState& state)
|
||||
bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, ReserveDestination& reservedest, CValidationState& state)
|
||||
{
|
||||
{
|
||||
auto locked_chain = chain().lock();
|
||||
@@ -3174,7 +3171,7 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
||||
WalletLogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); /* Continued */
|
||||
{
|
||||
// Take key pair from key pool so it won't be used again
|
||||
reservekey.KeepKey();
|
||||
reservedest.KeepDestination();
|
||||
|
||||
// Add tx to wallet, because if it has change it's also ours,
|
||||
// otherwise just for transaction history.
|
||||
@@ -3575,6 +3572,44 @@ 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;
|
||||
}
|
||||
|
||||
bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error)
|
||||
{
|
||||
error.clear();
|
||||
if (!IsLocked()) {
|
||||
TopUpKeyPool();
|
||||
}
|
||||
|
||||
ReserveDestination reservedest(this);
|
||||
if (!reservedest.GetReservedDestination(type, dest, true)) {
|
||||
error = "Error: Keypool ran out, please call keypoolrefill first";
|
||||
return false;
|
||||
}
|
||||
|
||||
reservedest.KeepDestination();
|
||||
return true;
|
||||
}
|
||||
|
||||
static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, WalletBatch& batch) {
|
||||
if (setKeyPool.empty()) {
|
||||
return GetTime();
|
||||
@@ -3754,7 +3789,7 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
|
||||
bool ReserveDestination::GetReservedDestination(const OutputType type, CTxDestination& dest, bool internal)
|
||||
{
|
||||
if (!pwallet->CanGetAddresses(internal)) {
|
||||
return false;
|
||||
@@ -3770,25 +3805,29 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
|
||||
fInternal = keypool.fInternal;
|
||||
}
|
||||
assert(vchPubKey.IsValid());
|
||||
pubkey = vchPubKey;
|
||||
pwallet->LearnRelatedScripts(vchPubKey, type);
|
||||
address = GetDestinationForKey(vchPubKey, type);
|
||||
dest = address;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CReserveKey::KeepKey()
|
||||
void ReserveDestination::KeepDestination()
|
||||
{
|
||||
if (nIndex != -1)
|
||||
pwallet->KeepKey(nIndex);
|
||||
nIndex = -1;
|
||||
vchPubKey = CPubKey();
|
||||
address = CNoDestination();
|
||||
}
|
||||
|
||||
void CReserveKey::ReturnKey()
|
||||
void ReserveDestination::ReturnDestination()
|
||||
{
|
||||
if (nIndex != -1) {
|
||||
pwallet->ReturnKey(nIndex, fInternal, vchPubKey);
|
||||
}
|
||||
nIndex = -1;
|
||||
vchPubKey = CPubKey();
|
||||
address = CNoDestination();
|
||||
}
|
||||
|
||||
void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
|
||||
|
||||
Reference in New Issue
Block a user