Changeset View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 644 Lines • ▼ Show 20 Lines | void CWallet::AddToSpends(const COutPoint &outpoint, const TxId &wtxid) { | ||||
mapTxSpends.insert(std::make_pair(outpoint, wtxid)); | mapTxSpends.insert(std::make_pair(outpoint, wtxid)); | ||||
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 TxId &wtxid) { | void CWallet::AddToSpends(const TxId &wtxid) { | ||||
assert(mapWallet.count(wtxid)); | auto it = mapWallet.find(wtxid); | ||||
CWalletTx &thisTx = mapWallet.at(wtxid); | assert(it != mapWallet.end()); | ||||
CWalletTx &thisTx = it->second; | |||||
// 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, wtxid); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 355 Lines • ▼ Show 20 Lines | |||||
bool CWallet::LoadToWallet(const CWalletTx &wtxIn) { | bool CWallet::LoadToWallet(const CWalletTx &wtxIn) { | ||||
const TxId &txid = wtxIn.GetId(); | const TxId &txid = wtxIn.GetId(); | ||||
CWalletTx &wtx = mapWallet.emplace(txid, wtxIn).first->second; | CWalletTx &wtx = mapWallet.emplace(txid, wtxIn).first->second; | ||||
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(txid); | ||||
for (const CTxIn &txin : wtx.tx->vin) { | for (const CTxIn &txin : wtx.tx->vin) { | ||||
if (mapWallet.count(txin.prevout.GetTxId())) { | auto it = mapWallet.find(txin.prevout.GetTxId()); | ||||
CWalletTx &prevtx = mapWallet.at(txin.prevout.GetTxId()); | if (it != mapWallet.end()) { | ||||
CWalletTx &prevtx = it->second; | |||||
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { | if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { | ||||
MarkConflicted(prevtx.hashBlock, wtx.GetId()); | MarkConflicted(prevtx.hashBlock, wtx.GetId()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
bool CWallet::AbandonTransaction(const TxId &txid) { | bool CWallet::AbandonTransaction(const TxId &txid) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
CWalletDB walletdb(*dbw, "r+"); | CWalletDB walletdb(*dbw, "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 | ||||
assert(mapWallet.count(txid)); | auto it = mapWallet.find(txid); | ||||
CWalletTx &origtx = mapWallet.at(txid); | assert(it != mapWallet.end()); | ||||
CWalletTx &origtx = it->second; | |||||
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { | if (origtx.GetDepthInMainChain() > 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); | ||||
assert(mapWallet.count(now)); | it = mapWallet.find(now); | ||||
jasonbcox: Removed the `auto ` from here and renamed some of the `it` to `it2` to prevent shadow warnings. | |||||
FabienUnsubmitted Not Done Inline ActionsWhy is this case different so that you can reuse the it variable here but not below ? Fabien: Why is this case different so that you can reuse the `it` variable here but not below ? | |||||
jasonbcoxAuthorUnsubmitted Done Inline ActionsThis line is guaranteed to run in this context for every loop, while the later is not. If you think it would be safer, I can rename this one as well to make it 100% clear. I just didn't really like the idea of having it, it2, and it3... Giving them "better" names may actually complicate merging backports in the future since it won't be clear if something was missed (imo). jasonbcox: This line is guaranteed to run in this context for every loop, while the later is not. If you… | |||||
FabienUnsubmitted Not Done Inline ActionsOK, thanks for making it clear. I think you can leave it as is. Fabien: OK, thanks for making it clear. I think you can leave it as is. | |||||
CWalletTx &wtx = mapWallet.at(now); | assert(it != mapWallet.end()); | ||||
CWalletTx &wtx = it->second; | |||||
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. | ||||
Show All 13 Lines | while (!todo.empty()) { | ||||
} | } | ||||
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.GetTxId())) { | auto it2 = mapWallet.find(txin.prevout.GetTxId()); | ||||
mapWallet.at(txin.prevout.GetTxId()).MarkDirty(); | if (it2 != mapWallet.end()) { | ||||
it2->second.MarkDirty(); | |||||
jasonbcoxAuthorUnsubmitted Done Inline ActionsSee comment above jasonbcox: See comment above | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
Show All 22 Lines | void CWallet::MarkConflicted(const uint256 &hashBlock, const TxId &txid) { | ||||
std::set<TxId> done; | std::set<TxId> done; | ||||
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); | ||||
assert(mapWallet.count(now)); | auto it = mapWallet.find(now); | ||||
CWalletTx &wtx = mapWallet.at(now); | assert(it != mapWallet.end()); | ||||
CWalletTx &wtx = it->second; | |||||
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. | ||||
wtx.nIndex = -1; | wtx.nIndex = -1; | ||||
wtx.hashBlock = hashBlock; | wtx.hashBlock = hashBlock; | ||||
wtx.MarkDirty(); | wtx.MarkDirty(); | ||||
walletdb.WriteTx(wtx); | walletdb.WriteTx(wtx); | ||||
// 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 conflicted too. | // that spend them conflicted too. | ||||
TxSpends::const_iterator iter = | TxSpends::const_iterator iter = | ||||
mapTxSpends.lower_bound(COutPoint(now, 0)); | mapTxSpends.lower_bound(COutPoint(now, 0)); | ||||
while (iter != mapTxSpends.end() && iter->first.GetTxId() == now) { | while (iter != mapTxSpends.end() && iter->first.GetTxId() == 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.GetTxId())) { | auto it2 = mapWallet.find(txin.prevout.GetTxId()); | ||||
mapWallet.at(txin.prevout.GetTxId()).MarkDirty(); | if (it2 != mapWallet.end()) { | ||||
it2->second.MarkDirty(); | |||||
jasonbcoxAuthorUnsubmitted Done Inline ActionsSee comment above jasonbcox: See comment above | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void CWallet::SyncTransaction(const CTransactionRef &ptx, | void CWallet::SyncTransaction(const CTransactionRef &ptx, | ||||
const CBlockIndex *pindex, int posInBlock) { | const CBlockIndex *pindex, int posInBlock) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, true)) { | if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, true)) { | ||||
// Not one of ours | // Not one of ours | ||||
return; | return; | ||||
} | } | ||||
// If a transaction changes 'conflicted' state, that changes the balance | // If a transaction changes 'conflicted' state, that changes the balance | ||||
// available of the outputs it spends. So force those to be recomputed, | // available of the outputs it spends. So force those to be | ||||
// also: | // recomputed, also: | ||||
FabienUnsubmitted Not Done Inline ActionsRestore Fabien: Restore | |||||
jasonbcoxAuthorUnsubmitted Done Inline ActionsThis actually matches the code in Core. Seeing as it meets our linting rules and reduces merge conflicts, I think it's best to keep this. jasonbcox: This actually matches the code in Core. Seeing as it meets our linting rules and reduces merge… | |||||
FabienUnsubmitted Not Done Inline ActionsI'll leave that up to you intended that this is only comments, and both cases have pros and cons. Fabien: I'll leave that up to you intended that this is only comments, and both cases have pros and… | |||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (mapWallet.count(txin.prevout.GetTxId())) { | auto it = mapWallet.find(txin.prevout.GetTxId()); | ||||
mapWallet.at(txin.prevout.GetTxId()).MarkDirty(); | if (it != mapWallet.end()) { | ||||
it->second.MarkDirty(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
void CWallet::TransactionAddedToMempool(const CTransactionRef &ptx) { | void CWallet::TransactionAddedToMempool(const CTransactionRef &ptx) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
SyncTransaction(ptx); | SyncTransaction(ptx); | ||||
▲ Show 20 Lines • Show All 3,182 Lines • Show Last 20 Lines |
Removed the auto from here and renamed some of the it to it2 to prevent shadow warnings.
See https://github.com/bitcoin/bitcoin/pull/11039#issuecomment-324238084 Core still hasn't fixed this.