-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Add unloadwallet RPC #13111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add unloadwallet RPC #13111
Conversation
580e822
to
72bbee3
Compare
55eb478
to
4cb3e57
Compare
80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once #13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces #11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce
a07427d
to
8b490cd
Compare
c3cbfd8
to
3a0da11
Compare
Rebased, added release notes and functional tests. |
3a0da11
to
e95206b
Compare
If a wallet is loaded after being unloaded then a segfault is raised: Process 10688 stopped
* thread #2, name = 'bitcoin-httpworker', stop reason = EXC_BAD_ACCESS (code=1, address=0x608)
frame #0: 0x0000000100a0ad18 libdb_cxx-4.8.dylib`DbEnv::set_lg_dir(char const*) + 38
libdb_cxx-4.8.dylib`DbEnv::set_lg_dir:
-> 0x100a0ad18 <+38>: callq *0x608(%rdi)
0x100a0ad1e <+44>: movl %eax, %ebx
0x100a0ad20 <+46>: testl %ebx, %ebx
0x100a0ad22 <+48>: je 0x100a0ad40 ; <+78>
Target 0: (bitcoind) stopped.
(lldb) bt
* thread #2, name = 'bitcoin-httpworker', stop reason = EXC_BAD_ACCESS (code=1, address=0x608)
* frame #0: 0x0000000100a0ad18 libdb_cxx-4.8.dylib`DbEnv::set_lg_dir(char const*) + 38
frame #1: 0x000000010026f0bf bitcoind`BerkeleyEnvironment::Open(this=0x0000000101900e68, retry=<unavailable>) at db.cpp:150 [opt]
frame #2: 0x0000000100274a8a bitcoind`BerkeleyBatch::VerifyEnvironment(file_path=<unavailable>, errorStr="") at db.cpp:335 [opt]
frame #3: 0x000000010030bd1f bitcoind`CWallet::Verify(wallet_file="�.\n\0p\0\0\x19\0\0\0\0\0\0\0\0\0���\x7f\0\0\x19\0\0\0\0\0\0\0p�.\n\0p\0\0\x012�w�, salvage_wallet=<unavailable>, error_string=<unavailable>, warning_string="") at wallet.cpp:4022 [opt]
frame #4: 0x00000001002c1419 bitcoind`loadwallet(request=<unavailable>) at rpcwallet.cpp:3098 [opt]
frame #5: 0x00000001001820ba bitcoind`CRPCTable::execute(this=<unavailable>, request=0x000070000a2eaab0) const at server.cpp:497 [opt]
frame #6: 0x000000010001cc57 bitcoind`HTTPReq_JSONRPC(req=0x0000000101a7e1d0, (null)=<unavailable>) at httprpc.cpp:191 [opt]
frame #7: 0x000000010002977b bitcoind`HTTPWorkItem::operator()() [inlined] std::__1::function<bool (HTTPRequest*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)>::operator(this=<unavailable>, __arg=0x0000000101a7e1d0, __arg=<unavailable>)(HTTPRequest*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const at functional:1914 [opt]
frame #8: 0x000000010002976e bitcoind`HTTPWorkItem::operator(this=<unavailable>)() at httpserver.cpp:54 [opt]
frame #9: 0x000000010002b060 bitcoind`WorkQueue<HTTPClosure>::Run(this=0x0000000101801430) at httpserver.cpp:113 [opt]
frame #10: 0x000000010002c03a bitcoind`void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*> >(void*) [inlined] decltype(std::__1::forward<void (*)(WorkQueue<HTTPClosure>*)>(fp)(std::__1::forward<WorkQueue<HTTPClosure>*>(fp0))) std::__1::__invoke<void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*>(void (*&&)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*&&) at type_traits:4291 [opt]
frame #11: 0x000000010002c032 bitcoind`void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*> >(void*) [inlined] void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*, 2ul>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*>&, std::__1::__tuple_indices<2ul>) at thread:336 [opt]
frame #12: 0x000000010002c032 bitcoind`void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(WorkQueue<HTTPClosure>*), WorkQueue<HTTPClosure>*> >(__vp=0x0000000101ad8af0) at thread:346 [opt]
frame #13: 0x00007fff77cd66c1 libsystem_pthread.dylib`_pthread_body + 340
frame #14: 0x00007fff77cd656d libsystem_pthread.dylib`_pthread_start + 377
frame #15: 0x00007fff77cd5c5d libsystem_pthread.dylib`thread_start + 13 Edit: Fixed in last commit. |
4f9f422
to
ba6a970
Compare
new warning:
|
f33ff8c
to
d968dc3
Compare
The
|
@ken2812221 corrupt how? Can't reproduce. |
Oh, the wallet does not corrupt. It's a libevent error, but the message says that the wallet corrupts. It might because I open so many connections at a short period of time, restart bitcoind fix the problem. Does not related to this PR
|
Is this related to the libevent error? |
Probobly the wallet would fail to close after the libevent error. Restart the node fix the issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a bug where if you run loadwallet <wallet>
and then unloadwallet <wallet>
, <wallet>
isn't removed from the dropdown menu (if you call unloadwallet <wallet>
on a wallet that was loaded at startup, it is removed.)
In general, the GUI doesn't seem to recognise unloading wallets that were loaded dynamically.
src/wallet/wallet.h
Outdated
@@ -1101,6 +1101,8 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface | |||
* Address book entry changed. | |||
* @note called with lock cs_wallet held. | |||
*/ | |||
boost::signals2::signal<void ()> Unload; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've placed this between NotifyAddressBookChanged()
and its comment. Please move it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yap.
src/wallet/rpcwallet.cpp
Outdated
UnregisterValidationInterface(wallet.get()); | ||
wallet->BlockUntilSyncedToCurrentChain(); | ||
wallet->Flush(true); | ||
wallet->Unload(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In commit rpc: Add unloadwallet RPC, this doesn't build (CWallet.Unload()
is only added in ui: Support wallets unloaded dynamically)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
assert_equal(self.nodes[0].listwallets(), []) | ||
|
||
# Successfully load a previously unloaded wallet | ||
self.nodes[0].loadwallet('w1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please assert that wallet w1 appears in listwallets
and is usable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
0496cfb
to
0b82bac
Compare
Segfault with QT:
Process 87183 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x00000001000b3edc bitcoin-qt`SendCoinsDialog::updateSmartFeeLabel(this=0x0000000124329810) at sendcoinsdialog.cpp:697 [opt] 694 coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels 695 int returned_target; 696 FeeReason reason; -> 697 CFeeRate feeRate = CFeeRate(model->wallet().getMinimumFee(1000, coin_control, &returned_target, &reason)); 698 699 ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB"); 700
|
@PierreRochard thanks for testing. I'm able to reproduce it. After your steps (which don't harm), call Lines 87 to 90 in 3f398d7
which happens after https://github.com/bitcoin/bitcoin/pull/13111/files#diff-8c9d79ba40bf702f01685008550ac100R483. Will fix. |
@PierreRochard actually |
Tested ACK fe65bde @jonasschnelli and @PierreRochard issues are fixed. |
@promag, thanks for the explanation, I really like this pull request. Maybe the issue is that URI should be populated after unload/load, it currently isn't: |
@PierreRochard it can be improved in a follow up. |
That's fair, tested ACK fe65bde |
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
static void ReleaseWallet(CWallet* wallet) | ||
{ | ||
LogPrintf("Releasing wallet %s\n", wallet->GetName()); | ||
wallet->BlockUntilSyncedToCurrentChain(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for this call? It seems very fragile because BlockUntilSyncedToCurrentChain may try to schedule a callback, but wallets currently get deleted after the scheduler is deleted:
Lines 297 to 299 in baf3a3a
GetMainSignals().UnregisterBackgroundSignalScheduler(); | |
GetMainSignals().UnregisterWithMempoolSignals(mempool); | |
g_wallet_init_interface.Close(); |
I was seeing this cause a crash due to a subtle change in behavior in one of my prs, which took me a long time to debug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initial idea was to avoid dangling pointers to the wallet in the validation queue. I agree that once in the deleter no more pointers to the wallet should exist. Do you suggest removing this call? Which PR are you referring?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initial idea was to avoid dangling pointers to the wallet in the validation queue.
@promag I think it would be better to just call UnregisterValidationInterface in this case. That looks like it would remove any wallet references from the notification code without needing to block wallet deletion on the scheduler thread or run additional notification handling code.
I agree that once in the deleter no more pointers to the wallet should exist. Do you suggest removing this call? Which PR are you referring?
Yesterday the problem I saw was in #10973. It slightly changed the way m_last_block_processed
got set during rescans leading to a new SyncWithValidationInterfaceQueue()
call in SyncWithValidationInterfaceQueue
that doesn't happen in master. The SyncWithValidationInterfaceQueue
call would fail with an assert error due to signal scheduler being deleted before the wallet in the init code shown above.
Today this is causing another problem in #11625. In this case, there seems to be a race condition there where the wallet sometimes gets deleted in a qt event thread after UnloadBlockIndex
gets called in another thread.
80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once bitcoin#13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces bitcoin#11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce
80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once bitcoin#13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces bitcoin#11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce
80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once bitcoin#13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces bitcoin#11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce
80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once bitcoin#13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces bitcoin#11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce
) 80b4910 wallet: Use shared pointer to retain wallet instance (João Barbosa) Pull request description: Currently there are 3 places where it makes sense to retain a wallet shared pointer: - `vpwallets`; - `interfaces::Wallet` interface instance - used by the UI; - wallet RPC functions - given by `GetWalletForJSONRPCRequest`. The way it is now it is possible to have, for instance, listunspent RPC and in parallel unload the wallet (once bitcoin#13111 is merged) without blocking. Once the RPC finishes, the shared pointer will release the wallet. It is also possible to get all existing wallets without blocking because the caller keeps a local list of shared pointers. This is mostly relevant for wallet unloading. This PR replaces bitcoin#11402. Tree-SHA512: b7e37c7e1ab56626085afe2d40b1628e8d4f0dbda08df01b7e618ecd2d894ce9b83d4219443f444ba889096286eff002f163cb0a48f37063b62e9ba4ccfa6cce Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com>
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets.