sparrow
sparrow copied to clipboard
force only a single instance to be opened at the same time
Sparrow wallet can be opened multiple times, which can lead to confusion and problems. For example, changing settings only seems to save whatever the last instance closed has set.
People using slow old computers or people who struggle with double clicking can open the application multiple times by accident. Would be nice to have a setting option that only allows a single instance to be opened at a time. If someone tries to open the application a second time, then just switch the focus to the instance that was already running.
Or, possibly make it so that that is the only way Sparrow wallet works and not have a setting to choose.
Sparrow wallet can be opened multiple times, which can lead to confusion and problems.
Actually, no it can't by design. The first instance of Sparrow opens a specific port that further instances check when launching.
How are you achieving this? Possibly there is a thread race that can achieve this if multiple instances are opened at once, but it's difficult to do much about this without better support from the OS.
I just click the icon in the launcher, wait a minute and do it again. Or, I double click on a desktop icon twice. Then I get a bunch of "Error opening wallet, Wallet file may already be in use. Make sure the application is not running elsewhere." popups. Also,
$ ps -ef|grep Sparrow
andy 29773 4536 28 11:15 ? 00:00:22 /opt/sparrow/bin/Sparrow
andy 29915 4536 12 11:15 ? 00:00:08 /opt/sparrow/bin/Sparrow
andy 30097 30075 0 11:16 pts/84 00:00:00 grep --color=auto Sparrow
$
What kind of port are you opening?
I just click the icon in the launcher, wait a minute and do it again.
I can't recreate this - what Linux flavour and desktop are you using?
What kind of port are you opening?
Sparrow will search for an open port on the loopback interface, starting from 7221 - details here: https://github.com/sparrowwallet/sparrow/blob/master/src/main/java/com/sparrowwallet/sparrow/instance/Instance.java
I am using https://xubuntu.org/ . I think I've seen this on windows too, but it was on someone else's computer and I didn't have time to try and reproduce.
Trying to understand why you are using a TCP port? Is that just a way for inter process communication? Seems like this is a bad idea since some people might fail to have a firewall installed.
Wondering why you don't use UNIX sockets instead? Here is an a (python) example: https://github.com/AndySchroder/StaticWire/blob/2e007c0db6ec8c65e2f0ba2478a31c6bff16ef82/staticIP#L49
Is that just a way for inter process communication?
Yes, effectively.
Seems like this is a bad idea since some people might fail to have a firewall installed.
A firewall on the loopback interface?
Wondering why you don't use UNIX sockets instead?
Unfortunately UNIX sockets have their own issues. They are obviously not really cross platform, and implementations differ in their approach I have found and are not consistently reliable. I had to switch from UNIX sockets for Sparrow's internal Tor back to TCP to resolve Tor startup issues.
It would be helpful if you can try debug this. My suspicion is that your system is giving you a different value for it's temporary file directory every time. Sparrow uses this location to store a file called (for example) com.sparrowwallet.sparrow.mainnet.lock
which contains the TCP port. For my Ubuntu system, this is in /tmp
.
If you bind to the loopback interface, can't other users on the system access the port still? Seems like there should be some authentication cookie required like bitcoind or X11. Also, it seems like the cookie should be present in the user's home folder and not in /tmp/
Here is the lock file that is created when the first instance starts.
$ cat /tmp/com.sparrowwallet.sparrow.mainnet.lock
7221
I am not seeing anything useful in the sparrow log file related to this problem other than that all the wallet files are locked and they can't be read (which is the same as the pop up errors that I'm getting).
If you bind to the loopback interface, can't other users on the system access the port still?
Yes, but what would they gain? One can assume that an application with access to the loopback interface can also for example send a URI to operating system, which will cause a second instance of Sparrow to launch and pass to the first (running) instance. So restricting access to the port does not really secure much I don't think.
Here is the lock file that is created when the first instance starts
Ok - so the file is created in a standard place, and the first instance of Sparrow should bind to that port. Subsequent runs should read that file and attempt to connect to the port. Unfortunately it's difficult to tell where this is going wrong on your system. Can you check if the port is actually bound?
Here is what I am getting. Please tell me a more useful message to try and send to the port besides quit
.
$ telnet localhost 7221
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
quit
!com.sparrowwallet.sparrow.mainnetConnection closed by foreign host.
If you bind to the loopback interface, can't other users on the system access the port still?
Yes, but what would they gain? One can assume that an application with access to the loopback interface can also for example send a URI to operating system, which will cause a second instance of Sparrow to launch and pass to the first (running) instance. So restricting access to the port does not really secure much I don't think.
Access to the wallet.
Not sure how the example you provided is relevant.
Consider this:
- User a launches sparrow wallet and opens wallets
- User b launches sparrow wallet and then that second instance connects to localhost port 7221.
- User b can now use user a's wallets, right?
User b can now use user a's wallets, right?
No - there is no access to a user's wallets from that port. You can pass in file paths and URIs (ones that are specifically supported) to that port for Sparrow to handle, which might be annoying but I think very low risk. Certainly you can't extract information.
That said, if you have malicious software running on the same operating system (and very often, the same user) as your Bitcoin software, you're at risk from a whole host of things that are difficult to defend against.
Here is what I am getting. Please tell me a more useful message to try and send to the port besides quit.
Ok - looks like the port is getting bound. Looks like I'll need to install Xubuntu to try figure out what is going on.
User b can now use user a's wallets, right?
No - there is no access to a user's wallets from that port. You can pass in file paths and URIs (ones that are specifically supported) to that port for Sparrow to handle, which might be annoying but I think very low risk. Certainly you can't extract information.
That said, if you have malicious software running on the same operating system (and very often, the same user) as your Bitcoin software, you're at risk from a whole host of things that are difficult to defend against.
So, confused what this function is actually trying to do again? Does the second process
- tell the first process to open a new window and then exit, or
- open a new window, stay open, and communicate the first process for everything it needs?
In either case, how does the first process know what user the second process is running under? If the first process is given commands from the second process to open specific file paths, how does that work if the first process doesn't have access to the second process's files?
Here is what I am getting. Please tell me a more useful message to try and send to the port besides quit.
Ok - looks like the port is getting bound. Looks like I'll need to install Xubuntu to try figure out what is going on.
FYI, if you already have regular ubuntu, you can run sudo apt install xubuntu-desktop
to install xubuntu on top of your existing installation. It's a little messier because you have two desktop environments and all their dependencies installed at the same time, but it works.
tell the first process to open a new window and then exit
This one - although it will likely be a new tab
how does that work if the first process doesn't have access to the second process's files
It will fail - which is probably what you want in this situation. The use case is that both Sparrow instances are created by the same user.
@craigraw I have a machine running xubuntu if you need info / help with this. FWIW I just tried and it does let me launch multiple copies of Sparrow:
ok so this is interesting - the same thing is also possible on windows - I was just able to launch two copies on windows 10
how does that work if the first process doesn't have access to the second process's files
It will fail - which is probably what you want in this situation. The use case is that both Sparrow instances are created by the same user.
That is what I want, but how does it fail if it is communicating on an unauthenticated TCP port?
Basically all user b can do is try to open a new window/tab on user a's desktop, but user b can never see that window/tab and user a can never access user b's filesystem, so that is how things are safe?
Seems like this design limits user a and user b from both using Sparrow at the same time on the same machine. Does this limitation also apply to the terminal version of Sparrow?
tell the first process to open a new window and then exit
This one - although it will likely be a new tab
What new tab will be opened if just launching Sparrow normally? Normally sparrow doesn't load any specific wallets when launching unless "Load Recent Wallets" is selected, but if this is the second lunch of sparrow, those wallets should already be opened. Will it really just change window focus to the existing sparrow wallet window?
I decided to rewrite the instance implementation to be more modern.
What Sparrow now does is:
- On launch, create a UNIX socket in Sparrow home which acts as both a lock file for that instance and an interprocess communication protocol for passing files and URIs to that instance. Since access to Sparrow home is restricted to the user starting the instance, this should resolve any privacy/security concerns. This means it's possible to run multiple instances of Sparrow using different Sparrow home locations with the
-d
argument. If Sparrow starts and the lock file is already present, any file or URI arguments will be passed to the already running instance via the UNIX socket. - In addition, Sparrow will create a symlink (or on Windows, a file containing the path) to the lock file in the user-specific default Sparrow home location. This means that even if Sparrow is started with a non-default home, the OS can still pass files and URIs to it as Sparrow will be able to find the current instance. The first instance started will be the one to receive them.
d1a353ae and subsequent commits.
It's interesting to note that macOS automatically prevents multiple instances from opening from the same installation, which is why I probably didn't notice any issues previously.
Consider this scenario:
- First instance started uses a different location with the
-d
argument. First instance places the symlink the default sparrow home - Second instance started uses the default sparrow home location, but explicitly using the
-d
argument.
In this case, can the second instance overwrite the symlink for the first with its lock file? Or, does the second instance just follow the symlink?
Seems like the second instance will probably follow the symlink.
So, it seems like if using -d
for the first instance to a non-default sparrow home location, no other instance can use the default home location. This is probably fine, but it is just worth noting.
- This means that even if Sparrow is started with a non-default home, the OS can still pass files and URIs to it as Sparrow will be able to find the current instance. The first instance started will be the one to receive them.
Generally, I like this approach. With multiple profiles in firefox, I get the same type of experience. In firefox, the first profile started I consider to be my main instance where links will open and any subsequent profiles are special ones that are self contained and don't receive any messages from the rest of the operating system. The same thought process can apply well to multiple instances of sparrow.
In this case, can the second instance overwrite the symlink for the first with its lock file?
No - and the symlink is only deleted once the first instance exits.
Or, does the second instance just follow the symlink?
The only time the symlink is followed is if there are file or URI arguments to the program. This is how the OS will pass them to Sparrow. This is not normally how Sparrow is ever run by a user, although it's perfectly ok to use it in this manner. The second instance, launched by the OS, will exit after communicating these arguments to the first instance.
If there are no file or URI arguments, and the second instance is trying to use the same Sparrow home as the first, it will simply exit.
If there are no file or URI arguments, and the second instance is trying to use the same Sparrow home as the first, it will simply exit.
Wondering in this case if you can make the first instance come to the foreground if it is minimized or in the background? For example, what if you have sparrow running in another workspace and you don't realize it, then you will keep trying to launch sparrow and wonder why nothing happens.
Good idea, implemented in 6b4c3014.
Good idea, implemented in 6b4c301.
Just tested in version 1.8.5 and I am no longer getting multiple instances but if the window is minimized or in the background it is not coming to the foreground when re-launching sparrow.
if the window is minimized
Added this behaviour in 5a0df265.
in the background
This I can't reproduce - I get the existing window coming to the foreground when the second instance is launched.
if the window is minimized
Added this behaviour in 5a0df26.
This works for me in the same workspace.
If in a different workspace, the window is moved to the current workspace and restored, but it can be behind an existing window.
in the background
This I can't reproduce - I get the existing window coming to the foreground when the second instance is launched.
Still not getting it to come to the foreground if it is already restored (un-minimized), it just stays behind whatever window is already in the foreground.
Which desktop environments are you testing with?
If in a different workspace, the window is moved to the current workspace and restored, but it can be behind an existing window.
This is probably implementation-specific to the windowing system in use. Might be difficult to solve this in general.
Which desktop environments are you testing with?
It would definitely have been tested on stock Ubuntu 20.01 - I may have tested on other environments as well. Which is it not working on?