Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,341 Lines • ▼ Show 20 Lines | void CWallet::TransactionAddedToMempool(const CTransactionRef &ptx) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
SyncTransaction(ptx); | SyncTransaction(ptx); | ||||
} | } | ||||
void CWallet::BlockConnected( | void CWallet::BlockConnected( | ||||
const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | ||||
const std::vector<CTransactionRef> &vtxConflicted) { | const std::vector<CTransactionRef> &vtxConflicted) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
// TODO: Tempoarily ensure that mempool removals are notified before | // TODO: Tempoarily ensure that mempool removals are notified before | ||||
// connected transactions. This shouldn't matter, but the abandoned state of | // connected transactions. This shouldn't matter, but the abandoned state of | ||||
// transactions in our wallet is currently cleared when we receive another | // transactions in our wallet is currently cleared when we receive another | ||||
// notification and there is a race condition where notification of a | // notification and there is a race condition where notification of a | ||||
// connected conflict might cause an outside process to abandon a | // connected conflict might cause an outside process to abandon a | ||||
// transaction and then have it inadvertantly cleared by the notification | // transaction and then have it inadvertantly cleared by the notification | ||||
// that the conflicted transaction was evicted. | // that the conflicted transaction was evicted. | ||||
for (const CTransactionRef &ptx : vtxConflicted) { | for (const CTransactionRef &ptx : vtxConflicted) { | ||||
SyncTransaction(ptx); | SyncTransaction(ptx); | ||||
} | } | ||||
for (size_t i = 0; i < pblock->vtx.size(); i++) { | for (size_t i = 0; i < pblock->vtx.size(); i++) { | ||||
SyncTransaction(pblock->vtx[i], pindex, i); | SyncTransaction(pblock->vtx[i], pindex, i); | ||||
} | } | ||||
} | } | ||||
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) { | void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
▲ Show 20 Lines • Show All 462 Lines • ▼ Show 20 Lines | if (pwallet != nullptr) { | ||||
result = pwallet->GetConflicts(myHash); | result = pwallet->GetConflicts(myHash); | ||||
result.erase(myHash); | result.erase(myHash); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
Amount CWalletTx::GetDebit(const isminefilter &filter) const { | Amount CWalletTx::GetDebit(const isminefilter &filter) const { | ||||
if (tx->vin.empty()) return Amount(0); | if (tx->vin.empty()) { | ||||
return Amount(0); | |||||
} | |||||
Amount debit(0); | Amount debit(0); | ||||
if (filter & ISMINE_SPENDABLE) { | if (filter & ISMINE_SPENDABLE) { | ||||
if (fDebitCached) { | if (fDebitCached) { | ||||
debit += nDebitCached; | debit += nDebitCached; | ||||
} else { | } else { | ||||
nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); | nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); | ||||
fDebitCached = true; | fDebitCached = true; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (filter & ISMINE_WATCH_ONLY) { | ||||
} | } | ||||
} | } | ||||
return credit; | return credit; | ||||
} | } | ||||
Amount CWalletTx::GetImmatureCredit(bool fUseCache) const { | Amount CWalletTx::GetImmatureCredit(bool fUseCache) const { | ||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { | if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { | ||||
if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; | if (fUseCache && fImmatureCreditCached) { | ||||
return nImmatureCreditCached; | |||||
} | |||||
nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | ||||
fImmatureCreditCached = true; | fImmatureCreditCached = true; | ||||
return nImmatureCreditCached; | return nImmatureCreditCached; | ||||
} | } | ||||
return Amount(0); | return Amount(0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | bool CWalletTx::IsTrusted() const { | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWalletTx::IsEquivalentTo(const CWalletTx &_tx) const { | bool CWalletTx::IsEquivalentTo(const CWalletTx &_tx) const { | ||||
CMutableTransaction tx1 = *this->tx; | CMutableTransaction tx1 = *this->tx; | ||||
CMutableTransaction tx2 = *_tx.tx; | CMutableTransaction tx2 = *_tx.tx; | ||||
for (unsigned int i = 0; i < tx1.vin.size(); i++) { | for (CTxIn &in : tx1.vin) { | ||||
tx1.vin[i].scriptSig = CScript(); | in.scriptSig = CScript(); | ||||
} | } | ||||
for (unsigned int i = 0; i < tx2.vin.size(); i++) { | for (CTxIn &in : tx2.vin) { | ||||
tx2.vin[i].scriptSig = CScript(); | in.scriptSig = CScript(); | ||||
} | } | ||||
return CTransaction(tx1) == CTransaction(tx2); | return CTransaction(tx1) == CTransaction(tx2); | ||||
} | } | ||||
std::vector<uint256> | std::vector<uint256> | ||||
CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman *connman) { | CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman *connman) { | ||||
std::vector<uint256> result; | std::vector<uint256> result; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
* @defgroup Actions | * @defgroup Actions | ||||
* | * | ||||
* @{ | * @{ | ||||
*/ | */ | ||||
Amount CWallet::GetBalance() const { | Amount CWallet::GetBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
if (pcoin->IsTrusted()) { | if (pcoin->IsTrusted()) { | ||||
nTotal += pcoin->GetAvailableCredit(); | nTotal += pcoin->GetAvailableCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedBalance() const { | Amount CWallet::GetUnconfirmedBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | ||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableCredit(); | nTotal += pcoin->GetAvailableCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureBalance() const { | Amount CWallet::GetImmatureBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
nTotal += pcoin->GetImmatureCredit(); | nTotal += pcoin->GetImmatureCredit(); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetWatchOnlyBalance() const { | Amount CWallet::GetWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
if (pcoin->IsTrusted()) { | if (pcoin->IsTrusted()) { | ||||
nTotal += pcoin->GetAvailableWatchOnlyCredit(); | nTotal += pcoin->GetAvailableWatchOnlyCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | ||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableWatchOnlyCredit(); | nTotal += pcoin->GetAvailableWatchOnlyCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureWatchOnlyBalance() const { | Amount CWallet::GetImmatureWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal(0); | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (const std::pair<uint256, CWalletTx> &p : mapWallet) { | ||||
it != mapWallet.end(); ++it) { | const CWalletTx *pcoin = &p.second; | ||||
const CWalletTx *pcoin = &(*it).second; | |||||
nTotal += pcoin->GetImmatureWatchOnlyCredit(); | nTotal += pcoin->GetImmatureWatchOnlyCredit(); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
// Calculate total balance in a different way from GetBalance. The biggest | // Calculate total balance in a different way from GetBalance. The biggest | ||||
// difference is that GetBalance sums up all unspent TxOuts paying to the | // difference is that GetBalance sums up all unspent TxOuts paying to the | ||||
▲ Show 20 Lines • Show All 579 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
Amount nCredit = pcoin.first->tx->vout[pcoin.second].nValue; | Amount nCredit = pcoin.first->tx->vout[pcoin.second].nValue; | ||||
// The coin age after the next block (depth+1) is used instead | // The coin age after the next block (depth+1) is used instead | ||||
// of the current, reflecting an assumption the user would | // of the current, reflecting an assumption the user would | ||||
// accept a bit more delay for a chance at a free transaction. | // accept a bit more delay for a chance at a free transaction. | ||||
// But mempool inputs might still be in the mempool, so their | // But mempool inputs might still be in the mempool, so their | ||||
// age stays 0. | // age stays 0. | ||||
int age = pcoin.first->GetDepthInMainChain(); | int age = pcoin.first->GetDepthInMainChain(); | ||||
assert(age >= 0); | assert(age >= 0); | ||||
if (age != 0) age += 1; | if (age != 0) { | ||||
dPriority += (double)nCredit.GetSatoshis() * age; | age += 1; | ||||
} | |||||
dPriority += age * nCredit.GetSatoshis(); | |||||
} | } | ||||
const Amount nChange = nValueIn - nValueToSelect; | const Amount nChange = nValueIn - nValueToSelect; | ||||
if (nChange > Amount(0)) { | if (nChange > Amount(0)) { | ||||
// Fill a vout to ourself. | // Fill a vout to ourself. | ||||
// TODO: pass in scriptChange instead of reservekey so change | // TODO: pass in scriptChange instead of reservekey so change | ||||
// transaction isn't always pay-to-bitcoin-address. | // transaction isn't always pay-to-bitcoin-address. | ||||
CScript scriptChange; | CScript scriptChange; | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
if (!ProduceSignature( | if (!ProduceSignature( | ||||
TransactionSignatureCreator( | TransactionSignatureCreator( | ||||
this, &txNewConst, nIn, | this, &txNewConst, nIn, | ||||
coin.first->tx->vout[coin.second].nValue, | coin.first->tx->vout[coin.second].nValue, | ||||
sigHashType), | sigHashType), | ||||
scriptPubKey, sigdata)) { | scriptPubKey, sigdata)) { | ||||
strFailReason = _("Signing transaction failed"); | strFailReason = _("Signing transaction failed"); | ||||
return false; | return false; | ||||
} else { | |||||
UpdateTransaction(txNew, nIn, sigdata); | |||||
} | } | ||||
UpdateTransaction(txNew, nIn, sigdata); | |||||
nIn++; | nIn++; | ||||
} | } | ||||
} | } | ||||
// Embed the constructed transaction data in wtxNew. | // Embed the constructed transaction data in wtxNew. | ||||
wtxNew.SetTx(MakeTransactionRef(std::move(txNew))); | wtxNew.SetTx(MakeTransactionRef(std::move(txNew))); | ||||
// Limit size. | // Limit size. | ||||
▲ Show 20 Lines • Show All 545 Lines • ▼ Show 20 Lines | for (std::pair<uint256, CWalletTx> walletEntry : mapWallet) { | ||||
if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | ||||
continue; | continue; | ||||
} | } | ||||
Amount n = IsSpent(walletEntry.first, i) | Amount n = IsSpent(walletEntry.first, i) | ||||
? Amount(0) | ? Amount(0) | ||||
: pcoin->tx->vout[i].nValue; | : pcoin->tx->vout[i].nValue; | ||||
if (!balances.count(addr)) balances[addr] = Amount(0); | if (!balances.count(addr)) { | ||||
balances[addr] = Amount(0); | |||||
} | |||||
balances[addr] += n; | balances[addr] += n; | ||||
} | } | ||||
} | } | ||||
return balances; | return balances; | ||||
} | } | ||||
std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | ||||
std::set<std::set<CTxDestination> *> uniqueGroupings; | std::set<std::set<CTxDestination> *> uniqueGroupings; | ||||
// Map addresses to the unique group containing it. | // Map addresses to the unique group containing it. | ||||
std::map<CTxDestination, std::set<CTxDestination> *> setmap; | std::map<CTxDestination, std::set<CTxDestination> *> setmap; | ||||
for (std::set<CTxDestination> _grouping : groupings) { | for (std::set<CTxDestination> _grouping : groupings) { | ||||
// Make a set of all the groups hit by this new group. | // Make a set of all the groups hit by this new group. | ||||
std::set<std::set<CTxDestination> *> hits; | std::set<std::set<CTxDestination> *> hits; | ||||
std::map<CTxDestination, std::set<CTxDestination> *>::iterator it; | std::map<CTxDestination, std::set<CTxDestination> *>::iterator it; | ||||
for (CTxDestination address : _grouping) { | for (CTxDestination address : _grouping) { | ||||
if ((it = setmap.find(address)) != setmap.end()) | if ((it = setmap.find(address)) != setmap.end()) { | ||||
hits.insert((*it).second); | hits.insert((*it).second); | ||||
} | } | ||||
} | |||||
// Merge all hit groups into a new single group and delete old groups. | // Merge all hit groups into a new single group and delete old groups. | ||||
std::set<CTxDestination> *merged = | std::set<CTxDestination> *merged = | ||||
new std::set<CTxDestination>(_grouping); | new std::set<CTxDestination>(_grouping); | ||||
for (std::set<CTxDestination> *hit : hits) { | for (std::set<CTxDestination> *hit : hits) { | ||||
merged->insert(hit->begin(), hit->end()); | merged->insert(hit->begin(), hit->end()); | ||||
uniqueGroupings.erase(hit); | uniqueGroupings.erase(hit); | ||||
delete hit; | delete hit; | ||||
Show All 30 Lines | CWallet::GetAccountAddresses(const std::string &strAccount) const { | ||||
return result; | return result; | ||||
} | } | ||||
bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) { | bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) { | ||||
if (nIndex == -1) { | if (nIndex == -1) { | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal); | pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal); | ||||
if (nIndex != -1) { | if (nIndex == -1) { | ||||
vchPubKey = keypool.vchPubKey; | |||||
} else { | |||||
return false; | return false; | ||||
} | } | ||||
vchPubKey = keypool.vchPubKey; | |||||
fInternal = keypool.fInternal; | fInternal = keypool.fInternal; | ||||
} | } | ||||
assert(vchPubKey.IsValid()); | assert(vchPubKey.IsValid()); | ||||
pubkey = vchPubKey; | pubkey = vchPubKey; | ||||
return true; | return true; | ||||
} | } | ||||
Show All 12 Lines | void CReserveKey::ReturnKey() { | ||||
} | } | ||||
nIndex = -1; | nIndex = -1; | ||||
vchPubKey = CPubKey(); | vchPubKey = CPubKey(); | ||||
} | } | ||||
void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) { | void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
bool internal = setInternalKeyPool.count(keypool_id); | bool internal = setInternalKeyPool.count(keypool_id); | ||||
if (!internal) assert(setExternalKeyPool.count(keypool_id)); | if (!internal) { | ||||
assert(setExternalKeyPool.count(keypool_id)); | |||||
} | |||||
std::set<int64_t> *setKeyPool = | std::set<int64_t> *setKeyPool = | ||||
internal ? &setInternalKeyPool : &setExternalKeyPool; | internal ? &setInternalKeyPool : &setExternalKeyPool; | ||||
auto it = setKeyPool->begin(); | auto it = setKeyPool->begin(); | ||||
CWalletDB walletdb(*dbw); | CWalletDB walletdb(*dbw); | ||||
while (it != std::end(*setKeyPool)) { | while (it != std::end(*setKeyPool)) { | ||||
const int64_t &index = *(it); | const int64_t &index = *(it); | ||||
if (index > keypool_id) { | if (index > keypool_id) { | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const { | ||||
COutPoint outpt(hash, n); | COutPoint outpt(hash, n); | ||||
return setLockedCoins.count(outpt) > 0; | return setLockedCoins.count(outpt) > 0; | ||||
} | } | ||||
void CWallet::ListLockedCoins(std::vector<COutPoint> &vOutpts) { | void CWallet::ListLockedCoins(std::vector<COutPoint> &vOutpts) { | ||||
// setLockedCoins | // setLockedCoins | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); | for (COutPoint outpoint : setLockedCoins) { | ||||
it != setLockedCoins.end(); it++) { | vOutpts.push_back(outpoint); | ||||
COutPoint outpt = (*it); | |||||
vOutpts.push_back(outpt); | |||||
} | } | ||||
} | } | ||||
/** @} */ // end of Actions | /** @} */ // end of Actions | ||||
void CWallet::GetKeyBirthTimes( | void CWallet::GetKeyBirthTimes( | ||||
std::map<CTxDestination, int64_t> &mapKeyBirth) const { | std::map<CTxDestination, int64_t> &mapKeyBirth) const { | ||||
// mapKeyMetadata | // mapKeyMetadata | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
} | } | ||||
} | } | ||||
vAffected.clear(); | vAffected.clear(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Extract block timestamps for those keys. | // Extract block timestamps for those keys. | ||||
for (std::map<CKeyID, CBlockIndex *>::const_iterator it = | for (const std::pair<CKeyID, CBlockIndex *> &p : mapKeyFirstBlock) { | ||||
mapKeyFirstBlock.begin(); | |||||
it != mapKeyFirstBlock.end(); it++) { | |||||
// Block times can be 2h off. | // Block times can be 2h off. | ||||
mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; | mapKeyBirth[p.first] = p.second->GetBlockTime() - TIMESTAMP_WINDOW; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Compute smart timestamp for a transaction being added to the wallet. | * Compute smart timestamp for a transaction being added to the wallet. | ||||
* | * | ||||
* Logic: | * Logic: | ||||
* - If sending a transaction, assign its timestamp to the current time. | * - If sending a transaction, assign its timestamp to the current time. | ||||
▲ Show 20 Lines • Show All 660 Lines • Show Last 20 Lines |