Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,157 Lines • ▼ Show 20 Lines | for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | ||||
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; | std::string unused_err_string; | ||||
wtx.AcceptToMemoryPool(locked_chain, state); | wtx.SubmitMemoryPoolAndRelay(unused_err_string, false, locked_chain); | ||||
} | } | ||||
} | } | ||||
bool CWalletTx::RelayWalletTransaction(interfaces::Chain::Lock &locked_chain) { | bool CWalletTx::SubmitMemoryPoolAndRelay( | ||||
std::string &err_string, bool relay, | |||||
interfaces::Chain::Lock &locked_chain) { | |||||
// Can't relay if wallet is not broadcasting | // Can't relay if wallet is not broadcasting | ||||
if (!pwallet->GetBroadcastTransactions()) { | if (!pwallet->GetBroadcastTransactions()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Don't relay coinbase transactions outside blocks | // Don't relay coinbase transactions outside blocks | ||||
if (IsCoinBase()) { | if (IsCoinBase()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Don't relay abandoned transactions | // Don't relay abandoned transactions | ||||
if (isAbandoned()) { | if (isAbandoned()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Don't relay conflicted or already confirmed transactions | // Don't relay conflicted or already confirmed transactions | ||||
if (GetDepthInMainChain(locked_chain) != 0) { | if (GetDepthInMainChain(locked_chain) != 0) { | ||||
return false; | return false; | ||||
} | } | ||||
// Don't relay transactions that aren't accepted to the mempool | |||||
CValidationState unused_state; | |||||
if (!InMempool() && !AcceptToMemoryPool(locked_chain, unused_state)) { | |||||
return false; | |||||
} | |||||
// Don't try to relay if the node is not connected to the p2p network | |||||
if (!pwallet->chain().p2pEnabled()) { | |||||
return false; | |||||
} | |||||
// Try to relay the transaction | |||||
pwallet->WalletLogPrintf("Relaying wtx %s\n", GetId().ToString()); | |||||
pwallet->chain().relayTransaction(GetId()); | |||||
return true; | // Submit transaction to mempool for relay | ||||
pwallet->WalletLogPrintf("Submitting wtx %s to mempool for relay\n", | |||||
GetId().ToString()); | |||||
// 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 | |||||
// 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 | |||||
// unavailable as we're not yet aware that it is in the mempool. | |||||
// | |||||
// Irrespective of the failure reason, un-marking fInMempool | |||||
// out-of-order is incorrect - it should be unmarked when | |||||
// TransactionRemovedFromMempool fires. | |||||
bool ret = pwallet->chain().broadcastTransaction( | |||||
GetConfig(), tx, err_string, pwallet->m_default_max_tx_fee, relay); | |||||
fInMempool |= ret; | |||||
return ret; | |||||
} | } | ||||
std::set<TxId> CWalletTx::GetConflicts() const { | std::set<TxId> CWalletTx::GetConflicts() const { | ||||
std::set<TxId> result; | std::set<TxId> result; | ||||
if (pwallet != nullptr) { | if (pwallet != nullptr) { | ||||
const TxId &txid = GetId(); | const TxId &txid = GetId(); | ||||
result = pwallet->GetConflicts(txid); | result = pwallet->GetConflicts(txid); | ||||
result.erase(txid); | result.erase(txid); | ||||
▲ Show 20 Lines • Show All 215 Lines • ▼ Show 20 Lines | void CWallet::ResendWalletTransactions() { | ||||
// Only do it if there's been a new block since last time | // Only do it if there's been a new block since last time | ||||
if (m_best_block_time < nLastResend) { | if (m_best_block_time < nLastResend) { | ||||
return; | return; | ||||
} | } | ||||
nLastResend = GetTime(); | nLastResend = GetTime(); | ||||
int relayed_tx_count = 0; | int submitted_tx_count = 0; | ||||
{ // locked_chain and cs_wallet scope | { // locked_chain and cs_wallet scope | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Relay transactions | // Relay transactions | ||||
for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | for (std::pair<const TxId, CWalletTx> &item : mapWallet) { | ||||
CWalletTx &wtx = item.second; | CWalletTx &wtx = item.second; | ||||
// only rebroadcast unconfirmed txes older than 5 minutes before the | // only rebroadcast unconfirmed txes older than 5 minutes before the | ||||
// last block was found | // last block was found | ||||
if (wtx.nTimeReceived > m_best_block_time - 5 * 60) { | if (wtx.nTimeReceived > m_best_block_time - 5 * 60) { | ||||
continue; | continue; | ||||
} | } | ||||
if (wtx.RelayWalletTransaction(*locked_chain)) { | std::string unused_err_string; | ||||
++relayed_tx_count; | if (wtx.SubmitMemoryPoolAndRelay(unused_err_string, true, | ||||
*locked_chain)) { | |||||
++submitted_tx_count; | |||||
} | } | ||||
} | } | ||||
} // locked_chain and cs_wallet | } // locked_chain and cs_wallet | ||||
if (relayed_tx_count > 0) { | if (submitted_tx_count > 0) { | ||||
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", | WalletLogPrintf("%s: resubmit %u unconfirmed transactions\n", __func__, | ||||
__func__, relayed_tx_count); | submitted_tx_count); | ||||
} | } | ||||
} | } | ||||
/** @} */ // end of mapWallet | /** @} */ // end of mapWallet | ||||
void MaybeResendWalletTxs() { | void MaybeResendWalletTxs() { | ||||
for (const std::shared_ptr<CWallet> &pwallet : GetWallets()) { | for (const std::shared_ptr<CWallet> &pwallet : GetWallets()) { | ||||
pwallet->ResendWalletTransactions(); | pwallet->ResendWalletTransactions(); | ||||
▲ Show 20 Lines • Show All 1,051 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : wtxNew.tx->vin) { | ||||
NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); | NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); | ||||
} | } | ||||
// 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 | std::string err_string; | ||||
if (!wtx.AcceptToMemoryPool(*locked_chain, state)) { | if (!wtx.SubmitMemoryPoolAndRelay(err_string, true, *locked_chain)) { | ||||
WalletLogPrintf("CommitTransaction(): Transaction cannot be " | WalletLogPrintf("CommitTransaction(): Transaction cannot be " | ||||
"broadcast immediately, %s\n", | "broadcast immediately, %s\n", | ||||
FormatStateMessage(state)); | err_string); | ||||
// 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 { | |||||
wtx.RelayWalletTransaction(*locked_chain); | |||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { | DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
▲ Show 20 Lines • Show All 1,457 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
bool CMerkleTx::IsImmatureCoinBase( | bool CMerkleTx::IsImmatureCoinBase( | ||||
interfaces::Chain::Lock &locked_chain) const { | interfaces::Chain::Lock &locked_chain) const { | ||||
// note GetBlocksToMaturity is 0 for non-coinbase tx | // note GetBlocksToMaturity is 0 for non-coinbase tx | ||||
return GetBlocksToMaturity(locked_chain) > 0; | return GetBlocksToMaturity(locked_chain) > 0; | ||||
} | } | ||||
bool CWalletTx::AcceptToMemoryPool(interfaces::Chain::Lock &locked_chain, | |||||
CValidationState &state) { | |||||
// 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 | |||||
// 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 | |||||
// unavailable as we're not yet aware that it is in the mempool. | |||||
bool ret = locked_chain.submitToMemoryPool( | |||||
::GetConfig(), tx, pwallet->m_default_max_tx_fee, state); | |||||
fInMempool |= ret; | |||||
return ret; | |||||
} | |||||
void CWallet::LearnRelatedScripts(const CPubKey &key, OutputType type) { | void CWallet::LearnRelatedScripts(const CPubKey &key, OutputType type) { | ||||
// Nothing to do... | // Nothing to do... | ||||
} | } | ||||
void CWallet::LearnAllRelatedScripts(const CPubKey &key) { | void CWallet::LearnAllRelatedScripts(const CPubKey &key) { | ||||
// Nothing to do... | // Nothing to do... | ||||
} | } | ||||
▲ Show 20 Lines • Show All 71 Lines • Show Last 20 Lines |