I'm working on a site that has wallet-like functionality in ruby/rails. I'm wondering the best way to process withdraws. My first inclination is to do something like this:

def process_withdraw
  client.wallet_passphrase(ENV['wallet_password'], 10) # unlock the wallet for 10 seconds
  client.send_to_address(address, amount) # send coins
  client.wallet_lock # re-lock the wallet

However, I'm concerned that with many concurrent withdraws I could run into race conditions. For example, if "Process A" unlocks the wallet and sends coins, but then "Process B" jumps in and unlocks the wallet but before it can send coins, "Process A" locks the wallet. So when "Process B" tries to send, the wallet is locked.

Is this a legitimate concern? Do I need to re-lock the wallet or is it safe enough to just wait for the 10 second timeout? Is it worth writing some sort of queue system for my client?

Thanks a lot in advance!

  • What is the password on the wallet protecting you against? If your server is compromised then they have your code and your password anyway, you're just making life hard for yourself. There's really no situation where having a locked wallet is helpful to you here. If you insist, look into making a locking system, process A locks, does it's actions, then removes the lock. Process B queues and waits for the lock to be removed before continuing. – user13413 Mar 3 '14 at 19:27
  • I'm considering running the site on Heroku in production with the dogeoin daemon on ec2 (since heroku doesn't allow write access to the file system.) So the thought was if attackers could somehow get the dogecoind username/password correct, they still wouldn't be able to unlock the wallet. I think you're right though, I'm probably making this too difficult. – repp Mar 3 '14 at 19:34
  • Long password + forced SSL on the RPC port, or just use a VPN and don't expose the port altogether. If they did have RPC access but no encryption password, they could just wait for the 10 second window and snake your funds out then. – user13413 Mar 3 '14 at 22:47
  • Yea, great point. I just won't worry about re-locking the wallet. Thanks a lot! – repp Mar 4 '14 at 5:29

If the wallet unlock is global (that is, it affects a wallet that exists outside the method, which it clearly does), then yes, that is a race condition. Generally, this is handled with mutexes. A mutex provides "mutual exclusion", that is, only one thread of execution can enter an area protected with the mutex.

From a software design point of view, forcing everything that calls the send_to_address method to do so in a mutex is very bad design. It seems you should make a wallet class that encapsulates all the functionality you need to perform on wallets that manages the locking/unlocking of the wallet inside the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.