Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,259 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
mapWallet[txin.prevout.GetTxId()].MarkDirty(); | mapWallet[txin.prevout.GetTxId()].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); | ||||
auto it = mapWallet.find(ptx->GetId()); | |||||
if (it != mapWallet.end()) { | |||||
it->second.fInMempool = true; | |||||
} | |||||
} | |||||
void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) { | |||||
LOCK(cs_wallet); | |||||
auto it = mapWallet.find(ptx->GetId()); | |||||
if (it != mapWallet.end()) { | |||||
it->second.fInMempool = false; | |||||
} | |||||
} | } | ||||
void CWallet::BlockConnected( | void CWallet::BlockConnected( | ||||
const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | ||||
const std::vector<CTransactionRef> &vtxConflicted) { | const std::vector<CTransactionRef> &vtxConflicted) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
// TODO: Tempoarily ensure that mempool removals are notified before | // TODO: Tempoarily ensure that mempool removals are notified before | ||||
// connected transactions. This shouldn't matter, but the abandoned state of | // connected transactions. This shouldn't matter, but the abandoned state of | ||||
// transactions in our wallet is currently cleared when we receive another | // transactions in our wallet is currently cleared when we receive another | ||||
// notification and there is a race condition where notification of a | // notification and there is a race condition where notification of a | ||||
// connected conflict might cause an outside process to abandon a | // connected conflict might cause an outside process to abandon a | ||||
// transaction and then have it inadvertantly cleared by the notification | // transaction and then have it inadvertantly cleared by the notification | ||||
// that the conflicted transaction was evicted. | // that the conflicted transaction was evicted. | ||||
for (const CTransactionRef &ptx : vtxConflicted) { | for (const CTransactionRef &ptx : vtxConflicted) { | ||||
SyncTransaction(ptx); | SyncTransaction(ptx); | ||||
TransactionRemovedFromMempool(ptx); | |||||
} | } | ||||
for (size_t i = 0; i < pblock->vtx.size(); i++) { | for (size_t i = 0; i < pblock->vtx.size(); i++) { | ||||
SyncTransaction(pblock->vtx[i], pindex, i); | SyncTransaction(pblock->vtx[i], pindex, i); | ||||
TransactionRemovedFromMempool(pblock->vtx[i]); | |||||
} | } | ||||
m_last_block_processed = pindex; | m_last_block_processed = pindex; | ||||
} | } | ||||
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) { | void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
▲ Show 20 Lines • Show All 692 Lines • ▼ Show 20 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(g_mempool.cs); | return fInMempool; | ||||
if (g_mempool.exists(GetId())) { | |||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
bool CWalletTx::IsTrusted() const { | bool CWalletTx::IsTrusted() const { | ||||
// Quick answer in most cases | // Quick answer in most cases | ||||
if (!CheckFinalTx(*this)) { | if (!CheckFinalTx(*this)) { | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,108 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : wtxNew.tx->vin) { | ||||
CWalletTx &coin = mapWallet[txin.prevout.GetTxId()]; | CWalletTx &coin = mapWallet[txin.prevout.GetTxId()]; | ||||
coin.BindWallet(this); | coin.BindWallet(this); | ||||
NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); | NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); | ||||
} | } | ||||
// Track how many getdata requests our transaction gets. | // Track how many getdata requests our transaction gets. | ||||
mapRequestCount[wtxNew.GetId()] = 0; | mapRequestCount[wtxNew.GetId()] = 0; | ||||
// Get the inserted-CWalletTx from mapWallet so that the | |||||
// fInMempool flag is cached properly | |||||
CWalletTx &wtx = mapWallet[wtxNew.GetId()]; | |||||
if (fBroadcastTransactions) { | if (fBroadcastTransactions) { | ||||
// Broadcast | // Broadcast | ||||
if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) { | if (!wtx.AcceptToMemoryPool(maxTxFee, state)) { | ||||
LogPrintf("CommitTransaction(): Transaction cannot be " | LogPrintf("CommitTransaction(): Transaction cannot be broadcast " | ||||
"broadcast immediately, %s\n", | "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, | ||||
// instead delete wtx from the wallet and return failure. | // instead delete wtx from the wallet and return failure. | ||||
} else { | } else { | ||||
wtxNew.RelayWalletTransaction(connman); | wtx.RelayWalletTransaction(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 1,140 Lines • ▼ Show 20 Lines | int CMerkleTx::GetBlocksToMaturity() const { | ||||
return std::max(0, (COINBASE_MATURITY + 1) - GetDepthInMainChain()); | return std::max(0, (COINBASE_MATURITY + 1) - GetDepthInMainChain()); | ||||
} | } | ||||
bool CMerkleTx::IsImmatureCoinBase() const { | bool CMerkleTx::IsImmatureCoinBase() const { | ||||
// note GetBlocksToMaturity is 0 for non-coinbase tx | // note GetBlocksToMaturity is 0 for non-coinbase tx | ||||
return GetBlocksToMaturity() > 0; | return GetBlocksToMaturity() > 0; | ||||
} | } | ||||
bool CMerkleTx::AcceptToMemoryPool(const Amount nAbsurdFee, | bool CWalletTx::AcceptToMemoryPool(const Amount nAbsurdFee, | ||||
CValidationState &state) { | CValidationState &state) { | ||||
return ::AcceptToMemoryPool(GetConfig(), g_mempool, state, tx, true, | // We must set fInMempool here - while it will be re-set to true by the | ||||
nullptr, false, nAbsurdFee); | // 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 | |||||
// because we think that the transaction they just generated's change is | |||||
// unavailable as we're not yet aware its in mempool. | |||||
bool ret = ::AcceptToMemoryPool( | |||||
GetConfig(), g_mempool, state, tx, true /* fLimitFree */, | |||||
nullptr /* pfMissingInputs */, false /* fOverrideMempoolLimit */, | |||||
nAbsurdFee); | |||||
fInMempool = ret; | |||||
return ret; | |||||
} | } |