Skip to content

Commit 2702711

Browse files
committed
Merge bitcoin#34642: wallet: call SyncWithValidationInterfaceQueue after disconnecting chain notifications
98e8af4 wallet: Drain validation interface queue after notifications disconnect (Ava Chow) 52992eb interfaces: Add waitForNotifications() to call SyncWithValidationInterfaceQueue() (Ava Chow) Pull request description: When the wallet disconnects chain notifications, it is expecting no further notifications to execute, but this is not the case. This results in test failures such as in bitcoin#34354. Instead of disconnecting the notifications and continuing shutdown, we should wait for the validation interface queue to be drained before the rest of wallet shutdown. This is achieved by adding an `interfaces::Chain::waitForNotifications()` function which calls `SyncWithValidationInterfaceQueue()`. Fixes bitcoin#34354 ACKs for top commit: stickies-v: utACK 98e8af4 furszy: ACK 98e8af4 rkrux: crACK 98e8af4 sedited: ACK 98e8af4 Tree-SHA512: 263628556f740cb633d3970c22a0dfdb52a644bd1d0cd5a69c2970524edbb0e25d592cb39fc9bf1d0c281eebce09578526e2958dffee9026fc7473db35bd0dec
2 parents 6b0a980 + 98e8af4 commit 2702711

4 files changed

Lines changed: 26 additions & 3 deletions

File tree

src/interfaces/chain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,18 @@ class Chain
326326
};
327327

328328
//! Register handler for notifications.
329+
//! Some notifications are asynchronous and may still execute after the handler is disconnected.
330+
//! Use waitForNotifications() after the handler is disconnected to ensure all pending notifications
331+
//! have been processed.
329332
virtual std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) = 0;
330333

331334
//! Wait for pending notifications to be processed unless block hash points to the current
332335
//! chain tip.
333336
virtual void waitForNotificationsIfTipChanged(const uint256& old_tip) = 0;
334337

338+
//! Wait for all pending notifications up to this point to be processed
339+
virtual void waitForNotifications() = 0;
340+
335341
//! Register handler for RPC. Command is not copied, so reference
336342
//! needs to remain valid until Handler is disconnected.
337343
virtual std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) = 0;

src/node/interfaces.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,10 @@ class ChainImpl : public Chain
785785
if (!old_tip.IsNull() && old_tip == WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()->GetBlockHash())) return;
786786
validation_signals().SyncWithValidationInterfaceQueue();
787787
}
788+
void waitForNotifications() override
789+
{
790+
validation_signals().SyncWithValidationInterfaceQueue();
791+
}
788792
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
789793
{
790794
return std::make_unique<RpcHandlerImpl>(command);

src/wallet/wallet.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet
169169
WITH_LOCK(wallet->cs_wallet, wallet->WriteBestBlock());
170170

171171
// Unregister with the validation interface which also drops shared pointers.
172-
wallet->m_chain_notifications_handler.reset();
172+
wallet->DisconnectChainNotifications();
173173
{
174174
LOCK(context.wallets_mutex);
175175
std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);
@@ -3117,7 +3117,7 @@ std::shared_ptr<CWallet> CWallet::CreateNew(WalletContext& context, const std::s
31173117
walletInstance->TopUpKeyPool();
31183118

31193119
if (chain && !AttachChain(walletInstance, *chain, /*rescan_required=*/false, error, warnings)) {
3120-
walletInstance->m_chain_notifications_handler.reset(); // Reset this pointer so that the wallet will actually be unloaded
3120+
walletInstance->DisconnectChainNotifications();
31213121
return nullptr;
31223122
}
31233123

@@ -3158,7 +3158,7 @@ std::shared_ptr<CWallet> CWallet::LoadExisting(WalletContext& context, const std
31583158
walletInstance->TopUpKeyPool();
31593159

31603160
if (chain && !AttachChain(walletInstance, *chain, rescan_required, error, warnings)) {
3161-
walletInstance->m_chain_notifications_handler.reset(); // Reset this pointer so that the wallet will actually be unloaded
3161+
walletInstance->DisconnectChainNotifications();
31623162
return nullptr;
31633163
}
31643164

@@ -4577,4 +4577,14 @@ std::optional<WalletTXO> CWallet::GetTXO(const COutPoint& outpoint) const
45774577
}
45784578
return it->second;
45794579
}
4580+
4581+
void CWallet::DisconnectChainNotifications()
4582+
{
4583+
if (m_chain_notifications_handler) {
4584+
m_chain_notifications_handler->disconnect();
4585+
chain().waitForNotifications();
4586+
m_chain_notifications_handler.reset();
4587+
}
4588+
}
4589+
45804590
} // namespace wallet

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
10721072
//! Find the private key for the given key id from the wallet's descriptors, if available
10731073
//! Returns nullopt when no descriptor has the key or if the wallet is locked.
10741074
std::optional<CKey> GetKey(const CKeyID& keyid) const;
1075+
1076+
//! Disconnect chain notifications and wait for all notifications to be processed
1077+
void DisconnectChainNotifications();
10751078
};
10761079

10771080
/**

0 commit comments

Comments
 (0)