Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,311 Lines • ▼ Show 20 Lines | void CWallet::BlockUntilSyncedToCurrentChain() const { | ||||
// queue and wait for the queue to drain enough to execute it (indicating we | // queue and wait for the queue to drain enough to execute it (indicating we | ||||
// are caught up at least with the time we entered this function). | // are caught up at least with the time we entered this function). | ||||
const BlockHash last_block_hash = | const BlockHash last_block_hash = | ||||
WITH_LOCK(cs_wallet, return m_last_block_processed); | WITH_LOCK(cs_wallet, return m_last_block_processed); | ||||
chain().waitForNotificationsIfTipChanged(last_block_hash); | chain().waitForNotificationsIfTipChanged(last_block_hash); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxIn &txin) const { | isminetype CWallet::IsMine(const CTxIn &txin) const { | ||||
LOCK(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
std::map<TxId, CWalletTx>::const_iterator mi = | std::map<TxId, CWalletTx>::const_iterator mi = | ||||
mapWallet.find(txin.prevout.GetTxId()); | mapWallet.find(txin.prevout.GetTxId()); | ||||
if (mi != mapWallet.end()) { | if (mi != mapWallet.end()) { | ||||
const CWalletTx &prev = (*mi).second; | const CWalletTx &prev = (*mi).second; | ||||
if (txin.prevout.GetN() < prev.tx->vout.size()) { | if (txin.prevout.GetN() < prev.tx->vout.size()) { | ||||
return IsMine(prev.tx->vout[txin.prevout.GetN()]); | return IsMine(prev.tx->vout[txin.prevout.GetN()]); | ||||
} | } | ||||
} | } | ||||
Show All 15 Lines | if (mi != mapWallet.end()) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return Amount::zero(); | return Amount::zero(); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxOut &txout) const { | isminetype CWallet::IsMine(const CTxOut &txout) const { | ||||
AssertLockHeld(cs_wallet); | |||||
return IsMine(txout.scriptPubKey); | return IsMine(txout.scriptPubKey); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxDestination &dest) const { | isminetype CWallet::IsMine(const CTxDestination &dest) const { | ||||
AssertLockHeld(cs_wallet); | |||||
return IsMine(GetScriptForDestination(dest)); | return IsMine(GetScriptForDestination(dest)); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CScript &script) const { | isminetype CWallet::IsMine(const CScript &script) const { | ||||
AssertLockHeld(cs_wallet); | |||||
isminetype result = ISMINE_NO; | isminetype result = ISMINE_NO; | ||||
for (const auto &spk_man_pair : m_spk_managers) { | for (const auto &spk_man_pair : m_spk_managers) { | ||||
result = std::max(result, spk_man_pair.second->IsMine(script)); | result = std::max(result, spk_man_pair.second->IsMine(script)); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
Amount CWallet::GetCredit(const CTxOut &txout, | Amount CWallet::GetCredit(const CTxOut &txout, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
if (!MoneyRange(txout.nValue)) { | if (!MoneyRange(txout.nValue)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
LOCK(cs_wallet); | |||||
return (IsMine(txout) & filter) ? txout.nValue : Amount::zero(); | return (IsMine(txout) & filter) ? txout.nValue : Amount::zero(); | ||||
} | } | ||||
bool CWallet::IsChange(const CTxOut &txout) const { | bool CWallet::IsChange(const CTxOut &txout) const { | ||||
return IsChange(txout.scriptPubKey); | return IsChange(txout.scriptPubKey); | ||||
} | } | ||||
bool CWallet::IsChange(const CScript &script) const { | bool CWallet::IsChange(const CScript &script) const { | ||||
// TODO: fix handling of 'change' outputs. The assumption is that any | // TODO: fix handling of 'change' outputs. The assumption is that any | ||||
// payment to a script that is ours, but is not in the address book is | // payment to a script that is ours, but is not in the address book is | ||||
// change. That assumption is likely to break when we implement | // change. That assumption is likely to break when we implement | ||||
// multisignature wallets that return change back into a | // multisignature wallets that return change back into a | ||||
// multi-signature-protected address; a better way of identifying which | // multi-signature-protected address; a better way of identifying which | ||||
// outputs are 'the send' and which are 'the change' will need to be | // outputs are 'the send' and which are 'the change' will need to be | ||||
// implemented (maybe extend CWalletTx to remember which output, if any, was | // implemented (maybe extend CWalletTx to remember which output, if any, was | ||||
// change). | // change). | ||||
LOCK(cs_wallet); | |||||
if (IsMine(script)) { | if (IsMine(script)) { | ||||
CTxDestination address; | CTxDestination address; | ||||
if (!ExtractDestination(script, address)) { | if (!ExtractDestination(script, address)) { | ||||
return true; | return true; | ||||
} | } | ||||
LOCK(cs_wallet); | |||||
if (!FindAddressBookEntry(address)) { | if (!FindAddressBookEntry(address)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
Amount CWallet::GetChange(const CTxOut &txout) const { | Amount CWallet::GetChange(const CTxOut &txout) const { | ||||
if (!MoneyRange(txout.nValue)) { | if (!MoneyRange(txout.nValue)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
return (IsChange(txout) ? txout.nValue : Amount::zero()); | return (IsChange(txout) ? txout.nValue : Amount::zero()); | ||||
} | } | ||||
bool CWallet::IsMine(const CTransaction &tx) const { | bool CWallet::IsMine(const CTransaction &tx) const { | ||||
AssertLockHeld(cs_wallet); | |||||
for (const CTxOut &txout : tx.vout) { | for (const CTxOut &txout : tx.vout) { | ||||
if (IsMine(txout)) { | if (IsMine(txout)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | void CWalletTx::GetAmounts(std::list<COutputEntry> &listReceived, | ||||
// Compute fee: | // Compute fee: | ||||
Amount nDebit = GetDebit(filter); | Amount nDebit = GetDebit(filter); | ||||
// debit>0 means we signed/sent this transaction. | // debit>0 means we signed/sent this transaction. | ||||
if (nDebit > Amount::zero()) { | if (nDebit > Amount::zero()) { | ||||
Amount nValueOut = tx->GetValueOut(); | Amount nValueOut = tx->GetValueOut(); | ||||
nFee = (nDebit - nValueOut); | nFee = (nDebit - nValueOut); | ||||
} | } | ||||
LOCK(pwallet->cs_wallet); | |||||
// Sent/received. | // Sent/received. | ||||
for (unsigned int i = 0; i < tx->vout.size(); ++i) { | for (unsigned int i = 0; i < tx->vout.size(); ++i) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
isminetype fIsMine = pwallet->IsMine(txout); | isminetype fIsMine = pwallet->IsMine(txout); | ||||
// Only need to handle txouts if AT LEAST one of these is true: | // Only need to handle txouts if AT LEAST one of these is true: | ||||
// 1) they debit from us (sent) | // 1) they debit from us (sent) | ||||
// 2) the output is to us (received) | // 2) the output is to us (received) | ||||
if (nDebit > Amount::zero()) { | if (nDebit > Amount::zero()) { | ||||
▲ Show 20 Lines • Show All 1,819 Lines • ▼ Show 20 Lines | DBErrors CWallet::ZapWalletTx(std::list<CWalletTx> &vWtx) { | ||||
return DBErrors::LOAD_OK; | return DBErrors::LOAD_OK; | ||||
} | } | ||||
bool CWallet::SetAddressBookWithDB(WalletBatch &batch, | bool CWallet::SetAddressBookWithDB(WalletBatch &batch, | ||||
const CTxDestination &address, | const CTxDestination &address, | ||||
const std::string &strName, | const std::string &strName, | ||||
const std::string &strPurpose) { | const std::string &strPurpose) { | ||||
bool fUpdated = false; | bool fUpdated = false; | ||||
bool is_mine; | |||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::map<CTxDestination, CAddressBookData>::iterator mi = | std::map<CTxDestination, CAddressBookData>::iterator mi = | ||||
m_address_book.find(address); | m_address_book.find(address); | ||||
fUpdated = (mi != m_address_book.end() && !mi->second.IsChange()); | fUpdated = (mi != m_address_book.end() && !mi->second.IsChange()); | ||||
m_address_book[address].SetLabel(strName); | m_address_book[address].SetLabel(strName); | ||||
// Update purpose only if requested. | // Update purpose only if requested. | ||||
if (!strPurpose.empty()) { | if (!strPurpose.empty()) { | ||||
m_address_book[address].purpose = strPurpose; | m_address_book[address].purpose = strPurpose; | ||||
} | } | ||||
is_mine = IsMine(address) != ISMINE_NO; | |||||
} | } | ||||
NotifyAddressBookChanged(this, address, strName, | NotifyAddressBookChanged(this, address, strName, is_mine, strPurpose, | ||||
IsMine(address) != ISMINE_NO, strPurpose, | |||||
(fUpdated ? CT_UPDATED : CT_NEW)); | (fUpdated ? CT_UPDATED : CT_NEW)); | ||||
if (!strPurpose.empty() && !batch.WritePurpose(address, strPurpose)) { | if (!strPurpose.empty() && !batch.WritePurpose(address, strPurpose)) { | ||||
return false; | return false; | ||||
} | } | ||||
return batch.WriteName(address, strName); | return batch.WriteName(address, strName); | ||||
} | } | ||||
bool CWallet::SetAddressBook(const CTxDestination &address, | bool CWallet::SetAddressBook(const CTxDestination &address, | ||||
const std::string &strName, | const std::string &strName, | ||||
const std::string &strPurpose) { | const std::string &strPurpose) { | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
return SetAddressBookWithDB(batch, address, strName, strPurpose); | return SetAddressBookWithDB(batch, address, strName, strPurpose); | ||||
} | } | ||||
bool CWallet::DelAddressBook(const CTxDestination &address) { | bool CWallet::DelAddressBook(const CTxDestination &address) { | ||||
bool is_mine; | |||||
{ | |||||
LOCK(cs_wallet); | |||||
// If we want to delete receiving addresses, we need to take care that | // If we want to delete receiving addresses, we need to take care that | ||||
// DestData "used" (and possibly newer DestData) gets preserved (and the | // DestData "used" (and possibly newer DestData) gets preserved (and the | ||||
// "deleted" address transformed into a change entry instead of actually | // "deleted" address transformed into a change entry instead of actually | ||||
// being deleted) | // being deleted) | ||||
// NOTE: This isn't a problem for sending addresses because they never have | // NOTE: This isn't a problem for sending addresses because they never | ||||
// any DestData yet! When adding new DestData, it should be considered here | // have any DestData yet! When adding new DestData, it should be | ||||
// whether to retain or delete it (or move it?). | // considered here whether to retain or delete it (or move it?). | ||||
if (IsMine(address)) { | if (IsMine(address)) { | ||||
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please " | WalletLogPrintf( | ||||
"%s called with IsMine address, NOT SUPPORTED. Please " | |||||
"report this bug! %s\n", | "report this bug! %s\n", | ||||
__func__, PACKAGE_BUGREPORT); | __func__, PACKAGE_BUGREPORT); | ||||
return false; | return false; | ||||
} | } | ||||
{ | |||||
LOCK(cs_wallet); | |||||
// Delete destdata tuples associated with address | // Delete destdata tuples associated with address | ||||
for (const std::pair<const std::string, std::string> &item : | for (const std::pair<const std::string, std::string> &item : | ||||
m_address_book[address].destdata) { | m_address_book[address].destdata) { | ||||
WalletBatch(*database).EraseDestData(address, item.first); | WalletBatch(*database).EraseDestData(address, item.first); | ||||
} | } | ||||
m_address_book.erase(address); | m_address_book.erase(address); | ||||
is_mine = IsMine(address) != ISMINE_NO; | |||||
} | } | ||||
NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, | NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED); | ||||
"", CT_DELETED); | |||||
WalletBatch(*database).ErasePurpose(address); | WalletBatch(*database).ErasePurpose(address); | ||||
return WalletBatch(*database).EraseName(address); | return WalletBatch(*database).EraseName(address); | ||||
} | } | ||||
size_t CWallet::KeypoolCountExternalKeys() const { | size_t CWallet::KeypoolCountExternalKeys() const { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
▲ Show 20 Lines • Show All 1,451 Lines • Show Last 20 Lines |