[Ethereum] How to store lots of private keys on a server

accountsserver-sideuser-safetyweb3.py

I am building a web app where I have to keep track of a private key associated with each user. For the sake of this discussion let's assume that it's an exchange and users can send their ETH to this address and ignore all the complexities of cold storage.

So far I have managed to cobble together this code for web3.py:

from web3 import *
web3 = Web3(IPCProvider(ipc_path='/path/to/geth.ipc'))
random_private_key = '0x71a7f0e2ef1b7ff501b65a1650d48b8d5521fadc9539eec146d4faa6f5ca9ccc'
random_password = 'qwertyuiop'
address = web3.personal.importRawKey(random_private_key, random_password)

# address -> '0x930198a4bdd322ee3305fcf0bcb106064b38754b'
# web3.eth.accounts -> [..., '0x930198a4bdd322ee3305fcf0bcb106064b38754b']

What is the correct way to generate and store these private keys? In the above example I just pulled something from the internet and modified it a bit.

My plan is to generate random private keys, dump them in a DB and import them whenever ETH from those accounts have to be transferred. Since there is no web3.personal.deleteAccount I'd have to delete the json file from the keystore after I've finished the transfer and call importRawKey again if I need to make a transfer.

I am not sure if my plan is a good one and am looking for feedback or better ways to handle this.

Best Answer

The best way to store the keys will depend on how you need to use them. For example, if you don't need to sign with them in real time, you may want to keep them on a separate system that isn't usually online. You can then give that system minimal functionality - just signing the transactions that you need signed - then send the signed transactions to your Geth node, rather than entrusting your Geth node with your keys.

If the goal of having all these separate keys is just to produce different addresses for users to pay, you have some other options that don't require you to create and manage a new random number for every address.

One option is to use use deterministic addresses based on a single root random number. Ethereum keys use the same crypto as Bitcoin keys, so the tools used for Hierarchical Deterministic Bitcoin wallets will mostly be transferable. For example, thanks to the magic of ECC addition, if you have one server that needs to be able online and interacting with the network in real time, and another that is mostly offline, you can generate a root private and public keypair on the offline system, transfer the root public key to the online system, then when you need a new address for a user with the ID 12345, generate a public key (and address) on the online server for user 12345, based on that root public key. Then when you need to spend that money, you will be able to generate the corresponding private key on the offline system.

A more Ethereum-like option is to generate a little contract for each address, controllable by a master contract, which can in turn by controllable by a multi-sig contract or using other security features. Like HD wallets, this would allow you to use a single master key or multi-sig collection of master keys to control funds sent to an unlimited number of addresses, without needing to generate an unlimited number of random numbers.