Skip to content

Conversation

@AkioNak
Copy link
Contributor

@AkioNak AkioNak commented Dec 11, 2018

wallet_multiwallet.py --usecli may sometimes fails with
"Duplicate -wallet filename specified"
unloadwallet() RPC command just notify the unload intention
and it may delay a little bit until actual unloading.

This patch check the completion of unloading by using listwallets().

This fixes #14917

@fanquake fanquake added the Tests label Dec 11, 2018
@promag
Copy link
Contributor

promag commented Dec 11, 2018

Not sure if this is the right fix, IIRC the wallet is removed from the list first and then the actual unload happens.

@kallewoof
Copy link
Contributor

The relevant code is

bitcoin/src/wallet/wallet.cpp

Lines 3879 to 3883 in 5f23460

// Make sure that the wallet path doesn't clash with an existing wallet path
if (IsWalletLoaded(wallet_path)) {
error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
return false;
}

The wallet itself has locks to prevent it from being loaded while already loaded, so it seems like an OK fix to me.

@promag
Copy link
Contributor

promag commented Dec 11, 2018

@kallewoof that's what happening, it hits that error.

It's always the case that after unloadwallet X listwallets doesn't return X but that wallet can be unloading. This change only reduces the race to the actual duplicate condition.

I see 4 solutions:

  1. add an option to unloadwallet to force waiting 👍 👍
  2. use this change but also change listwallets to actually verify if the wallet is not unloaded 👎
  3. make loadwallet aware the wallet is unloading and wait for it 👍
  4. change the test to repeat the loadwallet until it succeeds 👍 👍 👍 👍

Note that there are 2 wallet "registries":

std::vector<std::shared_ptr<CWallet>> GetWallets()
{
LOCK(cs_wallets);
return vpwallets;
}

bool IsWalletLoaded(const fs::path& wallet_path)
{
fs::path env_directory;
std::string database_filename;
SplitWalletPath(wallet_path, env_directory, database_filename);
LOCK(cs_db);
auto env = g_dbenvs.find(env_directory.string());
if (env == g_dbenvs.end()) return false;
return env->second.IsDatabaseLoaded(database_filename);
}

@AkioNak
Copy link
Contributor Author

AkioNak commented Dec 11, 2018

@promag @kallewoof Thank you for the discussion.

change the test to repeat the loadwallet until it succeeds 👍 👍 👍 👍

I will try this.

@promag
Copy link
Contributor

promag commented Dec 12, 2018

@AkioNak you could add an option to wait_until, untested:

diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index d0a78d8df..4af7a51ff 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -201,20 +201,24 @@ def str_to_b64str(string):
 def satoshi_round(amount):
     return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)

-def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None):
+def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, ignore_expections=False):
     if attempts == float('inf') and timeout == float('inf'):
         timeout = 60
     attempt = 0
     time_end = time.time() + timeout

     while attempt < attempts and time.time() < time_end:
-        if lock:
-            with lock:
+        try:
+            if lock:
+                with lock:
+                    if predicate():
+                        return
+            else:
                 if predicate():
                     return
-        else:
-            if predicate():
-                return
+        except JSONRPCException as e:
+            if not ignore_expections:
+                raise e
         attempt += 1
         time.sleep(0.05)

And then:

wait_until(lambda: self.nodes[0].loadwallet(wallet_name), ignore_exceptions=True)

BTW, now I'm more fond of

make loadwallet aware the wallet is unloading and wait for it

@ryanofsky what are your thoughts?

@ryanofsky
Copy link
Contributor

make loadwallet aware the wallet is unloading and wait for it

I think a better approach would be to make unloadwallet aware that a wallet is unloading and wait for it. It's surprising to me that this would be an asynchronous operation.

@promag
Copy link
Contributor

promag commented Dec 12, 2018

@ryanofsky the idea was to not block especially if the wallet is being used or a rescan is going on. In that case the client could timeout and then the problem would be the same — attempt to load would raise Duplicate -wallet filename specified error. But maybe we should ignore these edge cases and make it synchronous or even add an option?

@maflcko
Copy link
Member

maflcko commented Dec 12, 2018

Agree with @ryanofsky. Seems unnecessary to make this call async. If the wallet is in use (e.g. rescan) you should be aware of it and not call unloadwallet. So shouldn't unloadwallet throw an error in that case?

wallet_multiwallet.py --usecli may sometimes fails with
"Duplicate -wallet filename specified"
Unloadwallet RPC command just notify the unload intention
and it may delay a little bit until actual unloading.

This patch make loadwallet to retry if JSONRPCException occurs.
@AkioNak AkioNak force-pushed the confirm_unloadwallet_done branch from 67ccb4f to 52b380b Compare December 13, 2018 06:35
@laanwj
Copy link
Member

laanwj commented Dec 13, 2018

Closing in favor of #14941

@laanwj laanwj closed this Dec 13, 2018
@kallewoof
Copy link
Contributor

@laanwj Please do not close PR:s unless there is inactivity or the author is clearly not cooperating. The authors are perfectly capable of doing this themselves.

@laanwj
Copy link
Member

laanwj commented Dec 13, 2018

@kallewoof I don't think there's a point of having multiple competing PRs open, this spreads discussion around, reopening is always a possibility if discussion goes the other way

@kallewoof
Copy link
Contributor

I understand your desire to have a clean list of PRs, but there really is no rush on the matter. This PR literally had pushes to it hours before you closed it. If the author judges that the replacement is objectively better they will close their PR on their own, and if they refuse, I see no problem with you making a judgement call like this one.

@laanwj
Copy link
Member

laanwj commented Dec 14, 2018

I'm not sure how you're interpreting it, but for me, closing the PR is only an indication that it's currently not considered for merging. It doesn't delete the discussion, doesn't even prevent replying! it doesn't delete the code changes, etc.

That's a typical maintainer task. at least for me it has nothing to do with 'urgency' or capability or non-capability of the author to do it themselves.

But anyhow if you insist I'll re-open.

@laanwj laanwj reopened this Dec 14, 2018
@kallewoof
Copy link
Contributor

kallewoof commented Dec 14, 2018

Removing my comment as it strays off topic from the PR. I've sent it to @laanwj in private.

@promag
Copy link
Contributor

promag commented Dec 14, 2018

@kallewoof I don't think it makes sense to change the test tree to later revert. There is already agreement to change unloadwallet and @laanwj just closed this in light of that - being closed doesn't mean is locked and dead.

@laanwj
Copy link
Member

laanwj commented Dec 14, 2018

Yes, so I think there's a misunderstanding here:
Thanks @AkioNak for trying to fix the test!

However your PR made us realize that the current unloadwallet behavior is broken in the first place and that the unload shouldn't be asynchronous, and the test failure is pointing out an actual issue. It likely means that the test doesn't need to change.

@AkioNak
Copy link
Contributor Author

AkioNak commented Dec 14, 2018

@kallewoof @promag @ryanofsky @MarcoFalke @laanwj Thank you so much.
Now I understand that we need to fix the behaviour of unloadwallet rather than changing the test.
So, I close this PR myself.

@AkioNak AkioNak closed this Dec 14, 2018
@promag
Copy link
Contributor

promag commented Dec 14, 2018

Thank you @AkioNak for identifying the problem so quick.

@AkioNak AkioNak deleted the confirm_unloadwallet_done branch January 11, 2019 01:20
laanwj added a commit that referenced this pull request Jan 15, 2019
645e905 doc: Add release notes for unloadwallet change to synchronous call (João Barbosa)
c37851d rpc: Make unloadwallet wait for complete wallet unload (João Barbosa)

Pull request description:

  Currently the `unloadwallet` RPC is asynchronous, it only signals the intent to unload the wallet and then returns the response to the client. The actual unload can happen later and the client has no way to be notified of that.

  This PR makes the `unloadwallet` RPC synchronous, meaning that it blocks until the wallet is fully unloaded.

  Replaces #14919, fixes #14917.

Tree-SHA512: ad88b980e2f3652809a58f904afbfe020299f3aa6a517f495ba943b8d54d4520f6e70074d6749be8f5967065c0f476e0faedcde64c8b4899e5f99c70f0fd6534
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Sep 8, 2021
…unload

645e905 doc: Add release notes for unloadwallet change to synchronous call (João Barbosa)
c37851d rpc: Make unloadwallet wait for complete wallet unload (João Barbosa)

Pull request description:

  Currently the `unloadwallet` RPC is asynchronous, it only signals the intent to unload the wallet and then returns the response to the client. The actual unload can happen later and the client has no way to be notified of that.

  This PR makes the `unloadwallet` RPC synchronous, meaning that it blocks until the wallet is fully unloaded.

  Replaces bitcoin#14919, fixes bitcoin#14917.

Tree-SHA512: ad88b980e2f3652809a58f904afbfe020299f3aa6a517f495ba943b8d54d4520f6e70074d6749be8f5967065c0f476e0faedcde64c8b4899e5f99c70f0fd6534
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wallet_multiwallet --usecli fails with "Duplicate -wallet filename specified"

7 participants