Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
static void ReleaseWallet(CWallet *wallet) { | static void ReleaseWallet(CWallet *wallet) { | ||||
// Unregister and delete the wallet right after | // Unregister and delete the wallet right after | ||||
// BlockUntilSyncedToCurrentChain so that it's in sync with the current | // BlockUntilSyncedToCurrentChain so that it's in sync with the current | ||||
// chainstate. | // chainstate. | ||||
const std::string name = wallet->GetName(); | const std::string name = wallet->GetName(); | ||||
wallet->WalletLogPrintf("Releasing wallet\n"); | wallet->WalletLogPrintf("Releasing wallet\n"); | ||||
wallet->BlockUntilSyncedToCurrentChain(); | wallet->BlockUntilSyncedToCurrentChain(); | ||||
wallet->Flush(); | wallet->Flush(); | ||||
UnregisterValidationInterface(wallet); | wallet->m_chain_notifications_handler.reset(); | ||||
delete wallet; | delete wallet; | ||||
// Wallet is now released, notify UnloadWallet, if any. | // Wallet is now released, notify UnloadWallet, if any. | ||||
{ | { | ||||
LOCK(g_wallet_release_mutex); | LOCK(g_wallet_release_mutex); | ||||
if (g_unloading_wallet_set.erase(name) == 0) { | if (g_unloading_wallet_set.erase(name) == 0) { | ||||
// UnloadWallet was not called for this wallet, all done. | // UnloadWallet was not called for this wallet, all done. | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,167 Lines • ▼ Show 20 Lines | void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
auto it = mapWallet.find(ptx->GetId()); | auto it = mapWallet.find(ptx->GetId()); | ||||
if (it != mapWallet.end()) { | if (it != mapWallet.end()) { | ||||
it->second.fInMempool = false; | it->second.fInMempool = false; | ||||
} | } | ||||
} | } | ||||
void CWallet::BlockConnected( | void CWallet::BlockConnected( | ||||
const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | const CBlock &block, const std::vector<CTransactionRef> &vtxConflicted) { | ||||
const std::vector<CTransactionRef> &vtxConflicted) { | const BlockHash &block_hash = block.GetHash(); | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// TODO: Temporarily ensure that mempool removals are notified before | // TODO: Temporarily 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 inadvertently cleared by the notification | // transaction and then have it inadvertently 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, BlockHash(), 0 /* position in block */); | SyncTransaction(ptx, BlockHash(), 0 /* position in block */); | ||||
TransactionRemovedFromMempool(ptx); | TransactionRemovedFromMempool(ptx); | ||||
} | } | ||||
for (size_t i = 0; i < pblock->vtx.size(); i++) { | for (size_t i = 0; i < block.vtx.size(); i++) { | ||||
SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i); | SyncTransaction(block.vtx[i], block_hash, i); | ||||
TransactionRemovedFromMempool(pblock->vtx[i]); | TransactionRemovedFromMempool(block.vtx[i]); | ||||
} | } | ||||
m_last_block_processed = pindex->GetBlockHash(); | m_last_block_processed = block_hash; | ||||
} | } | ||||
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) { | void CWallet::BlockDisconnected(const CBlock &block) { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
for (const CTransactionRef &ptx : pblock->vtx) { | for (const CTransactionRef &ptx : block.vtx) { | ||||
SyncTransaction(ptx, BlockHash(), 0 /* position in block */); | SyncTransaction(ptx, BlockHash(), 0 /* position in block */); | ||||
} | } | ||||
} | } | ||||
void CWallet::BlockUntilSyncedToCurrentChain() { | void CWallet::BlockUntilSyncedToCurrentChain() { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
AssertLockNotHeld(cs_wallet); | AssertLockNotHeld(cs_wallet); | ||||
{ | { | ||||
// Skip the queue-draining stuff if we know we're caught up with | // Skip the queue-draining stuff if we know we're caught up with | ||||
// ::ChainActive().Tip()... | // ::ChainActive().Tip()... | ||||
// We could also take cs_wallet here, and call m_last_block_processed | // We could also take cs_wallet here, and call m_last_block_processed | ||||
// protected by cs_wallet instead of cs_main, but as long as we need | // protected by cs_wallet instead of cs_main, but as long as we need | ||||
// cs_main here anyway, it's easier to just call it cs_main-protected. | // cs_main here anyway, it's easier to just call it cs_main-protected. | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
if (!m_last_block_processed.IsNull() && | if (!m_last_block_processed.IsNull() && | ||||
locked_chain->isPotentialTip(m_last_block_processed)) { | locked_chain->isPotentialTip(m_last_block_processed)) { | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
// ...otherwise put a callback in the validation interface queue and wait | // ...otherwise put a callback in the validation interface queue and wait | ||||
// for the queue to drain enough to execute it (indicating we are caught up | // for the queue to drain enough to execute it (indicating we are caught up | ||||
// at least with the time we entered this function). | // at least with the time we entered this function). | ||||
SyncWithValidationInterfaceQueue(); | chain().waitForNotifications(); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxIn &txin) const { | isminetype CWallet::IsMine(const CTxIn &txin) const { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::map<TxId, CWalletTx>::const_iterator mi = | std::map<TxId, CWalletTx>::const_iterator mi = | ||||
mapWallet.find(txin.prevout.GetTxId()); | mapWallet.find(txin.prevout.GetTxId()); | ||||
if (mi != mapWallet.end()) { | if (mi != mapWallet.end()) { | ||||
const CWalletTx &prev = (*mi).second; | const CWalletTx &prev = (*mi).second; | ||||
▲ Show 20 Lines • Show All 911 Lines • ▼ Show 20 Lines | for (const std::pair<const unsigned int, CWalletTx *> &item : mapSorted) { | ||||
if (wtx.RelayWalletTransaction(locked_chain)) { | if (wtx.RelayWalletTransaction(locked_chain)) { | ||||
result.push_back(wtx.GetId()); | result.push_back(wtx.GetId()); | ||||
} | } | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, | void CWallet::ResendWalletTransactions(interfaces::Chain::Lock &locked_chain, | ||||
CConnman *connman) { | int64_t nBestBlockTime) { | ||||
// Do this infrequently and randomly to avoid giving away that these are our | // Do this infrequently and randomly to avoid giving away that these are our | ||||
// transactions. | // transactions. | ||||
if (GetTime() < nNextResend || !fBroadcastTransactions) { | if (GetTime() < nNextResend || !fBroadcastTransactions) { | ||||
return; | return; | ||||
} | } | ||||
bool fFirst = (nNextResend == 0); | bool fFirst = (nNextResend == 0); | ||||
nNextResend = GetTime() + GetRand(30 * 60); | nNextResend = GetTime() + GetRand(30 * 60); | ||||
if (fFirst) { | if (fFirst) { | ||||
return; | return; | ||||
} | } | ||||
// 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 (nBestBlockTime < nLastResend) { | if (nBestBlockTime < nLastResend) { | ||||
return; | return; | ||||
} | } | ||||
nLastResend = GetTime(); | nLastResend = GetTime(); | ||||
// Temporary. Removed in upcoming lock cleanup | |||||
auto locked_chain = chain().assumeLocked(); | |||||
// 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<uint256> relayed = | ||||
ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime - 5 * 60); | ResendWalletTransactionsBefore(locked_chain, nBestBlockTime - 5 * 60); | ||||
if (!relayed.empty()) { | if (!relayed.empty()) { | ||||
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", | WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", | ||||
__func__, relayed.size()); | __func__, relayed.size()); | ||||
} | } | ||||
} | } | ||||
/** @} */ // end of mapWallet | /** @} */ // end of mapWallet | ||||
▲ Show 20 Lines • Show All 2,474 Lines • ▼ Show 20 Lines | if (tip_height && *tip_height != rescan_height) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
chain.loadWallet(interfaces::MakeWallet(walletInstance)); | chain.loadWallet(interfaces::MakeWallet(walletInstance)); | ||||
// Register with the validation interface. It's ok to do this after rescan | // Register with the validation interface. It's ok to do this after rescan | ||||
// since we're still holding cs_main. | // since we're still holding locked_chain. | ||||
RegisterValidationInterface(walletInstance.get()); | walletInstance->m_chain_notifications_handler = | ||||
chain.handleNotifications(*walletInstance); | |||||
walletInstance->SetBroadcastTransactions( | walletInstance->SetBroadcastTransactions( | ||||
gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); | gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); | ||||
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", | walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", | ||||
walletInstance->GetKeyPoolSize()); | walletInstance->GetKeyPoolSize()); | ||||
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", | walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", | ||||
walletInstance->mapWallet.size()); | walletInstance->mapWallet.size()); | ||||
▲ Show 20 Lines • Show All 158 Lines • Show Last 20 Lines |