Changeset View
Changeset View
Standalone 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); | ||||
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(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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(); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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: | ||||
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 |