Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | bool operator()( | ||||
const std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> &t1, | const std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> &t1, | ||||
const std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> &t2) | const std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> &t2) | ||||
const { | const { | ||||
return t1.first < t2.first; | return t1.first < t2.first; | ||||
} | } | ||||
}; | }; | ||||
std::string COutput::ToString() const { | std::string COutput::ToString() const { | ||||
return strprintf("COutput(%s, %d, %d) [%s]", tx->GetId().ToString(), i, | return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, | ||||
nDepth, FormatMoney(tx->tx->vout[i].nValue)); | nDepth, FormatMoney(tx->tx->vout[i].nValue)); | ||||
} | } | ||||
const CWalletTx *CWallet::GetWalletTx(const uint256 &hash) const { | const CWalletTx *CWallet::GetWalletTx(const TxHash &hash) const { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash); | std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.find(hash); | ||||
if (it == mapWallet.end()) { | if (it == mapWallet.end()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return &(it->second); | return &(it->second); | ||||
} | } | ||||
CPubKey CWallet::GenerateNewKey() { | CPubKey CWallet::GenerateNewKey() { | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | if (nWalletVersion > nVersion) { | ||||
return false; | return false; | ||||
} | } | ||||
nWalletMaxVersion = nVersion; | nWalletMaxVersion = nVersion; | ||||
return true; | return true; | ||||
} | } | ||||
std::set<uint256> CWallet::GetConflicts(const uint256 &txid) const { | std::set<TxHash> CWallet::GetConflicts(const TxHash &txid) const { | ||||
std::set<uint256> result; | std::set<TxHash> result; | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid); | std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.find(txid); | ||||
if (it == mapWallet.end()) { | if (it == mapWallet.end()) { | ||||
return result; | return result; | ||||
} | } | ||||
const CWalletTx &wtx = it->second; | const CWalletTx &wtx = it->second; | ||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range; | std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range; | ||||
for (const CTxIn &txin : wtx.tx->vin) { | for (const CTxIn &txin : wtx.tx->vin) { | ||||
if (mapTxSpends.count(txin.prevout) <= 1) { | if (mapTxSpends.count(txin.prevout) <= 1) { | ||||
// No conflict if zero or one spends. | // No conflict if zero or one spends. | ||||
continue; | continue; | ||||
} | } | ||||
range = mapTxSpends.equal_range(txin.prevout); | range = mapTxSpends.equal_range(txin.prevout); | ||||
for (TxSpends::const_iterator _it = range.first; _it != range.second; | for (TxSpends::const_iterator _it = range.first; _it != range.second; | ||||
++_it) { | ++_it) { | ||||
result.insert(_it->second); | result.insert(_it->second); | ||||
} | } | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
bool CWallet::HasWalletSpend(const uint256 &txid) const { | bool CWallet::HasWalletSpend(const TxHash &txid) const { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0)); | auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0)); | ||||
return (iter != mapTxSpends.end() && iter->first.hash == txid); | return (iter != mapTxSpends.end() && iter->first.hash == txid); | ||||
} | } | ||||
void CWallet::Flush(bool shutdown) { | void CWallet::Flush(bool shutdown) { | ||||
bitdb.Flush(shutdown); | bitdb.Flush(shutdown); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | void CWallet::SyncMetaData( | ||||
std::pair<TxSpends::iterator, TxSpends::iterator> range) { | std::pair<TxSpends::iterator, TxSpends::iterator> range) { | ||||
// We want all the wallet transactions in range to have the same metadata as | // We want all the wallet transactions in range to have the same metadata as | ||||
// the oldest (smallest nOrderPos). | // the oldest (smallest nOrderPos). | ||||
// So: find smallest nOrderPos: | // So: find smallest nOrderPos: | ||||
int nMinOrderPos = std::numeric_limits<int>::max(); | int nMinOrderPos = std::numeric_limits<int>::max(); | ||||
const CWalletTx *copyFrom = nullptr; | const CWalletTx *copyFrom = nullptr; | ||||
for (TxSpends::iterator it = range.first; it != range.second; ++it) { | for (TxSpends::iterator it = range.first; it != range.second; ++it) { | ||||
const uint256 &hash = it->second; | const TxHash &hash = it->second; | ||||
int n = mapWallet[hash].nOrderPos; | int n = mapWallet[hash].nOrderPos; | ||||
if (n < nMinOrderPos) { | if (n < nMinOrderPos) { | ||||
nMinOrderPos = n; | nMinOrderPos = n; | ||||
copyFrom = &mapWallet[hash]; | copyFrom = &mapWallet[hash]; | ||||
} | } | ||||
} | } | ||||
// Now copy data from copyFrom to rest: | // Now copy data from copyFrom to rest: | ||||
for (TxSpends::iterator it = range.first; it != range.second; ++it) { | for (TxSpends::iterator it = range.first; it != range.second; ++it) { | ||||
const uint256 &hash = it->second; | const TxHash &hash = it->second; | ||||
CWalletTx *copyTo = &mapWallet[hash]; | CWalletTx *copyTo = &mapWallet[hash]; | ||||
if (copyFrom == copyTo) { | if (copyFrom == copyTo) { | ||||
continue; | continue; | ||||
} | } | ||||
if (!copyFrom->IsEquivalentTo(*copyTo)) { | if (!copyFrom->IsEquivalentTo(*copyTo)) { | ||||
continue; | continue; | ||||
} | } | ||||
copyTo->mapValue = copyFrom->mapValue; | copyTo->mapValue = copyFrom->mapValue; | ||||
copyTo->vOrderForm = copyFrom->vOrderForm; | copyTo->vOrderForm = copyFrom->vOrderForm; | ||||
// fTimeReceivedIsTxTime not copied on purpose nTimeReceived not copied | // fTimeReceivedIsTxTime not copied on purpose nTimeReceived not copied | ||||
// on purpose. | // on purpose. | ||||
copyTo->nTimeSmart = copyFrom->nTimeSmart; | copyTo->nTimeSmart = copyFrom->nTimeSmart; | ||||
copyTo->fFromMe = copyFrom->fFromMe; | copyTo->fFromMe = copyFrom->fFromMe; | ||||
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 uint256 &hash, unsigned int n) const { | bool CWallet::IsSpent(const TxHash &hash, unsigned int n) const { | ||||
const COutPoint outpoint(hash, n); | const COutPoint outpoint(hash, n); | ||||
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range; | std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range; | ||||
range = mapTxSpends.equal_range(outpoint); | range = 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 uint256 &wtxid = it->second; | const TxHash &wtxhash = it->second; | ||||
std::map<uint256, CWalletTx>::const_iterator mit = | std::map<TxHash, CWalletTx>::const_iterator mit = | ||||
mapWallet.find(wtxid); | mapWallet.find(wtxhash); | ||||
if (mit != mapWallet.end()) { | if (mit != mapWallet.end()) { | ||||
int depth = mit->second.GetDepthInMainChain(); | int depth = mit->second.GetDepthInMainChain(); | ||||
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; | ||||
} | } | ||||
void CWallet::AddToSpends(const COutPoint &outpoint, const uint256 &wtxid) { | void CWallet::AddToSpends(const COutPoint &outpoint, const TxHash &wtxhash) { | ||||
mapTxSpends.insert(std::make_pair(outpoint, wtxid)); | mapTxSpends.insert(std::make_pair(outpoint, wtxhash)); | ||||
std::pair<TxSpends::iterator, TxSpends::iterator> range; | std::pair<TxSpends::iterator, TxSpends::iterator> range; | ||||
range = mapTxSpends.equal_range(outpoint); | range = mapTxSpends.equal_range(outpoint); | ||||
SyncMetaData(range); | SyncMetaData(range); | ||||
} | } | ||||
void CWallet::AddToSpends(const uint256 &wtxid) { | void CWallet::AddToSpends(const TxHash &wtxhash) { | ||||
assert(mapWallet.count(wtxid)); | assert(mapWallet.count(wtxhash)); | ||||
CWalletTx &thisTx = mapWallet[wtxid]; | CWalletTx &thisTx = mapWallet[wtxhash]; | ||||
// Coinbases don't spend anything! | // Coinbases don't spend anything! | ||||
if (thisTx.IsCoinBase()) { | if (thisTx.IsCoinBase()) { | ||||
return; | return; | ||||
} | } | ||||
for (const CTxIn &txin : thisTx.tx->vin) { | for (const CTxIn &txin : thisTx.tx->vin) { | ||||
AddToSpends(txin.prevout, wtxid); | AddToSpends(txin.prevout, wtxhash); | ||||
} | } | ||||
} | } | ||||
bool CWallet::EncryptWallet(const SecureString &strWalletPassphrase) { | bool CWallet::EncryptWallet(const SecureString &strWalletPassphrase) { | ||||
if (IsCrypted()) { | if (IsCrypted()) { | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | DBErrors CWallet::ReorderTransactions() { | ||||
// bad idea to change the output of this. | // bad idea to change the output of this. | ||||
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time | // First: get all CWalletTx and CAccountingEntry into a sorted-by-time | ||||
// multimap. | // multimap. | ||||
typedef std::pair<CWalletTx *, CAccountingEntry *> TxPair; | typedef std::pair<CWalletTx *, CAccountingEntry *> TxPair; | ||||
typedef std::multimap<int64_t, TxPair> TxItems; | typedef std::multimap<int64_t, TxPair> TxItems; | ||||
TxItems txByTime; | TxItems txByTime; | ||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | for (std::map<TxHash, CWalletTx>::iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
CWalletTx *wtx = &((*it).second); | CWalletTx *wtx = &((*it).second); | ||||
txByTime.insert( | txByTime.insert( | ||||
std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr))); | std::make_pair(wtx->nTimeReceived, TxPair(wtx, nullptr))); | ||||
} | } | ||||
std::list<CAccountingEntry> acentries; | std::list<CAccountingEntry> acentries; | ||||
walletdb.ListAccountCreditDebit("", acentries); | walletdb.ListAccountCreditDebit("", acentries); | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, | ||||
if (!bForceNew) { | if (!bForceNew) { | ||||
if (!account.vchPubKey.IsValid()) { | if (!account.vchPubKey.IsValid()) { | ||||
bForceNew = true; | bForceNew = true; | ||||
} else { | } else { | ||||
// Check if the current key has been used. | // Check if the current key has been used. | ||||
CScript scriptPubKey = | CScript scriptPubKey = | ||||
GetScriptForDestination(account.vchPubKey.GetID()); | GetScriptForDestination(account.vchPubKey.GetID()); | ||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | for (std::map<TxHash, CWalletTx>::iterator it = mapWallet.begin(); | ||||
it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) { | it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) { | ||||
for (const CTxOut &txout : (*it).second.tx->vout) { | for (const CTxOut &txout : (*it).second.tx->vout) { | ||||
if (txout.scriptPubKey == scriptPubKey) { | if (txout.scriptPubKey == scriptPubKey) { | ||||
bForceNew = true; | bForceNew = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Show All 12 Lines | bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, | ||||
pubKey = account.vchPubKey; | pubKey = account.vchPubKey; | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::MarkDirty() { | void CWallet::MarkDirty() { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
for (std::pair<const uint256, CWalletTx> &item : mapWallet) { | for (std::pair<const TxHash, CWalletTx> &item : mapWallet) { | ||||
item.second.MarkDirty(); | item.second.MarkDirty(); | ||||
} | } | ||||
} | } | ||||
bool CWallet::MarkReplaced(const uint256 &originalHash, | bool CWallet::MarkReplaced(const TxHash &originalHash, const TxHash &newHash) { | ||||
const uint256 &newHash) { | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
auto mi = mapWallet.find(originalHash); | auto mi = mapWallet.find(originalHash); | ||||
// There is a bug if MarkReplaced is not called on an existing wallet | // There is a bug if MarkReplaced is not called on an existing wallet | ||||
// transaction. | // transaction. | ||||
assert(mi != mapWallet.end()); | assert(mi != mapWallet.end()); | ||||
CWalletTx &wtx = (*mi).second; | CWalletTx &wtx = (*mi).second; | ||||
// Ensure for now that we're not overwriting data. | // Ensure for now that we're not overwriting data. | ||||
assert(wtx.mapValue.count("replaced_by_txid") == 0); | assert(wtx.mapValue.count("replaced_by_txid") == 0); | ||||
wtx.mapValue["replaced_by_txid"] = newHash.ToString(); | wtx.mapValue["replaced_by_txid"] = newHash.ToString(); | ||||
CWalletDB walletdb(strWalletFile, "r+"); | CWalletDB walletdb(strWalletFile, "r+"); | ||||
bool success = true; | bool success = true; | ||||
if (!walletdb.WriteTx(wtx)) { | if (!walletdb.WriteTx(wtx)) { | ||||
LogPrintf("%s: Updating walletdb tx %s failed", __func__, | LogPrintf("%s: Updating walletdb tx %s failed", __func__, | ||||
wtx.GetId().ToString()); | wtx.GetHash().ToString()); | ||||
success = false; | success = false; | ||||
} | } | ||||
NotifyTransactionChanged(this, originalHash, CT_UPDATED); | NotifyTransactionChanged(this, originalHash, CT_UPDATED); | ||||
return success; | return success; | ||||
} | } | ||||
bool CWallet::AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose) { | bool CWallet::AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); | CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); | ||||
uint256 hash = wtxIn.GetId(); | TxHash hash = wtxIn.GetHash(); | ||||
// Inserts only if not already there, returns tx inserted or tx found. | // Inserts only if not already there, returns tx inserted or tx found. | ||||
std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = | std::pair<std::map<TxHash, CWalletTx>::iterator, bool> ret = | ||||
mapWallet.insert(std::make_pair(hash, wtxIn)); | mapWallet.insert(std::make_pair(hash, wtxIn)); | ||||
CWalletTx &wtx = (*ret.first).second; | CWalletTx &wtx = (*ret.first).second; | ||||
wtx.BindWallet(this); | wtx.BindWallet(this); | ||||
bool fInsertedNew = ret.second; | bool fInsertedNew = ret.second; | ||||
if (fInsertedNew) { | if (fInsertedNew) { | ||||
wtx.nTimeReceived = GetAdjustedTime(); | wtx.nTimeReceived = GetAdjustedTime(); | ||||
wtx.nOrderPos = IncOrderPosNext(&walletdb); | wtx.nOrderPos = IncOrderPosNext(&walletdb); | ||||
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); | wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); | ||||
Show All 39 Lines | if (fInsertedNew) { | ||||
} | } | ||||
int64_t blocktime = | int64_t blocktime = | ||||
mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); | mapBlockIndex[wtxIn.hashBlock]->GetBlockTime(); | ||||
wtx.nTimeSmart = | wtx.nTimeSmart = | ||||
std::max(latestEntry, std::min(blocktime, latestNow)); | std::max(latestEntry, std::min(blocktime, latestNow)); | ||||
} else { | } else { | ||||
LogPrintf("AddToWallet(): found %s in block %s not in index\n", | LogPrintf("AddToWallet(): found %s in block %s not in index\n", | ||||
wtxIn.GetId().ToString(), wtxIn.hashBlock.ToString()); | wtxIn.GetHash().ToString(), | ||||
wtxIn.hashBlock.ToString()); | |||||
} | } | ||||
} | } | ||||
AddToSpends(hash); | AddToSpends(hash); | ||||
} | } | ||||
bool fUpdated = false; | bool fUpdated = false; | ||||
if (!fInsertedNew) { | if (!fInsertedNew) { | ||||
Show All 16 Lines | if (!fInsertedNew) { | ||||
if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) { | if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe) { | ||||
wtx.fFromMe = wtxIn.fFromMe; | wtx.fFromMe = wtxIn.fFromMe; | ||||
fUpdated = true; | fUpdated = true; | ||||
} | } | ||||
} | } | ||||
//// debug print | //// debug print | ||||
LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetId().ToString(), | LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), | ||||
(fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); | (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); | ||||
// Write to disk | // Write to disk | ||||
if ((fInsertedNew || fUpdated) && !walletdb.WriteTx(wtx)) { | if ((fInsertedNew || fUpdated) && !walletdb.WriteTx(wtx)) { | ||||
return false; | return false; | ||||
} | } | ||||
// Break debit/credit balance caches: | // Break debit/credit balance caches: | ||||
wtx.MarkDirty(); | wtx.MarkDirty(); | ||||
// Notify UI of new or updated transaction. | // Notify UI of new or updated transaction. | ||||
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); | NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); | ||||
// Notify an external script when a wallet transaction comes in or is | // Notify an external script when a wallet transaction comes in or is | ||||
// updated. | // updated. | ||||
std::string strCmd = GetArg("-walletnotify", ""); | std::string strCmd = GetArg("-walletnotify", ""); | ||||
if (!strCmd.empty()) { | if (!strCmd.empty()) { | ||||
boost::replace_all(strCmd, "%s", wtxIn.GetId().GetHex()); | boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); | ||||
// Thread runs free. | // Thread runs free. | ||||
boost::thread t(runCommand, strCmd); | boost::thread t(runCommand, strCmd); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::LoadToWallet(const CWalletTx &wtxIn) { | bool CWallet::LoadToWallet(const CWalletTx &wtxIn) { | ||||
uint256 txid = wtxIn.GetId(); | TxHash txhash = wtxIn.GetHash(); | ||||
mapWallet[txid] = wtxIn; | mapWallet[txhash] = wtxIn; | ||||
CWalletTx &wtx = mapWallet[txid]; | CWalletTx &wtx = mapWallet[txhash]; | ||||
wtx.BindWallet(this); | wtx.BindWallet(this); | ||||
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); | wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); | ||||
AddToSpends(txid); | AddToSpends(txhash); | ||||
for (const CTxIn &txin : wtx.tx->vin) { | for (const CTxIn &txin : wtx.tx->vin) { | ||||
if (mapWallet.count(txin.prevout.hash)) { | if (mapWallet.count(txin.prevout.hash)) { | ||||
CWalletTx &prevtx = mapWallet[txin.prevout.hash]; | CWalletTx &prevtx = mapWallet[txin.prevout.hash]; | ||||
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { | if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { | ||||
MarkConflicted(prevtx.hashBlock, wtx.GetId()); | MarkConflicted(prevtx.hashBlock, wtx.GetHash()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | if (fExisted || IsMine(tx) || IsFromMe(tx)) { | ||||
} | } | ||||
return AddToWallet(wtx, false); | return AddToWallet(wtx, false); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::AbandonTransaction(const uint256 &hashTx) { | bool CWallet::AbandonTransaction(const TxHash &hashTx) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
CWalletDB walletdb(strWalletFile, "r+"); | CWalletDB walletdb(strWalletFile, "r+"); | ||||
std::set<uint256> todo; | std::set<TxHash> todo; | ||||
std::set<uint256> done; | std::set<TxHash> done; | ||||
// Can't mark abandoned if confirmed or in mempool. | // Can't mark abandoned if confirmed or in mempool. | ||||
assert(mapWallet.count(hashTx)); | assert(mapWallet.count(hashTx)); | ||||
CWalletTx &origtx = mapWallet[hashTx]; | CWalletTx &origtx = mapWallet[hashTx]; | ||||
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { | if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { | ||||
return false; | return false; | ||||
} | } | ||||
todo.insert(hashTx); | todo.insert(hashTx); | ||||
while (!todo.empty()) { | while (!todo.empty()) { | ||||
uint256 now = *todo.begin(); | TxHash now = *todo.begin(); | ||||
todo.erase(now); | todo.erase(now); | ||||
done.insert(now); | done.insert(now); | ||||
assert(mapWallet.count(now)); | assert(mapWallet.count(now)); | ||||
CWalletTx &wtx = mapWallet[now]; | CWalletTx &wtx = mapWallet[now]; | ||||
int currentconfirm = wtx.GetDepthInMainChain(); | int currentconfirm = wtx.GetDepthInMainChain(); | ||||
// 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()); | ||||
wtx.nIndex = -1; | wtx.nIndex = -1; | ||||
wtx.setAbandoned(); | wtx.setAbandoned(); | ||||
wtx.MarkDirty(); | wtx.MarkDirty(); | ||||
walletdb.WriteTx(wtx); | walletdb.WriteTx(wtx); | ||||
NotifyTransactionChanged(this, wtx.GetId(), CT_UPDATED); | NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED); | ||||
// Iterate over all its outputs, and mark transactions in the wallet | // Iterate over all its outputs, and mark transactions in the wallet | ||||
// that spend them abandoned too. | // that spend them abandoned too. | ||||
TxSpends::const_iterator iter = | TxSpends::const_iterator iter = | ||||
mapTxSpends.lower_bound(COutPoint(hashTx, 0)); | mapTxSpends.lower_bound(COutPoint(hashTx, 0)); | ||||
while (iter != mapTxSpends.end() && iter->first.hash == now) { | while (iter != mapTxSpends.end() && iter->first.hash == now) { | ||||
if (!done.count(iter->second)) { | if (!done.count(iter->second)) { | ||||
todo.insert(iter->second); | todo.insert(iter->second); | ||||
} | } | ||||
iter++; | iter++; | ||||
} | } | ||||
// If a transaction changes 'conflicted' state, that changes the | // If a transaction changes 'conflicted' state, that changes the | ||||
// balance available of the outputs it spends. So force those to be | // balance available of the outputs it spends. So force those to be | ||||
// recomputed. | // recomputed. | ||||
for (const CTxIn &txin : wtx.tx->vin) { | for (const CTxIn &txin : wtx.tx->vin) { | ||||
if (mapWallet.count(txin.prevout.hash)) | if (mapWallet.count(txin.prevout.hash)) | ||||
mapWallet[txin.prevout.hash].MarkDirty(); | mapWallet[txin.prevout.hash].MarkDirty(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::MarkConflicted(const uint256 &hashBlock, const uint256 &hashTx) { | void CWallet::MarkConflicted(const uint256 &hashBlock, const TxHash &hashTx) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
int conflictconfirms = 0; | int conflictconfirms = 0; | ||||
if (mapBlockIndex.count(hashBlock)) { | if (mapBlockIndex.count(hashBlock)) { | ||||
CBlockIndex *pindex = mapBlockIndex[hashBlock]; | CBlockIndex *pindex = mapBlockIndex[hashBlock]; | ||||
if (chainActive.Contains(pindex)) { | if (chainActive.Contains(pindex)) { | ||||
conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); | conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); | ||||
} | } | ||||
} | } | ||||
// If number of conflict confirms cannot be determined, this means that the | // If number of conflict confirms cannot be determined, this means that the | ||||
// block is still unknown or not yet part of the main chain, for example | // block is still unknown or not yet part of the main chain, for example | ||||
// when loading the wallet during a reindex. Do nothing in that case. | // when loading the wallet during a reindex. Do nothing in that case. | ||||
if (conflictconfirms >= 0) { | if (conflictconfirms >= 0) { | ||||
return; | return; | ||||
} | } | ||||
// Do not flush the wallet here for performance reasons | // Do not flush the wallet here for performance reasons | ||||
CWalletDB walletdb(strWalletFile, "r+", false); | CWalletDB walletdb(strWalletFile, "r+", false); | ||||
std::set<uint256> todo; | std::set<TxHash> todo; | ||||
std::set<uint256> done; | std::set<TxHash> done; | ||||
todo.insert(hashTx); | todo.insert(hashTx); | ||||
while (!todo.empty()) { | while (!todo.empty()) { | ||||
uint256 now = *todo.begin(); | TxHash now = *todo.begin(); | ||||
todo.erase(now); | todo.erase(now); | ||||
done.insert(now); | done.insert(now); | ||||
assert(mapWallet.count(now)); | assert(mapWallet.count(now)); | ||||
CWalletTx &wtx = mapWallet[now]; | CWalletTx &wtx = mapWallet[now]; | ||||
int currentconfirm = wtx.GetDepthInMainChain(); | int currentconfirm = wtx.GetDepthInMainChain(); | ||||
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. | ||||
Show All 39 Lines | void CWallet::SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (mapWallet.count(txin.prevout.hash)) | if (mapWallet.count(txin.prevout.hash)) | ||||
mapWallet[txin.prevout.hash].MarkDirty(); | mapWallet[txin.prevout.hash].MarkDirty(); | ||||
} | } | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxIn &txin) const { | isminetype CWallet::IsMine(const CTxIn &txin) const { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::map<uint256, CWalletTx>::const_iterator mi = | std::map<TxHash, CWalletTx>::const_iterator mi = | ||||
mapWallet.find(txin.prevout.hash); | mapWallet.find(txin.prevout.hash); | ||||
if (mi != mapWallet.end()) { | if (mi != mapWallet.end()) { | ||||
const CWalletTx &prev = (*mi).second; | const CWalletTx &prev = (*mi).second; | ||||
if (txin.prevout.n < prev.tx->vout.size()) { | if (txin.prevout.n < prev.tx->vout.size()) { | ||||
return IsMine(prev.tx->vout[txin.prevout.n]); | return IsMine(prev.tx->vout[txin.prevout.n]); | ||||
} | } | ||||
} | } | ||||
return ISMINE_NO; | return ISMINE_NO; | ||||
} | } | ||||
// Note that this function doesn't distinguish between a 0-valued input, and a | // Note that this function doesn't distinguish between a 0-valued input, and a | ||||
// not-"is mine" (according to the filter) input. | // not-"is mine" (according to the filter) input. | ||||
Amount CWallet::GetDebit(const CTxIn &txin, const isminefilter &filter) const { | Amount CWallet::GetDebit(const CTxIn &txin, const isminefilter &filter) const { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::map<uint256, CWalletTx>::const_iterator mi = | std::map<TxHash, CWalletTx>::const_iterator mi = | ||||
mapWallet.find(txin.prevout.hash); | mapWallet.find(txin.prevout.hash); | ||||
if (mi != mapWallet.end()) { | if (mi != mapWallet.end()) { | ||||
const CWalletTx &prev = (*mi).second; | const CWalletTx &prev = (*mi).second; | ||||
if (txin.prevout.n < prev.tx->vout.size()) { | if (txin.prevout.n < prev.tx->vout.size()) { | ||||
if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { | if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { | ||||
return prev.tx->vout[txin.prevout.n].nValue; | return prev.tx->vout[txin.prevout.n].nValue; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | int CWalletTx::GetRequestCount() const { | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
// Returns -1 if it wasn't being tracked. | // Returns -1 if it wasn't being tracked. | ||||
int nRequests = -1; | int nRequests = -1; | ||||
if (IsCoinBase()) { | if (IsCoinBase()) { | ||||
// Generated block. | // Generated block. | ||||
if (!hashUnset()) { | if (!hashUnset()) { | ||||
std::map<uint256, int>::const_iterator mi = | std::map<TxHash, int>::const_iterator mi = | ||||
pwallet->mapRequestCount.find(hashBlock); | pwallet->mapRequestCount.find(hashBlock); | ||||
if (mi != pwallet->mapRequestCount.end()) { | if (mi != pwallet->mapRequestCount.end()) { | ||||
nRequests = (*mi).second; | nRequests = (*mi).second; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
// Did anyone request this transaction? | // Did anyone request this transaction? | ||||
std::map<uint256, int>::const_iterator mi = | std::map<TxHash, int>::const_iterator mi = | ||||
pwallet->mapRequestCount.find(GetId()); | pwallet->mapRequestCount.find(GetHash()); | ||||
if (mi != pwallet->mapRequestCount.end()) { | if (mi != pwallet->mapRequestCount.end()) { | ||||
nRequests = (*mi).second; | nRequests = (*mi).second; | ||||
// How about the block it's in? | // How about the block it's in? | ||||
if (nRequests == 0 && !hashUnset()) { | if (nRequests == 0 && !hashUnset()) { | ||||
std::map<uint256, int>::const_iterator _mi = | std::map<TxHash, int>::const_iterator _mi = | ||||
pwallet->mapRequestCount.find(hashBlock); | pwallet->mapRequestCount.find(hashBlock); | ||||
if (_mi != pwallet->mapRequestCount.end()) { | if (_mi != pwallet->mapRequestCount.end()) { | ||||
nRequests = (*_mi).second; | nRequests = (*_mi).second; | ||||
} else { | } else { | ||||
// If it's in someone else's block it must have got out. | // If it's in someone else's block it must have got out. | ||||
nRequests = 1; | nRequests = 1; | ||||
} | } | ||||
} | } | ||||
Show All 38 Lines | for (unsigned int i = 0; i < tx->vout.size(); ++i) { | ||||
// In either case, we need to get the destination address. | // In either case, we need to get the destination address. | ||||
CTxDestination address; | CTxDestination address; | ||||
if (!ExtractDestination(txout.scriptPubKey, address) && | if (!ExtractDestination(txout.scriptPubKey, address) && | ||||
!txout.scriptPubKey.IsUnspendable()) { | !txout.scriptPubKey.IsUnspendable()) { | ||||
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, " | LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, " | ||||
"txid %s\n", | "txid %s\n", | ||||
this->GetId().ToString()); | this->GetHash().ToString()); | ||||
address = CNoDestination(); | address = CNoDestination(); | ||||
} | } | ||||
COutputEntry output = {address, txout.nValue, (int)i}; | COutputEntry output = {address, txout.nValue, (int)i}; | ||||
// If we are debited by the transaction, add the output as a "sent" | // If we are debited by the transaction, add the output as a "sent" | ||||
// entry. | // entry. | ||||
if (nDebit > Amount(0)) { | if (nDebit > Amount(0)) { | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | if (!fBroadcastTransactions) { | ||||
return; | return; | ||||
} | } | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
std::map<int64_t, CWalletTx *> mapSorted; | std::map<int64_t, CWalletTx *> mapSorted; | ||||
// 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 uint256, CWalletTx> &item : mapWallet) { | for (std::pair<const TxHash, CWalletTx> &item : mapWallet) { | ||||
const uint256 &wtxid = item.first; | const TxHash &wtxhash = item.first; | ||||
CWalletTx &wtx = item.second; | CWalletTx &wtx = item.second; | ||||
assert(wtx.GetId() == wtxid); | assert(wtx.GetHash() == wtxhash); | ||||
int nDepth = wtx.GetDepthInMainChain(); | int nDepth = wtx.GetDepthInMainChain(); | ||||
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)); | ||||
} | } | ||||
} | } | ||||
Show All 11 Lines | bool CWalletTx::RelayWalletTransaction(CConnman *connman) { | ||||
assert(pwallet->GetBroadcastTransactions()); | assert(pwallet->GetBroadcastTransactions()); | ||||
if (IsCoinBase() || isAbandoned() || GetDepthInMainChain() != 0) { | if (IsCoinBase() || isAbandoned() || GetDepthInMainChain() != 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(maxTxFee, state)) { | ||||
LogPrintf("Relaying wtx %s\n", GetId().ToString()); | LogPrintf("Relaying wtx %s\n", GetHash().ToString()); | ||||
if (connman) { | if (connman) { | ||||
CInv inv(MSG_TX, GetId()); | CInv inv(MSG_TX, GetHash()); | ||||
connman->ForEachNode( | connman->ForEachNode( | ||||
[&inv](CNode *pnode) { pnode->PushInventory(inv); }); | [&inv](CNode *pnode) { pnode->PushInventory(inv); }); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
std::set<uint256> CWalletTx::GetConflicts() const { | std::set<TxHash> CWalletTx::GetConflicts() const { | ||||
std::set<uint256> result; | std::set<TxHash> result; | ||||
if (pwallet != nullptr) { | if (pwallet != nullptr) { | ||||
uint256 myHash = GetId(); | TxHash myHash = GetHash(); | ||||
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 { | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | if (IsCoinBase() && GetBlocksToMaturity() > 0) { | ||||
return 0; | return 0; | ||||
} | } | ||||
if (fUseCache && fAvailableCreditCached) { | if (fUseCache && fAvailableCreditCached) { | ||||
return nAvailableCreditCached; | return nAvailableCreditCached; | ||||
} | } | ||||
Amount nCredit = 0; | Amount nCredit = 0; | ||||
uint256 hashTx = GetId(); | TxHash hashTx = GetHash(); | ||||
for (unsigned int i = 0; i < tx->vout.size(); i++) { | for (unsigned int i = 0; i < tx->vout.size(); i++) { | ||||
if (!pwallet->IsSpent(hashTx, i)) { | if (!pwallet->IsSpent(hashTx, i)) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); | nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"CWalletTx::GetAvailableCredit() : value out of range"); | "CWalletTx::GetAvailableCredit() : value out of range"); | ||||
} | } | ||||
Show All 32 Lines | Amount CWalletTx::GetAvailableWatchOnlyCredit(const bool &fUseCache) const { | ||||
} | } | ||||
if (fUseCache && fAvailableWatchCreditCached) { | if (fUseCache && fAvailableWatchCreditCached) { | ||||
return nAvailableWatchCreditCached; | return nAvailableWatchCreditCached; | ||||
} | } | ||||
Amount nCredit = 0; | Amount nCredit = 0; | ||||
for (unsigned int i = 0; i < tx->vout.size(); i++) { | for (unsigned int i = 0; i < tx->vout.size(); i++) { | ||||
if (!pwallet->IsSpent(GetId(), i)) { | if (!pwallet->IsSpent(GetHash(), i)) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); | nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"CWalletTx::GetAvailableCredit() : value out of range"); | "CWalletTx::GetAvailableCredit() : value out of range"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
Show All 10 Lines | Amount CWalletTx::GetChange() const { | ||||
nChangeCached = pwallet->GetChange(*this); | nChangeCached = pwallet->GetChange(*this); | ||||
fChangeCached = true; | fChangeCached = true; | ||||
return nChangeCached; | return nChangeCached; | ||||
} | } | ||||
bool CWalletTx::InMempool() const { | bool CWalletTx::InMempool() const { | ||||
LOCK(mempool.cs); | LOCK(mempool.cs); | ||||
if (mempool.exists(GetId())) { | if (mempool.exists(GetHash())) { | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWalletTx::IsTrusted() const { | bool CWalletTx::IsTrusted() const { | ||||
// Quick answer in most cases | // Quick answer in most cases | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | bool CWalletTx::IsEquivalentTo(const CWalletTx &_tx) const { | ||||
for (unsigned int i = 0; i < tx2.vin.size(); i++) { | for (unsigned int i = 0; i < tx2.vin.size(); i++) { | ||||
tx2.vin[i].scriptSig = CScript(); | tx2.vin[i].scriptSig = CScript(); | ||||
} | } | ||||
return CTransaction(tx1) == CTransaction(tx2); | return CTransaction(tx1) == CTransaction(tx2); | ||||
} | } | ||||
std::vector<uint256> | std::vector<TxHash> CWallet::ResendWalletTransactionsBefore(int64_t nTime, | ||||
CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman *connman) { | CConnman *connman) { | ||||
std::vector<uint256> result; | std::vector<TxHash> 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 uint256, CWalletTx> &item : mapWallet) { | for (std::pair<const TxHash, 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 (std::pair<const unsigned int, CWalletTx *> &item : mapSorted) { | for (std::pair<const unsigned int, CWalletTx *> &item : mapSorted) { | ||||
CWalletTx &wtx = *item.second; | CWalletTx &wtx = *item.second; | ||||
if (wtx.RelayWalletTransaction(connman)) { | if (wtx.RelayWalletTransaction(connman)) { | ||||
result.push_back(wtx.GetId()); | result.push_back(wtx.GetHash()); | ||||
} | } | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | ||||
CConnman *connman) { | CConnman *connman) { | ||||
Show All 13 Lines | void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | ||||
if (nBestBlockTime < nLastResend) { | if (nBestBlockTime < nLastResend) { | ||||
return; | return; | ||||
} | } | ||||
nLastResend = GetTime(); | nLastResend = GetTime(); | ||||
// 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<TxHash> relayed = | ||||
ResendWalletTransactionsBefore(nBestBlockTime - 5 * 60, connman); | ResendWalletTransactionsBefore(nBestBlockTime - 5 * 60, connman); | ||||
if (!relayed.empty()) { | if (!relayed.empty()) { | ||||
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, | LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, | ||||
relayed.size()); | relayed.size()); | ||||
} | } | ||||
} | } | ||||
/** @} */ // end of mapWallet | /** @} */ // end of mapWallet | ||||
/** | /** | ||||
* @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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).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 (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
nTotal += pcoin->GetImmatureWatchOnlyCredit(); | nTotal += pcoin->GetImmatureWatchOnlyCredit(); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlyConfirmed, | void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlyConfirmed, | ||||
const CCoinControl *coinControl, | const CCoinControl *coinControl, | ||||
bool fIncludeZeroValue) const { | bool fIncludeZeroValue) const { | ||||
vCoins.clear(); | vCoins.clear(); | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const uint256 &wtxid = it->first; | const TxHash &wtxhash = it->first; | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
if (!CheckFinalTx(*pcoin)) { | if (!CheckFinalTx(*pcoin)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (fOnlyConfirmed && !pcoin->IsTrusted()) { | if (fOnlyConfirmed && !pcoin->IsTrusted()) { | ||||
continue; | continue; | ||||
Show All 33 Lines | for (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
// in the wallet code. | // in the wallet code. | ||||
if (nDepth == 0 && fOnlyConfirmed && | if (nDepth == 0 && fOnlyConfirmed && | ||||
pcoin->mapValue.count("replaced_by_txid")) { | pcoin->mapValue.count("replaced_by_txid")) { | ||||
continue; | continue; | ||||
} | } | ||||
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { | for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { | ||||
isminetype mine = IsMine(pcoin->tx->vout[i]); | isminetype mine = IsMine(pcoin->tx->vout[i]); | ||||
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && | if (!(IsSpent(wtxhash, i)) && mine != ISMINE_NO && | ||||
!IsLockedCoin((*it).first, i) && | !IsLockedCoin((*it).first, i) && | ||||
(pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) && | (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) && | ||||
(!coinControl || !coinControl->HasSelected() || | (!coinControl || !coinControl->HasSelected() || | ||||
coinControl->fAllowOtherInputs || | coinControl->fAllowOtherInputs || | ||||
coinControl->IsSelected(COutPoint((*it).first, i)))) { | coinControl->IsSelected(COutPoint((*it).first, i)))) { | ||||
vCoins.push_back(COutput( | vCoins.push_back(COutput( | ||||
pcoin, i, nDepth, | pcoin, i, nDepth, | ||||
((mine & ISMINE_SPENDABLE) != ISMINE_NO) || | ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | for (const COutput &output : vCoins) { | ||||
const CWalletTx *pcoin = output.tx; | const CWalletTx *pcoin = output.tx; | ||||
if (output.nDepth < | if (output.nDepth < | ||||
(pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs)) { | (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs)) { | ||||
continue; | continue; | ||||
} | } | ||||
if (!mempool.TransactionWithinChainLimit(pcoin->GetId(), | if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), | ||||
nMaxAncestors)) { | nMaxAncestors)) { | ||||
continue; | continue; | ||||
} | } | ||||
int i = output.i; | int i = output.i; | ||||
Amount n = pcoin->tx->vout[i].nValue; | Amount n = pcoin->tx->vout[i].nValue; | ||||
std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> coin = | std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> coin = | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | bool CWallet::SelectCoins( | ||||
Amount nValueFromPresetInputs = 0; | Amount nValueFromPresetInputs = 0; | ||||
std::vector<COutPoint> vPresetInputs; | std::vector<COutPoint> vPresetInputs; | ||||
if (coinControl) { | if (coinControl) { | ||||
coinControl->ListSelected(vPresetInputs); | coinControl->ListSelected(vPresetInputs); | ||||
} | } | ||||
for (const COutPoint &outpoint : vPresetInputs) { | for (const COutPoint &outpoint : vPresetInputs) { | ||||
std::map<uint256, CWalletTx>::const_iterator it = | std::map<TxHash, CWalletTx>::const_iterator it = | ||||
mapWallet.find(outpoint.hash); | mapWallet.find(outpoint.hash); | ||||
if (it == mapWallet.end()) { | if (it == mapWallet.end()) { | ||||
// TODO: Allow non-wallet inputs | // TODO: Allow non-wallet inputs | ||||
return false; | return false; | ||||
} | } | ||||
const CWalletTx *pcoin = &it->second; | const CWalletTx *pcoin = &it->second; | ||||
// Clearly invalid input, fail. | // Clearly invalid input, fail. | ||||
▲ Show 20 Lines • Show All 359 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
} | } | ||||
// Fill vin | // Fill vin | ||||
// | // | ||||
// Note how the sequence number is set to non-maxint so that the | // Note how the sequence number is set to non-maxint so that the | ||||
// nLockTime set above actually works. | // nLockTime set above actually works. | ||||
for (const auto &coin : setCoins) { | for (const auto &coin : setCoins) { | ||||
txNew.vin.push_back( | txNew.vin.push_back( | ||||
CTxIn(coin.first->GetId(), coin.second, CScript(), | CTxIn(coin.first->GetHash(), coin.second, CScript(), | ||||
std::numeric_limits<unsigned int>::max() - 1)); | std::numeric_limits<unsigned int>::max() - 1)); | ||||
} | } | ||||
// Fill in dummy signatures for fee calculation. | // Fill in dummy signatures for fee calculation. | ||||
if (!DummySignTx(txNew, setCoins)) { | if (!DummySignTx(txNew, setCoins)) { | ||||
strFailReason = _("Signing transaction failed"); | strFailReason = _("Signing transaction failed"); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | bool CWallet::CommitTransaction(CWalletTx &wtxNew, CReserveKey &reservekey, | ||||
// Add tx to wallet, because if it has change it's also ours, otherwise just | // Add tx to wallet, because if it has change it's also ours, otherwise just | ||||
// for transaction history. | // for transaction history. | ||||
AddToWallet(wtxNew); | AddToWallet(wtxNew); | ||||
// Notify that old coins are spent. | // Notify that old coins are spent. | ||||
for (const CTxIn &txin : wtxNew.tx->vin) { | for (const CTxIn &txin : wtxNew.tx->vin) { | ||||
CWalletTx &coin = mapWallet[txin.prevout.hash]; | CWalletTx &coin = mapWallet[txin.prevout.hash]; | ||||
coin.BindWallet(this); | coin.BindWallet(this); | ||||
NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); | NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); | ||||
} | } | ||||
// Track how many getdata requests our transaction gets. | // Track how many getdata requests our transaction gets. | ||||
mapRequestCount[wtxNew.GetId()] = 0; | mapRequestCount[wtxNew.GetHash()] = 0; | ||||
if (fBroadcastTransactions) { | if (fBroadcastTransactions) { | ||||
// Broadcast | // Broadcast | ||||
if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) { | if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) { | ||||
LogPrintf("CommitTransaction(): Transaction cannot be " | LogPrintf("CommitTransaction(): Transaction cannot be " | ||||
"broadcast immediately, %s\n", | "broadcast immediately, %s\n", | ||||
state.GetRejectReason()); | state.GetRejectReason()); | ||||
// TODO: if we expect the failure to be long term or permanent, | // TODO: if we expect the failure to be long term or permanent, | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { | ||||
fFirstRunRet = !vchDefaultKey.IsValid(); | fFirstRunRet = !vchDefaultKey.IsValid(); | ||||
uiInterface.LoadWallet(this); | uiInterface.LoadWallet(this); | ||||
return DB_LOAD_OK; | return DB_LOAD_OK; | ||||
} | } | ||||
DBErrors CWallet::ZapSelectTx(std::vector<uint256> &vHashIn, | DBErrors CWallet::ZapSelectTx(std::vector<TxHash> &vHashIn, | ||||
std::vector<uint256> &vHashOut) { | std::vector<TxHash> &vHashOut) { | ||||
if (!fFileBacked) { | if (!fFileBacked) { | ||||
return DB_LOAD_OK; | return DB_LOAD_OK; | ||||
} | } | ||||
DBErrors nZapSelectTxRet = | DBErrors nZapSelectTxRet = | ||||
CWalletDB(strWalletFile, "cr+").ZapSelectTx(this, vHashIn, vHashOut); | CWalletDB(strWalletFile, "cr+").ZapSelectTx(this, vHashIn, vHashOut); | ||||
if (nZapSelectTxRet == DB_NEED_REWRITE) { | if (nZapSelectTxRet == DB_NEED_REWRITE) { | ||||
if (CDB::Rewrite(strWalletFile, "\x04pool")) { | if (CDB::Rewrite(strWalletFile, "\x04pool")) { | ||||
▲ Show 20 Lines • Show All 266 Lines • ▼ Show 20 Lines | int64_t CWallet::GetOldestKeyPoolTime() { | ||||
assert(keypool.vchPubKey.IsValid()); | assert(keypool.vchPubKey.IsValid()); | ||||
return keypool.nTime; | return keypool.nTime; | ||||
} | } | ||||
std::map<CTxDestination, Amount> CWallet::GetAddressBalances() { | std::map<CTxDestination, Amount> CWallet::GetAddressBalances() { | ||||
std::map<CTxDestination, Amount> balances; | std::map<CTxDestination, Amount> balances; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
for (std::pair<uint256, CWalletTx> walletEntry : mapWallet) { | for (std::pair<TxHash, CWalletTx> walletEntry : mapWallet) { | ||||
CWalletTx *pcoin = &walletEntry.second; | CWalletTx *pcoin = &walletEntry.second; | ||||
if (!pcoin->IsTrusted()) { | if (!pcoin->IsTrusted()) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) { | if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) { | ||||
continue; | continue; | ||||
Show All 26 Lines | |||||
} | } | ||||
std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | ||||
// mapWallet | // mapWallet | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
std::set<std::set<CTxDestination>> groupings; | std::set<std::set<CTxDestination>> groupings; | ||||
std::set<CTxDestination> grouping; | std::set<CTxDestination> grouping; | ||||
for (std::pair<uint256, CWalletTx> walletEntry : mapWallet) { | for (std::pair<TxHash, CWalletTx> walletEntry : mapWallet) { | ||||
CWalletTx *pcoin = &walletEntry.second; | CWalletTx *pcoin = &walletEntry.second; | ||||
if (pcoin->tx->vin.size() > 0) { | if (pcoin->tx->vin.size() > 0) { | ||||
bool any_mine = false; | bool any_mine = false; | ||||
// Group all input addresses with each other. | // Group all input addresses with each other. | ||||
for (CTxIn txin : pcoin->tx->vin) { | for (CTxIn txin : pcoin->tx->vin) { | ||||
CTxDestination address; | CTxDestination address; | ||||
// If this input isn't mine, ignore it. | // If this input isn't mine, ignore it. | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
Amount CWallet::GetAccountBalance(CWalletDB &walletdb, | Amount CWallet::GetAccountBalance(CWalletDB &walletdb, | ||||
const std::string &strAccount, int nMinDepth, | const std::string &strAccount, int nMinDepth, | ||||
const isminefilter &filter) { | const isminefilter &filter) { | ||||
Amount nBalance = 0; | Amount nBalance = 0; | ||||
// Tally wallet transactions. | // Tally wallet transactions. | ||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | for (std::map<TxHash, CWalletTx>::iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx &wtx = (*it).second; | const CWalletTx &wtx = (*it).second; | ||||
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || | if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || | ||||
wtx.GetDepthInMainChain() < 0) { | wtx.GetDepthInMainChain() < 0) { | ||||
continue; | continue; | ||||
} | } | ||||
Amount nReceived, nSent, nFee; | Amount nReceived, nSent, nFee; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | for (const int64_t &id : setKeyPool) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": unknown key in key pool"); | ": unknown key in key pool"); | ||||
} | } | ||||
setAddress.insert(keyID); | setAddress.insert(keyID); | ||||
} | } | ||||
} | } | ||||
void CWallet::UpdatedTransaction(const uint256 &hashTx) { | void CWallet::UpdatedTransaction(const TxHash &hashTx) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Only notify UI if this transaction is in this wallet. | // Only notify UI if this transaction is in this wallet. | ||||
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx); | std::map<TxHash, CWalletTx>::const_iterator mi = mapWallet.find(hashTx); | ||||
if (mi != mapWallet.end()) { | if (mi != mapWallet.end()) { | ||||
NotifyTransactionChanged(this, hashTx, CT_UPDATED); | NotifyTransactionChanged(this, hashTx, CT_UPDATED); | ||||
} | } | ||||
} | } | ||||
void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script) { | void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script) { | ||||
std::shared_ptr<CReserveKey> rKey(new CReserveKey(this)); | std::shared_ptr<CReserveKey> rKey(new CReserveKey(this)); | ||||
CPubKey pubkey; | CPubKey pubkey; | ||||
Show All 18 Lines | |||||
} | } | ||||
void CWallet::UnlockAllCoins() { | void CWallet::UnlockAllCoins() { | ||||
// setLockedCoins | // setLockedCoins | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
setLockedCoins.clear(); | setLockedCoins.clear(); | ||||
} | } | ||||
bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const { | bool CWallet::IsLockedCoin(TxHash hash, unsigned int n) const { | ||||
// setLockedCoins | // setLockedCoins | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
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) { | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | void CWallet::GetKeyBirthTimes( | ||||
// If there are no such keys, we're done. | // If there are no such keys, we're done. | ||||
if (mapKeyFirstBlock.empty()) { | if (mapKeyFirstBlock.empty()) { | ||||
return; | return; | ||||
} | } | ||||
// Find first block that affects those keys, if there are any left. | // Find first block that affects those keys, if there are any left. | ||||
std::vector<CKeyID> vAffected; | std::vector<CKeyID> vAffected; | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<TxHash, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); it++) { | it != mapWallet.end(); it++) { | ||||
// Iterate over all wallet transactions... | // Iterate over all wallet transactions... | ||||
const CWalletTx &wtx = (*it).second; | const CWalletTx &wtx = (*it).second; | ||||
BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); | BlockMap::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); | ||||
if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { | if (blit != mapBlockIndex.end() && chainActive.Contains(blit->second)) { | ||||
// ... which are already in a block. | // ... which are already in a block. | ||||
int nHeight = blit->second->nHeight; | int nHeight = blit->second->nHeight; | ||||
for (const CTxOut &txout : wtx.tx->vout) { | for (const CTxOut &txout : wtx.tx->vout) { | ||||
▲ Show 20 Lines • Show All 338 Lines • ▼ Show 20 Lines | if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { | ||||
CWalletDB::IncrementUpdateCounter(); | CWalletDB::IncrementUpdateCounter(); | ||||
// Restore wallet transaction metadata after -zapwallettxes=1 | // Restore wallet transaction metadata after -zapwallettxes=1 | ||||
if (GetBoolArg("-zapwallettxes", false) && | if (GetBoolArg("-zapwallettxes", false) && | ||||
GetArg("-zapwallettxes", "1") != "2") { | GetArg("-zapwallettxes", "1") != "2") { | ||||
CWalletDB walletdb(walletFile); | CWalletDB walletdb(walletFile); | ||||
for (const CWalletTx &wtxOld : vWtx) { | for (const CWalletTx &wtxOld : vWtx) { | ||||
uint256 txid = wtxOld.GetId(); | TxHash txhash = wtxOld.GetHash(); | ||||
std::map<uint256, CWalletTx>::iterator mi = | std::map<TxHash, CWalletTx>::iterator mi = | ||||
walletInstance->mapWallet.find(txid); | walletInstance->mapWallet.find(txhash); | ||||
if (mi != walletInstance->mapWallet.end()) { | if (mi != walletInstance->mapWallet.end()) { | ||||
const CWalletTx *copyFrom = &wtxOld; | const CWalletTx *copyFrom = &wtxOld; | ||||
CWalletTx *copyTo = &mi->second; | CWalletTx *copyTo = &mi->second; | ||||
copyTo->mapValue = copyFrom->mapValue; | copyTo->mapValue = copyFrom->mapValue; | ||||
copyTo->vOrderForm = copyFrom->vOrderForm; | copyTo->vOrderForm = copyFrom->vOrderForm; | ||||
copyTo->nTimeReceived = copyFrom->nTimeReceived; | copyTo->nTimeReceived = copyFrom->nTimeReceived; | ||||
copyTo->nTimeSmart = copyFrom->nTimeSmart; | copyTo->nTimeSmart = copyFrom->nTimeSmart; | ||||
copyTo->fFromMe = copyFrom->fFromMe; | copyTo->fFromMe = copyFrom->fFromMe; | ||||
▲ Show 20 Lines • Show All 298 Lines • Show Last 20 Lines |