Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 666 Lines • ▼ Show 20 Lines | for (TxSpends::iterator it = range.first; it != range.second; ++it) { | ||||
copyTo->strFromAccount = copyFrom->strFromAccount; | copyTo->strFromAccount = copyFrom->strFromAccount; | ||||
// nOrderPos not copied on purpose cached members not copied on purpose. | // nOrderPos not copied on purpose cached members not copied on purpose. | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Outpoint is spent if any non-conflicted transaction, spends it: | * Outpoint is spent if any non-conflicted transaction, spends it: | ||||
*/ | */ | ||||
bool CWallet::IsSpent(const COutPoint &outpoint) const { | bool CWallet::IsSpent(interfaces::Chain::Lock &locked_chain, | ||||
const COutPoint &outpoint) const { | |||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = | std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = | ||||
mapTxSpends.equal_range(outpoint); | mapTxSpends.equal_range(outpoint); | ||||
for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { | for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { | ||||
const TxId &wtxid = it->second; | const TxId &wtxid = it->second; | ||||
std::map<TxId, CWalletTx>::const_iterator mit = mapWallet.find(wtxid); | std::map<TxId, CWalletTx>::const_iterator mit = mapWallet.find(wtxid); | ||||
if (mit != mapWallet.end()) { | if (mit != mapWallet.end()) { | ||||
int depth = mit->second.GetDepthInMainChain(); | int depth = mit->second.GetDepthInMainChain(locked_chain); | ||||
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) { | if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) { | ||||
// Spent | // Spent | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 474 Lines • ▼ Show 20 Lines | bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef &ptx, | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::TransactionCanBeAbandoned(const TxId &txid) const { | bool CWallet::TransactionCanBeAbandoned(const TxId &txid) const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
const CWalletTx *wtx = GetWalletTx(txid); | const CWalletTx *wtx = GetWalletTx(txid); | ||||
return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && | return wtx && !wtx->isAbandoned() && | ||||
!wtx->InMempool(); | wtx->GetDepthInMainChain(*locked_chain) == 0 && !wtx->InMempool(); | ||||
} | } | ||||
void CWallet::MarkInputsDirty(const CTransactionRef &tx) { | void CWallet::MarkInputsDirty(const CTransactionRef &tx) { | ||||
for (const CTxIn &txin : tx->vin) { | for (const CTxIn &txin : tx->vin) { | ||||
auto it = mapWallet.find(txin.prevout.GetTxId()); | auto it = mapWallet.find(txin.prevout.GetTxId()); | ||||
if (it != mapWallet.end()) { | if (it != mapWallet.end()) { | ||||
it->second.MarkDirty(); | it->second.MarkDirty(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
bool CWallet::AbandonTransaction(const TxId &txid) { | bool CWallet::AbandonTransaction(interfaces::Chain::Lock &locked_chain, | ||||
const TxId &txid) { | |||||
// Temporary. Removed in upcoming lock cleanup | // Temporary. Removed in upcoming lock cleanup | ||||
auto locked_chain_recursive = chain().lock(); | auto locked_chain_recursive = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
WalletBatch batch(*database, "r+"); | WalletBatch batch(*database, "r+"); | ||||
std::set<TxId> todo; | std::set<TxId> todo; | ||||
std::set<TxId> done; | std::set<TxId> done; | ||||
// Can't mark abandoned if confirmed or in mempool | // Can't mark abandoned if confirmed or in mempool | ||||
auto it = mapWallet.find(txid); | auto it = mapWallet.find(txid); | ||||
assert(it != mapWallet.end()); | assert(it != mapWallet.end()); | ||||
CWalletTx &origtx = it->second; | CWalletTx &origtx = it->second; | ||||
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) { | if (origtx.GetDepthInMainChain(locked_chain) != 0 || origtx.InMempool()) { | ||||
return false; | return false; | ||||
} | } | ||||
todo.insert(txid); | todo.insert(txid); | ||||
while (!todo.empty()) { | while (!todo.empty()) { | ||||
const TxId now = *todo.begin(); | const TxId now = *todo.begin(); | ||||
todo.erase(now); | todo.erase(now); | ||||
done.insert(now); | done.insert(now); | ||||
it = mapWallet.find(now); | it = mapWallet.find(now); | ||||
assert(it != mapWallet.end()); | assert(it != mapWallet.end()); | ||||
CWalletTx &wtx = it->second; | CWalletTx &wtx = it->second; | ||||
int currentconfirm = wtx.GetDepthInMainChain(); | int currentconfirm = wtx.GetDepthInMainChain(locked_chain); | ||||
// If the orig tx was not in block, none of its spends can be. | // If the orig tx was not in block, none of its spends can be. | ||||
assert(currentconfirm <= 0); | assert(currentconfirm <= 0); | ||||
// If (currentconfirm < 0) {Tx and spends are already conflicted, no | // If (currentconfirm < 0) {Tx and spends are already conflicted, no | ||||
// need to abandon} | // need to abandon} | ||||
if (currentconfirm == 0 && !wtx.isAbandoned()) { | if (currentconfirm == 0 && !wtx.isAbandoned()) { | ||||
// If the orig tx was not in block/mempool, none of its spends can | // If the orig tx was not in block/mempool, none of its spends can | ||||
// be in mempool. | // be in mempool. | ||||
assert(!wtx.InMempool()); | assert(!wtx.InMempool()); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | void CWallet::MarkConflicted(const BlockHash &hashBlock, const TxId &txid) { | ||||
while (!todo.empty()) { | while (!todo.empty()) { | ||||
const TxId now = *todo.begin(); | const TxId now = *todo.begin(); | ||||
todo.erase(now); | todo.erase(now); | ||||
done.insert(now); | done.insert(now); | ||||
auto it = mapWallet.find(now); | auto it = mapWallet.find(now); | ||||
assert(it != mapWallet.end()); | assert(it != mapWallet.end()); | ||||
CWalletTx &wtx = it->second; | CWalletTx &wtx = it->second; | ||||
int currentconfirm = wtx.GetDepthInMainChain(); | int currentconfirm = wtx.GetDepthInMainChain(*locked_chain); | ||||
if (conflictconfirms < currentconfirm) { | if (conflictconfirms < currentconfirm) { | ||||
// Block is 'more conflicted' than current confirm; update. | // Block is 'more conflicted' than current confirm; update. | ||||
// Mark transaction as conflicted with this block. | // Mark transaction as conflicted with this block. | ||||
wtx.nIndex = -1; | wtx.nIndex = -1; | ||||
wtx.hashBlock = hashBlock; | wtx.hashBlock = hashBlock; | ||||
wtx.MarkDirty(); | wtx.MarkDirty(); | ||||
batch.WriteTx(wtx); | batch.WriteTx(wtx); | ||||
// Iterate over all its outputs, and mark transactions in the wallet | // Iterate over all its outputs, and mark transactions in the wallet | ||||
▲ Show 20 Lines • Show All 706 Lines • ▼ Show 20 Lines | void CWallet::ReacceptWalletTransactions() { | ||||
// Sort pending wallet transactions based on their initial wallet insertion | // Sort pending wallet transactions based on their initial wallet insertion | ||||
// order. | // order. | ||||
for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | ||||
const TxId &wtxid = item.first; | const TxId &wtxid = item.first; | ||||
CWalletTx &wtx = item.second; | CWalletTx &wtx = item.second; | ||||
assert(wtx.GetId() == wtxid); | assert(wtx.GetId() == wtxid); | ||||
int nDepth = wtx.GetDepthInMainChain(); | int nDepth = wtx.GetDepthInMainChain(*locked_chain); | ||||
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) { | if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) { | ||||
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); | mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); | ||||
} | } | ||||
} | } | ||||
// Try to add wallet transactions to memory pool. | // Try to add wallet transactions to memory pool. | ||||
for (const std::pair<const int64_t, CWalletTx *> &item : mapSorted) { | for (const std::pair<const int64_t, CWalletTx *> &item : mapSorted) { | ||||
CWalletTx &wtx = *(item.second); | CWalletTx &wtx = *(item.second); | ||||
CValidationState state; | CValidationState state; | ||||
wtx.AcceptToMemoryPool(maxTxFee, state); | wtx.AcceptToMemoryPool(*locked_chain, maxTxFee, state); | ||||
} | } | ||||
} | } | ||||
bool CWalletTx::RelayWalletTransaction(CConnman *connman) { | bool CWalletTx::RelayWalletTransaction(interfaces::Chain::Lock &locked_chain, | ||||
CConnman *connman) { | |||||
assert(pwallet->GetBroadcastTransactions()); | assert(pwallet->GetBroadcastTransactions()); | ||||
if (IsCoinBase() || isAbandoned() || GetDepthInMainChain() != 0) { | if (IsCoinBase() || isAbandoned() || | ||||
GetDepthInMainChain(locked_chain) != 0) { | |||||
return false; | return false; | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
// GetDepthInMainChain already catches known conflicts. | // GetDepthInMainChain already catches known conflicts. | ||||
if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) { | if (InMempool() || AcceptToMemoryPool(locked_chain, maxTxFee, state)) { | ||||
pwallet->WalletLogPrintf("Relaying wtx %s\n", GetId().ToString()); | pwallet->WalletLogPrintf("Relaying wtx %s\n", GetId().ToString()); | ||||
if (connman) { | if (connman) { | ||||
CInv inv(MSG_TX, GetId()); | CInv inv(MSG_TX, GetId()); | ||||
connman->ForEachNode( | connman->ForEachNode( | ||||
[&inv](CNode *pnode) { pnode->PushInventory(inv); }); | [&inv](CNode *pnode) { pnode->PushInventory(inv); }); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
Show All 36 Lines | if (filter & ISMINE_WATCH_ONLY) { | ||||
fWatchDebitCached = true; | fWatchDebitCached = true; | ||||
debit += Amount(nWatchDebitCached); | debit += Amount(nWatchDebitCached); | ||||
} | } | ||||
} | } | ||||
return debit; | return debit; | ||||
} | } | ||||
Amount CWalletTx::GetCredit(const isminefilter &filter) const { | Amount CWalletTx::GetCredit(interfaces::Chain::Lock &locked_chain, | ||||
const isminefilter &filter) const { | |||||
// Must wait until coinbase is safely deep enough in the chain before | // Must wait until coinbase is safely deep enough in the chain before | ||||
// valuing it. | // valuing it. | ||||
if (IsImmatureCoinBase()) { | if (IsImmatureCoinBase(locked_chain)) { | ||||
return Amount::zero(); | return Amount::zero(); | ||||
} | } | ||||
Amount credit = Amount::zero(); | Amount credit = Amount::zero(); | ||||
if (filter & ISMINE_SPENDABLE) { | if (filter & ISMINE_SPENDABLE) { | ||||
// GetBalance can assume transactions in mapWallet won't change. | // GetBalance can assume transactions in mapWallet won't change. | ||||
if (fCreditCached) { | if (fCreditCached) { | ||||
credit += nCreditCached; | credit += nCreditCached; | ||||
Show All 12 Lines | if (filter & ISMINE_WATCH_ONLY) { | ||||
fWatchCreditCached = true; | fWatchCreditCached = true; | ||||
credit += nWatchCreditCached; | credit += nWatchCreditCached; | ||||
} | } | ||||
} | } | ||||
return credit; | return credit; | ||||
} | } | ||||
Amount CWalletTx::GetImmatureCredit(bool fUseCache) const { | Amount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock &locked_chain, | ||||
if (IsImmatureCoinBase() && IsInMainChain()) { | bool fUseCache) const { | ||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) { | |||||
if (fUseCache && fImmatureCreditCached) { | if (fUseCache && fImmatureCreditCached) { | ||||
return nImmatureCreditCached; | return nImmatureCreditCached; | ||||
} | } | ||||
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE); | nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE); | ||||
fImmatureCreditCached = true; | fImmatureCreditCached = true; | ||||
return nImmatureCreditCached; | return nImmatureCreditCached; | ||||
} | } | ||||
return Amount::zero(); | return Amount::zero(); | ||||
} | } | ||||
Amount CWalletTx::GetAvailableCredit(bool fUseCache, | Amount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock &locked_chain, | ||||
bool fUseCache, | |||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
if (pwallet == nullptr) { | if (pwallet == nullptr) { | ||||
return Amount::zero(); | return Amount::zero(); | ||||
} | } | ||||
// Must wait until coinbase is safely deep enough in the chain before | // Must wait until coinbase is safely deep enough in the chain before | ||||
// valuing it. | // valuing it. | ||||
if (IsImmatureCoinBase()) { | if (IsImmatureCoinBase(locked_chain)) { | ||||
return Amount::zero(); | return Amount::zero(); | ||||
} | } | ||||
Amount *cache = nullptr; | Amount *cache = nullptr; | ||||
bool *cache_used = nullptr; | bool *cache_used = nullptr; | ||||
if (filter == ISMINE_SPENDABLE) { | if (filter == ISMINE_SPENDABLE) { | ||||
cache = &nAvailableCreditCached; | cache = &nAvailableCreditCached; | ||||
cache_used = &fAvailableCreditCached; | cache_used = &fAvailableCreditCached; | ||||
} else if (filter == ISMINE_WATCH_ONLY) { | } else if (filter == ISMINE_WATCH_ONLY) { | ||||
cache = &nAvailableWatchCreditCached; | cache = &nAvailableWatchCreditCached; | ||||
cache_used = &fAvailableWatchCreditCached; | cache_used = &fAvailableWatchCreditCached; | ||||
} | } | ||||
if (fUseCache && cache_used && *cache_used) { | if (fUseCache && cache_used && *cache_used) { | ||||
return *cache; | return *cache; | ||||
} | } | ||||
Amount nCredit = Amount::zero(); | Amount nCredit = Amount::zero(); | ||||
const TxId &txid = GetId(); | const TxId &txid = GetId(); | ||||
for (uint32_t i = 0; i < tx->vout.size(); i++) { | for (uint32_t i = 0; i < tx->vout.size(); i++) { | ||||
if (!pwallet->IsSpent(COutPoint(txid, i))) { | if (!pwallet->IsSpent(locked_chain, COutPoint(txid, i))) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
nCredit += pwallet->GetCredit(txout, filter); | nCredit += pwallet->GetCredit(txout, filter); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
" : value out of range"); | " : value out of range"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (cache) { | if (cache) { | ||||
*cache = nCredit; | *cache = nCredit; | ||||
*cache_used = true; | *cache_used = true; | ||||
} | } | ||||
return nCredit; | return nCredit; | ||||
} | } | ||||
Amount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const { | Amount | ||||
if (IsImmatureCoinBase() && IsInMainChain()) { | CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock &locked_chain, | ||||
const bool fUseCache) const { | |||||
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) { | |||||
if (fUseCache && fImmatureWatchCreditCached) { | if (fUseCache && fImmatureWatchCreditCached) { | ||||
return nImmatureWatchCreditCached; | return nImmatureWatchCreditCached; | ||||
} | } | ||||
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY); | nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY); | ||||
fImmatureWatchCreditCached = true; | fImmatureWatchCreditCached = true; | ||||
return nImmatureWatchCreditCached; | return nImmatureWatchCreditCached; | ||||
} | } | ||||
Show All 10 Lines | Amount CWalletTx::GetChange() const { | ||||
fChangeCached = true; | fChangeCached = true; | ||||
return nChangeCached; | return nChangeCached; | ||||
} | } | ||||
bool CWalletTx::InMempool() const { | bool CWalletTx::InMempool() const { | ||||
return fInMempool; | return fInMempool; | ||||
} | } | ||||
bool CWalletTx::IsTrusted() const { | bool CWalletTx::IsTrusted(interfaces::Chain::Lock &locked_chain) const { | ||||
// Temporary, for CheckFinalTx below. Removed in upcoming commit. | |||||
LockAnnotation lock(::cs_main); | |||||
// Quick answer in most cases | // Quick answer in most cases | ||||
if (!CheckFinalTx(*tx)) { | if (!CheckFinalTx(*tx)) { | ||||
return false; | return false; | ||||
} | } | ||||
int nDepth = GetDepthInMainChain(); | int nDepth = GetDepthInMainChain(locked_chain); | ||||
if (nDepth >= 1) { | if (nDepth >= 1) { | ||||
return true; | return true; | ||||
} | } | ||||
if (nDepth < 0) { | if (nDepth < 0) { | ||||
return false; | return false; | ||||
} | } | ||||
Show All 35 Lines | bool CWalletTx::IsEquivalentTo(const CWalletTx &_tx) const { | ||||
for (auto &txin : tx2.vin) { | for (auto &txin : tx2.vin) { | ||||
txin.scriptSig = CScript(); | txin.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(interfaces::Chain::Lock &locked_chain, | ||||
int64_t nTime, CConnman *connman) { | |||||
std::vector<uint256> result; | std::vector<uint256> result; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Sort them in chronological order | // Sort them in chronological order | ||||
std::multimap<unsigned int, CWalletTx *> mapSorted; | std::multimap<unsigned int, CWalletTx *> mapSorted; | ||||
for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | ||||
CWalletTx &wtx = item.second; | CWalletTx &wtx = item.second; | ||||
// Don't rebroadcast if newer than nTime: | // Don't rebroadcast if newer than nTime: | ||||
if (wtx.nTimeReceived > nTime) { | if (wtx.nTimeReceived > nTime) { | ||||
continue; | continue; | ||||
} | } | ||||
mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); | mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); | ||||
} | } | ||||
for (const std::pair<const unsigned int, CWalletTx *> &item : mapSorted) { | for (const std::pair<const unsigned int, CWalletTx *> &item : mapSorted) { | ||||
CWalletTx &wtx = *item.second; | CWalletTx &wtx = *item.second; | ||||
if (wtx.RelayWalletTransaction(connman)) { | if (wtx.RelayWalletTransaction(locked_chain, connman)) { | ||||
result.push_back(wtx.GetId()); | result.push_back(wtx.GetId()); | ||||
} | } | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | ||||
Show All 16 Lines | void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | ||||
} | } | ||||
nLastResend = GetTime(); | nLastResend = GetTime(); | ||||
// Temporary. Removed in upcoming lock cleanup | // Temporary. Removed in upcoming lock cleanup | ||||
auto locked_chain = chain().assumeLocked(); | auto locked_chain = chain().assumeLocked(); | ||||
// Rebroadcast unconfirmed txes older than 5 minutes before the last block | // Rebroadcast unconfirmed txes older than 5 minutes before the last block | ||||
// was found: | // was found: | ||||
std::vector<uint256> relayed = | std::vector<uint256> relayed = ResendWalletTransactionsBefore( | ||||
ResendWalletTransactionsBefore(nBestBlockTime - 5 * 60, connman); | *locked_chain, nBestBlockTime - 5 * 60, connman); | ||||
if (!relayed.empty()) { | if (!relayed.empty()) { | ||||
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", | WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", | ||||
__func__, relayed.size()); | __func__, relayed.size()); | ||||
} | } | ||||
} | } | ||||
/** @} */ // end of mapWallet | /** @} */ // end of mapWallet | ||||
/** | /** | ||||
* @defgroup Actions | * @defgroup Actions | ||||
* | * | ||||
* @{ | * @{ | ||||
*/ | */ | ||||
Amount CWallet::GetBalance(const isminefilter &filter, | Amount CWallet::GetBalance(const isminefilter &filter, | ||||
const int min_depth) const { | const int min_depth) const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() >= min_depth) { | if (pcoin->IsTrusted(*locked_chain) && | ||||
nTotal += pcoin->GetAvailableCredit(true, filter); | pcoin->GetDepthInMainChain(*locked_chain) >= min_depth) { | ||||
nTotal += pcoin->GetAvailableCredit(*locked_chain, true, filter); | |||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedBalance() const { | Amount CWallet::GetUnconfirmedBalance() const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted(*locked_chain) && | ||||
pcoin->GetDepthInMainChain(*locked_chain) == 0 && | |||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableCredit(); | nTotal += pcoin->GetAvailableCredit(*locked_chain); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureBalance() const { | Amount CWallet::GetImmatureBalance() const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
nTotal += pcoin->GetImmatureCredit(); | nTotal += pcoin->GetImmatureCredit(*locked_chain); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted(*locked_chain) && | ||||
pcoin->GetDepthInMainChain(*locked_chain) == 0 && | |||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableCredit(true, ISMINE_WATCH_ONLY); | nTotal += pcoin->GetAvailableCredit(*locked_chain, true, | ||||
ISMINE_WATCH_ONLY); | |||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureWatchOnlyBalance() const { | Amount CWallet::GetImmatureWatchOnlyBalance() const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
nTotal += pcoin->GetImmatureWatchOnlyCredit(); | nTotal += pcoin->GetImmatureWatchOnlyCredit(*locked_chain); | ||||
} | } | ||||
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 | ||||
// wallet, while this sums up both spent and unspent TxOuts paying to the | // wallet, while this sums up both spent and unspent TxOuts paying to the | ||||
// wallet, and then subtracts the values of TxIns spending from the wallet. This | // wallet, and then subtracts the values of TxIns spending from the wallet. This | ||||
// also has fewer restrictions on which unconfirmed transactions are considered | // also has fewer restrictions on which unconfirmed transactions are considered | ||||
// trusted. | // trusted. | ||||
Amount CWallet::GetLegacyBalance(const isminefilter &filter, int minDepth, | Amount CWallet::GetLegacyBalance(const isminefilter &filter, int minDepth, | ||||
const std::string *account) const { | const std::string *account) const { | ||||
// Temporary, for CheckFinalTx below. Removed in upcoming commit. | |||||
LockAnnotation lock(::cs_main); | |||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount balance = Amount::zero(); | Amount balance = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const CWalletTx &wtx = entry.second; | const CWalletTx &wtx = entry.second; | ||||
const int depth = wtx.GetDepthInMainChain(); | const int depth = wtx.GetDepthInMainChain(*locked_chain); | ||||
if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) { | if (depth < 0 || !CheckFinalTx(*wtx.tx) || | ||||
wtx.IsImmatureCoinBase(*locked_chain)) { | |||||
continue; | continue; | ||||
} | } | ||||
// Loop through tx outputs and add incoming payments. For outgoing txs, | // Loop through tx outputs and add incoming payments. For outgoing txs, | ||||
// treat change outputs specially, as part of the amount debited. | // treat change outputs specially, as part of the amount debited. | ||||
Amount debit = wtx.GetDebit(filter); | Amount debit = wtx.GetDebit(filter); | ||||
const bool outgoing = debit > Amount::zero(); | const bool outgoing = debit > Amount::zero(); | ||||
for (const CTxOut &out : wtx.tx->vout) { | for (const CTxOut &out : wtx.tx->vout) { | ||||
Show All 20 Lines | |||||
} | } | ||||
Amount CWallet::GetAvailableBalance(const CCoinControl *coinControl) const { | Amount CWallet::GetAvailableBalance(const CCoinControl *coinControl) const { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
Amount balance = Amount::zero(); | Amount balance = Amount::zero(); | ||||
std::vector<COutput> vCoins; | std::vector<COutput> vCoins; | ||||
AvailableCoins(vCoins, true, coinControl); | AvailableCoins(*locked_chain, vCoins, true, coinControl); | ||||
for (const COutput &out : vCoins) { | for (const COutput &out : vCoins) { | ||||
if (out.fSpendable) { | if (out.fSpendable) { | ||||
balance += out.tx->tx->vout[out.i].nValue; | balance += out.tx->tx->vout[out.i].nValue; | ||||
} | } | ||||
} | } | ||||
return balance; | return balance; | ||||
} | } | ||||
void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, | void CWallet::AvailableCoins(interfaces::Chain::Lock &locked_chain, | ||||
std::vector<COutput> &vCoins, bool fOnlySafe, | |||||
const CCoinControl *coinControl, | const CCoinControl *coinControl, | ||||
const Amount nMinimumAmount, | const Amount nMinimumAmount, | ||||
const Amount nMaximumAmount, | const Amount nMaximumAmount, | ||||
const Amount nMinimumSumAmount, | const Amount nMinimumSumAmount, | ||||
const uint64_t nMaximumCount, const int nMinDepth, | const uint64_t nMaximumCount, const int nMinDepth, | ||||
const int nMaxDepth) const { | const int nMaxDepth) const { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
vCoins.clear(); | vCoins.clear(); | ||||
Amount nTotal = Amount::zero(); | Amount nTotal = Amount::zero(); | ||||
for (const auto &entry : mapWallet) { | for (const auto &entry : mapWallet) { | ||||
const TxId &wtxid = entry.first; | const TxId &wtxid = entry.first; | ||||
const CWalletTx *pcoin = &entry.second; | const CWalletTx *pcoin = &entry.second; | ||||
if (!CheckFinalTx(*pcoin->tx)) { | if (!CheckFinalTx(*pcoin->tx)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pcoin->IsImmatureCoinBase()) { | if (pcoin->IsImmatureCoinBase(locked_chain)) { | ||||
continue; | continue; | ||||
} | } | ||||
int nDepth = pcoin->GetDepthInMainChain(); | int nDepth = pcoin->GetDepthInMainChain(locked_chain); | ||||
if (nDepth < 0) { | if (nDepth < 0) { | ||||
continue; | continue; | ||||
} | } | ||||
// We should not consider coins which aren't at least in our mempool. | // We should not consider coins which aren't at least in our mempool. | ||||
// It's possible for these to be conflicted via ancestors which we may | // It's possible for these to be conflicted via ancestors which we may | ||||
// never be able to detect. | // never be able to detect. | ||||
if (nDepth == 0 && !pcoin->InMempool()) { | if (nDepth == 0 && !pcoin->InMempool()) { | ||||
continue; | continue; | ||||
} | } | ||||
bool safeTx = pcoin->IsTrusted(); | bool safeTx = pcoin->IsTrusted(locked_chain); | ||||
// Bitcoin-ABC: Removed check that prevents consideration of coins from | // Bitcoin-ABC: Removed check that prevents consideration of coins from | ||||
// transactions that are replacing other transactions. This check based | // transactions that are replacing other transactions. This check based | ||||
// on pcoin->mapValue.count("replaces_txid") which was not being set | // on pcoin->mapValue.count("replaces_txid") which was not being set | ||||
// anywhere. | // anywhere. | ||||
// Similarly, we should not consider coins from transactions that have | // Similarly, we should not consider coins from transactions that have | ||||
// been replaced. In the example above, we would want to prevent | // been replaced. In the example above, we would want to prevent | ||||
Show All 31 Lines | for (const auto &entry : mapWallet) { | ||||
!coinControl->IsSelected(outpoint)) { | !coinControl->IsSelected(outpoint)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (IsLockedCoin(outpoint)) { | if (IsLockedCoin(outpoint)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (IsSpent(outpoint)) { | if (IsSpent(locked_chain, outpoint)) { | ||||
continue; | continue; | ||||
} | } | ||||
isminetype mine = IsMine(pcoin->tx->vout[i]); | isminetype mine = IsMine(pcoin->tx->vout[i]); | ||||
if (mine == ISMINE_NO) { | if (mine == ISMINE_NO) { | ||||
continue; | continue; | ||||
} | } | ||||
Show All 20 Lines | for (const auto &entry : mapWallet) { | ||||
// Checks the maximum number of UTXO's. | // Checks the maximum number of UTXO's. | ||||
if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) { | if (nMaximumCount > 0 && vCoins.size() >= nMaximumCount) { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const { | std::map<CTxDestination, std::vector<COutput>> | ||||
CWallet::ListCoins(interfaces::Chain::Lock &locked_chain) const { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
std::map<CTxDestination, std::vector<COutput>> result; | std::map<CTxDestination, std::vector<COutput>> result; | ||||
std::vector<COutput> availableCoins; | std::vector<COutput> availableCoins; | ||||
AvailableCoins(availableCoins); | AvailableCoins(locked_chain, availableCoins); | ||||
for (const auto &coin : availableCoins) { | for (const auto &coin : availableCoins) { | ||||
CTxDestination address; | CTxDestination address; | ||||
if (coin.fSpendable && | if (coin.fSpendable && | ||||
ExtractDestination( | ExtractDestination( | ||||
FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, | FindNonChangeParentOutput(*coin.tx->tx, coin.i).scriptPubKey, | ||||
address)) { | address)) { | ||||
result[address].emplace_back(std::move(coin)); | result[address].emplace_back(std::move(coin)); | ||||
} | } | ||||
} | } | ||||
std::vector<COutPoint> lockedCoins; | std::vector<COutPoint> lockedCoins; | ||||
ListLockedCoins(lockedCoins); | ListLockedCoins(lockedCoins); | ||||
for (const auto &output : lockedCoins) { | for (const auto &output : lockedCoins) { | ||||
auto it = mapWallet.find(output.GetTxId()); | auto it = mapWallet.find(output.GetTxId()); | ||||
if (it != mapWallet.end()) { | if (it != mapWallet.end()) { | ||||
int depth = it->second.GetDepthInMainChain(); | int depth = it->second.GetDepthInMainChain(locked_chain); | ||||
if (depth >= 0 && output.GetN() < it->second.tx->vout.size() && | if (depth >= 0 && output.GetN() < it->second.tx->vout.size() && | ||||
IsMine(it->second.tx->vout[output.GetN()]) == | IsMine(it->second.tx->vout[output.GetN()]) == | ||||
ISMINE_SPENDABLE) { | ISMINE_SPENDABLE) { | ||||
CTxDestination address; | CTxDestination address; | ||||
if (ExtractDestination( | if (ExtractDestination( | ||||
FindNonChangeParentOutput(*it->second.tx, output.GetN()) | FindNonChangeParentOutput(*it->second.tx, output.GetN()) | ||||
.scriptPubKey, | .scriptPubKey, | ||||
address)) { | address)) { | ||||
▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | bool CWallet::FundTransaction(CMutableTransaction &tx, Amount &nFeeRet, | ||||
// Acquire the locks to prevent races to the new locked unspents between the | // Acquire the locks to prevent races to the new locked unspents between the | ||||
// CreateTransaction call and LockCoin calls (when lockUnspents is true). | // CreateTransaction call and LockCoin calls (when lockUnspents is true). | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
CReserveKey reservekey(this); | CReserveKey reservekey(this); | ||||
CTransactionRef tx_new; | CTransactionRef tx_new; | ||||
if (!CreateTransaction(vecSend, tx_new, reservekey, nFeeRet, | if (!CreateTransaction(*locked_chain, vecSend, tx_new, reservekey, nFeeRet, | ||||
nChangePosInOut, strFailReason, coinControl, | nChangePosInOut, strFailReason, coinControl, | ||||
false)) { | false)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (nChangePosInOut != -1) { | if (nChangePosInOut != -1) { | ||||
tx.vout.insert(tx.vout.begin() + nChangePosInOut, | tx.vout.insert(tx.vout.begin() + nChangePosInOut, | ||||
tx_new->vout[nChangePosInOut]); | tx_new->vout[nChangePosInOut]); | ||||
Show All 35 Lines | CWallet::TransactionChangeType(OutputType change_type, | ||||
if (m_default_address_type == OutputType::LEGACY) { | if (m_default_address_type == OutputType::LEGACY) { | ||||
return OutputType::LEGACY; | return OutputType::LEGACY; | ||||
} | } | ||||
// else use m_default_address_type for change | // else use m_default_address_type for change | ||||
return m_default_address_type; | return m_default_address_type; | ||||
} | } | ||||
bool CWallet::CreateTransaction(const std::vector<CRecipient> &vecSend, | bool CWallet::CreateTransaction(interfaces::Chain::Lock &locked_chainIn, | ||||
const std::vector<CRecipient> &vecSend, | |||||
CTransactionRef &tx, CReserveKey &reservekey, | CTransactionRef &tx, CReserveKey &reservekey, | ||||
Amount &nFeeRet, int &nChangePosInOut, | Amount &nFeeRet, int &nChangePosInOut, | ||||
std::string &strFailReason, | std::string &strFailReason, | ||||
const CCoinControl &coinControl, bool sign) { | const CCoinControl &coinControl, bool sign) { | ||||
Amount nValue = Amount::zero(); | Amount nValue = Amount::zero(); | ||||
int nChangePosRequest = nChangePosInOut; | int nChangePosRequest = nChangePosInOut; | ||||
unsigned int nSubtractFeeFromAmount = 0; | unsigned int nSubtractFeeFromAmount = 0; | ||||
for (const auto &recipient : vecSend) { | for (const auto &recipient : vecSend) { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | bool CWallet::CreateTransaction(interfaces::Chain::Lock &locked_chainIn, | ||||
assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
{ | { | ||||
std::set<CInputCoin> setCoins; | std::set<CInputCoin> setCoins; | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::vector<COutput> vAvailableCoins; | std::vector<COutput> vAvailableCoins; | ||||
AvailableCoins(vAvailableCoins, true, &coinControl); | AvailableCoins(*locked_chain, vAvailableCoins, true, &coinControl); | ||||
// Parameters for coin selection, init with dummy | // Parameters for coin selection, init with dummy | ||||
CoinSelectionParams coin_selection_params; | CoinSelectionParams coin_selection_params; | ||||
// Create change script that will be used if we need change | // 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 reservekey so | ||||
// change transaction isn't always pay-to-bitcoin-address | // change transaction isn't always pay-to-bitcoin-address | ||||
CScript scriptChange; | CScript scriptChange; | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | bool CWallet::CommitTransaction( | ||||
} | } | ||||
// Get the inserted-CWalletTx from mapWallet so that the | // Get the inserted-CWalletTx from mapWallet so that the | ||||
// fInMempool flag is cached properly | // fInMempool flag is cached properly | ||||
CWalletTx &wtx = mapWallet.at(wtxNew.GetId()); | CWalletTx &wtx = mapWallet.at(wtxNew.GetId()); | ||||
if (fBroadcastTransactions) { | if (fBroadcastTransactions) { | ||||
// Broadcast | // Broadcast | ||||
if (!wtx.AcceptToMemoryPool(maxTxFee, state)) { | if (!wtx.AcceptToMemoryPool(*locked_chain, maxTxFee, state)) { | ||||
WalletLogPrintf("CommitTransaction(): Transaction cannot be " | WalletLogPrintf("CommitTransaction(): Transaction cannot be " | ||||
"broadcast immediately, %s\n", | "broadcast immediately, %s\n", | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
// TODO: if we expect the failure to be long term or permanent, | // TODO: if we expect the failure to be long term or permanent, | ||||
// instead delete wtx from the wallet and return failure. | // instead delete wtx from the wallet and return failure. | ||||
} else { | } else { | ||||
wtx.RelayWalletTransaction(connman); | wtx.RelayWalletTransaction(*locked_chain, connman); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::ListAccountCreditDebit(const std::string &strAccount, | void CWallet::ListAccountCreditDebit(const std::string &strAccount, | ||||
std::list<CAccountingEntry> &entries) { | std::list<CAccountingEntry> &entries) { | ||||
▲ Show 20 Lines • Show All 436 Lines • ▼ Show 20 Lines | if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), | std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), | ||||
oldestKey); | oldestKey); | ||||
} | } | ||||
} | } | ||||
return oldestKey; | return oldestKey; | ||||
} | } | ||||
std::map<CTxDestination, Amount> CWallet::GetAddressBalances() { | std::map<CTxDestination, Amount> | ||||
CWallet::GetAddressBalances(interfaces::Chain::Lock &locked_chain) { | |||||
std::map<CTxDestination, Amount> balances; | std::map<CTxDestination, Amount> balances; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
for (const auto &walletEntry : mapWallet) { | for (const auto &walletEntry : mapWallet) { | ||||
const CWalletTx *pcoin = &walletEntry.second; | const CWalletTx *pcoin = &walletEntry.second; | ||||
if (!pcoin->IsTrusted()) { | if (!pcoin->IsTrusted(locked_chain)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pcoin->IsImmatureCoinBase()) { | if (pcoin->IsImmatureCoinBase(locked_chain)) { | ||||
continue; | continue; | ||||
} | } | ||||
int nDepth = pcoin->GetDepthInMainChain(); | int nDepth = pcoin->GetDepthInMainChain(locked_chain); | ||||
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1)) { | if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1)) { | ||||
continue; | continue; | ||||
} | } | ||||
for (uint32_t i = 0; i < pcoin->tx->vout.size(); i++) { | for (uint32_t i = 0; i < pcoin->tx->vout.size(); i++) { | ||||
CTxDestination addr; | CTxDestination addr; | ||||
if (!IsMine(pcoin->tx->vout[i])) { | if (!IsMine(pcoin->tx->vout[i])) { | ||||
continue; | continue; | ||||
} | } | ||||
if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | ||||
continue; | continue; | ||||
} | } | ||||
Amount n = IsSpent(COutPoint(walletEntry.first, i)) | Amount n = IsSpent(locked_chain, COutPoint(walletEntry.first, i)) | ||||
? Amount::zero() | ? Amount::zero() | ||||
: pcoin->tx->vout[i].nValue; | : pcoin->tx->vout[i].nValue; | ||||
if (!balances.count(addr)) { | if (!balances.count(addr)) { | ||||
balances[addr] = Amount::zero(); | balances[addr] = Amount::zero(); | ||||
} | } | ||||
balances[addr] += n; | balances[addr] += n; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 241 Lines • ▼ Show 20 Lines | void CWallet::ListLockedCoins(std::vector<COutPoint> &vOutpts) const { | ||||
for (COutPoint outpoint : setLockedCoins) { | for (COutPoint outpoint : setLockedCoins) { | ||||
vOutpts.push_back(outpoint); | vOutpts.push_back(outpoint); | ||||
} | } | ||||
} | } | ||||
/** @} */ // end of Actions | /** @} */ // end of Actions | ||||
void CWallet::GetKeyBirthTimes( | void CWallet::GetKeyBirthTimes( | ||||
interfaces::Chain::Lock &locked_chain, | |||||
std::map<CTxDestination, int64_t> &mapKeyBirth) const { | std::map<CTxDestination, int64_t> &mapKeyBirth) const { | ||||
// mapKeyMetadata | // mapKeyMetadata | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
mapKeyBirth.clear(); | mapKeyBirth.clear(); | ||||
// Get birth times for keys with metadata. | // Get birth times for keys with metadata. | ||||
for (const auto &entry : mapKeyMetadata) { | for (const auto &entry : mapKeyMetadata) { | ||||
if (entry.second.nCreateTime) { | if (entry.second.nCreateTime) { | ||||
▲ Show 20 Lines • Show All 519 Lines • ▼ Show 20 Lines | std::shared_ptr<CWallet> CWallet::CreateWalletFromFile( | ||||
walletInstance->m_default_change_type = DEFAULT_CHANGE_TYPE; | walletInstance->m_default_change_type = DEFAULT_CHANGE_TYPE; | ||||
walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", | walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", | ||||
GetTimeMillis() - nStart); | GetTimeMillis() - nStart); | ||||
// Try to top up keypool. No-op if the wallet is locked. | // Try to top up keypool. No-op if the wallet is locked. | ||||
walletInstance->TopUpKeyPool(); | walletInstance->TopUpKeyPool(); | ||||
// Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit. | |||||
LockAnnotation lock(::cs_main); | |||||
auto locked_chain = chain.lock(); | auto locked_chain = chain.lock(); | ||||
LOCK(walletInstance->cs_wallet); | LOCK(walletInstance->cs_wallet); | ||||
CBlockIndex *pindexRescan = chainActive.Genesis(); | CBlockIndex *pindexRescan = chainActive.Genesis(); | ||||
if (!gArgs.GetBoolArg("-rescan", false)) { | if (!gArgs.GetBoolArg("-rescan", false)) { | ||||
WalletBatch batch(*walletInstance->database); | WalletBatch batch(*walletInstance->database); | ||||
CBlockLocator locator; | CBlockLocator locator; | ||||
if (batch.ReadBestBlock(locator)) { | if (batch.ReadBestBlock(locator)) { | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | |||||
void CMerkleTx::SetMerkleBranch(const CBlockIndex *pindex, int posInBlock) { | void CMerkleTx::SetMerkleBranch(const CBlockIndex *pindex, int posInBlock) { | ||||
// Update the tx's hashBlock | // Update the tx's hashBlock | ||||
hashBlock = pindex->GetBlockHash(); | hashBlock = pindex->GetBlockHash(); | ||||
// Set the position of the transaction in the block. | // Set the position of the transaction in the block. | ||||
nIndex = posInBlock; | nIndex = posInBlock; | ||||
} | } | ||||
int CMerkleTx::GetDepthInMainChain() const { | int CMerkleTx::GetDepthInMainChain( | ||||
interfaces::Chain::Lock &locked_chain) const { | |||||
if (hashUnset()) { | if (hashUnset()) { | ||||
return 0; | return 0; | ||||
} | } | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// Find the block it claims to be in. | // Find the block it claims to be in. | ||||
CBlockIndex *pindex = LookupBlockIndex(hashBlock); | CBlockIndex *pindex = LookupBlockIndex(hashBlock); | ||||
if (!pindex || !chainActive.Contains(pindex)) { | if (!pindex || !chainActive.Contains(pindex)) { | ||||
return 0; | return 0; | ||||
} | } | ||||
return ((nIndex == -1) ? (-1) : 1) * | return ((nIndex == -1) ? (-1) : 1) * | ||||
(chainActive.Height() - pindex->nHeight + 1); | (chainActive.Height() - pindex->nHeight + 1); | ||||
} | } | ||||
int CMerkleTx::GetBlocksToMaturity() const { | int CMerkleTx::GetBlocksToMaturity( | ||||
interfaces::Chain::Lock &locked_chain) const { | |||||
if (!IsCoinBase()) { | if (!IsCoinBase()) { | ||||
return 0; | return 0; | ||||
} | } | ||||
return std::max(0, (COINBASE_MATURITY + 1) - GetDepthInMainChain()); | return std::max(0, (COINBASE_MATURITY + 1) - | ||||
GetDepthInMainChain(locked_chain)); | |||||
} | } | ||||
bool CMerkleTx::IsImmatureCoinBase() const { | bool CMerkleTx::IsImmatureCoinBase( | ||||
interfaces::Chain::Lock &locked_chain) const { | |||||
// note GetBlocksToMaturity is 0 for non-coinbase tx | // note GetBlocksToMaturity is 0 for non-coinbase tx | ||||
return GetBlocksToMaturity() > 0; | return GetBlocksToMaturity(locked_chain) > 0; | ||||
} | } | ||||
bool CWalletTx::AcceptToMemoryPool(const Amount nAbsurdFee, | bool CWalletTx::AcceptToMemoryPool(interfaces::Chain::Lock &locked_chain, | ||||
const Amount nAbsurdFee, | |||||
CValidationState &state) { | CValidationState &state) { | ||||
// Temporary, for AcceptToMemoryPool below. Removed in upcoming commit. | |||||
LockAnnotation lock(::cs_main); | |||||
// We must set fInMempool here - while it will be re-set to true by the | // We must set fInMempool here - while it will be re-set to true by the | ||||
// entered-mempool callback, if we did not there would be a race where a | // entered-mempool callback, if we did not there would be a race where a | ||||
// user could call sendmoney in a loop and hit spurious out of funds errors | // user could call sendmoney in a loop and hit spurious out of funds errors | ||||
// because we think that this newly generated transaction's change is | // because we think that this newly generated transaction's change is | ||||
// unavailable as we're not yet aware that it is in the mempool. | // unavailable as we're not yet aware that it is in the mempool. | ||||
bool ret = ::AcceptToMemoryPool(GetConfig(), g_mempool, state, tx, | bool ret = ::AcceptToMemoryPool(GetConfig(), g_mempool, state, tx, | ||||
nullptr /* pfMissingInputs */, | nullptr /* pfMissingInputs */, | ||||
false /* bypass_limits */, nAbsurdFee); | false /* bypass_limits */, nAbsurdFee); | ||||
▲ Show 20 Lines • Show All 80 Lines • Show Last 20 Lines |