electrum-personal-server

Maximally lightweight electrum server for a single user
git clone https://git.parazyd.org/electrum-personal-server
Log | Files | Refs | README

commit 76386c21c7e1c6b766949144be00dd59036ba559
parent 471fc07f4e89b11919017c2f912301c912ba93ae
Author: chris-belcher <chris-belcher@users.noreply.github.com>
Date:   Fri, 16 Mar 2018 13:03:30 +0000

added code and default cert files to handle ssl, the user can generate their own self-signed cert files but its not necessary for security

Diffstat:
MREADME.md | 14++++----------
Acert.crt | 19+++++++++++++++++++
Acert.key | 27+++++++++++++++++++++++++++
Mconfig.cfg_sample | 8+++++++-
Mserver.py | 46+++++++++++++++++++++++++---------------------
5 files changed, 82 insertions(+), 32 deletions(-)

diff --git a/README.md b/README.md @@ -38,13 +38,10 @@ wallet addresses to the `[wallets]` section. Finally run `./server.py` on Linux or double-click `run-server.bat` on Windows. The first time the server is run it will import all configured addresses as watch-only into the Bitcoin node, and then exit giving you a chance to -`-rescan` if your wallet contains historical transactions. +rescan if your wallet contains historical transactions. -Electrum wallet must be configured to connect to the server. SSL must be -disabled which can be done either by `Tools` -> `Connection` -> Uncheck box -`Use SSL`, or starting with the command line flag `--nossl`, depending on the -version of Electrum. Tell Electrum to connect to the server in -`Tools` -> `Server`, usually `localhost` if running on the same machine. +Tell Electrum to connect to the server in `Tools` -> `Server`, usually +`localhost` if running on the same machine. Note that you can also try this with on [testnet bitcoin](https://en.bitcoin.it/wiki/Testnet). Electrum can be started in testnet mode with the command line flag `--testnet`. @@ -64,8 +61,6 @@ tunnel. This project is in alpha stages as there are several essential missing features such as: -* The server does not support SSL so Electrum must be configured to disable it. - * Deterministic wallets and master public keys are not supported. Addresses must be imported individually. @@ -90,4 +85,4 @@ I can be contacted on freenode IRC on the `#bitcoin` and `#electrum` channels. ## Media Coverage -* https://bitcoinmagazine.com/articles/electrum-personal-server-will-give-users-full-node-security-they-need/- \ No newline at end of file +* https://bitcoinmagazine.com/articles/electrum-personal-server-will-give-users-full-node-security-they-need/ diff --git a/cert.crt b/cert.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQDRr9lL8wL3+jANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE4MDMxMzAwMDc1OFoXDTIzMDMxMjAwMDc1OFowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALvqB0SrsncAhIkvmkLhhE4GW0MKGQognd1Vm67gnOZ4rC2+HwF3xS1xpJDZIjRJ +Tump6bp4dFoyty2vsrWJzzBib3xPh6yx37cqkQkLS7mlvl5J+VaV3vefW9Jt84Me +hT2xH62haZ6gyAI2OItyoC57uiKGJ/4TNcXZRchc3Ee1R29q5evMjJRBG6QLfHmc +btsSquPwIoGxaTICNZmmZlHKct+6bBGGbJ1tJttWCeLQe//rW9KBs+Ip3heNxZpQ +RZgPYwxFhZg4g4nv0CmIeMCC8KBZE82P4SRjMirVZD0YH/nNYQTEGwutZZ8F0K8Z +pWR1/HDXLQVeF66SreRxp98CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEATELegjEF +03r1SWSsJ2Jhg4gLDLi3tORqHFzu3S8JECi57geZKmF7NmhJHXd0vemusX9P8IRh +A0B9mEU8e92k2fenqxj/t71rm+e71PBU2GwXsE5vtkX/AGmsk6KhAsbe56A3IUGK +JvS3HZ2JS9MmwoUI3cHB5ExBisk4YkDripA6cIkF4i9ctQbk3bzN7FhCbj9wrKBR +Lg48tbswQw4UUUZ70U5uW3pt9pPbDErSifBv6UMoY8A2s4RqiyXDyI/cxVFsY71A +c+tInksyG4KAeDo919/Y0bNjgzOCt267ApQE96j4lnGCx/KSwduWBNMng6qeTecx +ZOyPoABtFZcv1g== +-----END CERTIFICATE----- diff --git a/cert.key b/cert.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAu+oHRKuydwCEiS+aQuGETgZbQwoZCiCd3VWbruCc5nisLb4f +AXfFLXGkkNkiNElO6anpunh0WjK3La+ytYnPMGJvfE+HrLHftyqRCQtLuaW+Xkn5 +VpXe959b0m3zgx6FPbEfraFpnqDIAjY4i3KgLnu6IoYn/hM1xdlFyFzcR7VHb2rl +68yMlEEbpAt8eZxu2xKq4/AigbFpMgI1maZmUcpy37psEYZsnW0m21YJ4tB7/+tb +0oGz4ineF43FmlBFmA9jDEWFmDiDie/QKYh4wILwoFkTzY/hJGMyKtVkPRgf+c1h +BMQbC61lnwXQrxmlZHX8cNctBV4XrpKt5HGn3wIDAQABAoIBAHjQSuH8nZ3i6FMn +Fr+/LAfaEFy2pkiblcNSoeg6IsYOeWxjWp3f+hZwhQRXhaUmKKUUB+BKR0wiZSDr +YDNVKa8K6nB61VjTd2jU5jBxYbs284C9gKAJdTOw8iEFbdU0DygNs7c3GqfQ6SZ6 +47nL9W5NP+uoYxf4E89jFHlwMnOq3n2vW3TUIys0Op3RG40VqKEhU/XsOIjU5B7C +HN2wMKMol3N62t8rbX/J7PaWxR3O017kim1Xz0fSbYA+nHk6SvA2rXMdShACcBRz +t/DK4TzjwUL3a7P8Lvw8cfe0C6pBQD1sAcUxw4CQBcCs/PMCModJWoUmCflZZTqe ++WdDA9kCgYEA8yvQyVhK4xMAWzCzaRjBNpFpFJAX6XAHjMmhnOCLNe2m7SQdi5p4 +/j65P9pjRv+nD07cv/7mrYAWXFXkLgz3WWObR4A5eWjA0gnyIHJGNa9NQ7vCWu6g +aQpI+hnnwShakxuQ7w9w1WKAXh0rvnWO4hOxHlr5ve7UpEN18s7uzQMCgYEAxdPu +b38Qb2tGUXWQOBYsJNvhdwevO8EPggP044ENJvQW0gmJuVsF/Yrua0TNrUv+ETYd +mgK6MhNlxR6v3STwDg/OpM+MvgBafKRX2PeBJTf6k3Yx7ykxhLNPmuL6RCVv3ou9 +F064UzzyM9ApyWna7b0+1R1XPS+VttWZliLefPUCgYAb0iV/A7T9qczeogHEwmpI +nfZRvfKeaIzUlLUCx8Xlk50HgJxIvpGdNPvozEmTc+hfHfyvkrA9pWvpgIIsqpsa +BQVc9tSciVmWLkEfaTOTLM1ANJkV4jtECUM0KgaT2NQUBJFeaHvWTgC1w8yfa7+/ +KdWXzXzJOCvn5zf1Yat8lQKBgGgsfP+rqqzxkZrtzJ8sVdynCSiUHFvcA12U1c1D +tPhRSv8Z1LON0i68jWZhWemq/cR0ecwTKZebDVlrGnLas6rD+i5huRyItR2zsSro +0tIVk1c5w3vMdm4Jup62bdGa4TkQ3uc6Jeh3TJeqQ4bzvjy5DjBNfhYTS8R24KTm +AcFNAoGAPF4fOuTeFwy+a+LZ5ZTSHTiQ5YZYmnu27mM4YS0KjWCs2UKYKr47tOhf +96kuaN6zcE7gqawMTDGW+77DxTwKpbIEvKRb03PfqGnD8SHQmAQCjLOlnhW816n/ ++AtLlzWB7dBtgO/cW9lFIzyPCVlXRcbsn3RKS5HnLgIkuXn/kZI= +-----END RSA PRIVATE KEY----- diff --git a/config.cfg_sample b/config.cfg_sample @@ -43,10 +43,16 @@ gap_limit = 25 [electrum-server] # 0.0.0.0 to accept connections from any IP #127.0.0.1 to accept from only localhost -# recommended you accept localhost only and for connecting remotely use a ssh tunnel +# recommend you accept localhost only, for connecting remotely use a ssh tunnel host = 127.0.0.1 port = 50002 +#uses the default one, which is fine because by default nobody should be +# allowed to connect to your server or scan your packets +#to generate another certificate see https://github.com/spesmilo/electrum-server/blob/ce1b11d7f5f7a70a3b6cc7ec1d3e552436e54ffe/HOWTO.md#step-8-create-a-self-signed-ssl-cert +certfile = cert.crt +keyfile = cert.key + [misc] # not implemented yet print_debug = false diff --git a/server.py b/server.py @@ -179,6 +179,9 @@ def handle_query(sock, line, rpc, address_history, deterministic_wallets): result = e.message debug("tx broadcast result = " + str(result)) send_response(sock, query, result) + elif method == "mempool.get_fee_histogram": + result = [] #not handling, sending empty + send_response(sock, query, result) elif method == "blockchain.estimatefee": estimate = rpc.call("estimatesmartfee", [query["params"][0]]) feerate = 0.0001 @@ -209,7 +212,7 @@ def handle_query(sock, line, rpc, address_history, deterministic_wallets): send_response(sock, query, []) #no peers to report else: log("*** BUG! Not handling method: " + method + " query=" + str(query)) - #TODO just send back the same query will result = [] + #TODO just send back the same query with result = [] def get_block_header(rpc, blockhash): rpc_head = rpc.call("getblockheader", [blockhash]) @@ -239,34 +242,34 @@ def create_server_socket(hostport): server_sock = socket.socket() server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_sock.bind(hostport) + server_sock.listen(1) log("Listening on " + str(hostport)) return server_sock def run_electrum_server(hostport, rpc, address_history, unconfirmed_txes, deterministic_wallets, poll_interval_listening, - poll_interval_connected): + poll_interval_connected, certfile, keyfile): log("Starting electrum server") + server_sock = create_server_socket(hostport) + server_sock.settimeout(poll_interval_listening) while True: try: - server_sock = create_server_socket(hostport) - server_sock.settimeout(poll_interval_listening) - while True: + sock = None + while sock == None: try: - server_sock.listen(1) sock, addr = server_sock.accept() - break + sock = ssl.wrap_socket(sock, server_side=True, + certfile=certfile, keyfile=keyfile, + ssl_version=ssl.PROTOCOL_SSLv23) except socket.timeout: on_heartbeat_listening(rpc, address_history, unconfirmed_txes, deterministic_wallets) - server_sock.close() - sock.settimeout(poll_interval_connected) - ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - #generate self signed cert with - #openssl req -new -x509 -days 365 -nodes -out server.pem -keyout server.pem - ctx.load_cert_chain(certfile="server.pem", - keyfile="server.pem") - sock = ctx.wrap_socket(sock, server_side=True) + except ssl.SSLError: + sock.close() + sock = None + log('Electrum connected from ' + str(addr)) + sock.settimeout(poll_interval_connected) recv_buffer = bytearray() while True: try: @@ -291,14 +294,13 @@ def run_electrum_server(hostport, rpc, address_history, unconfirmed_txes, log("Electrum wallet disconnected") else: log("IOError: " + repr(e)) - import traceback - traceback.print_exc() - on_disconnect(address_history) - time.sleep(0.2) try: - server_sock.close() + sock.close() except IOError: pass + sock = None + on_disconnect(address_history) + time.sleep(0.2) def get_input_and_output_scriptpubkeys(rpc, txid): gettx = rpc.call("gettransaction", [txid]) @@ -696,8 +698,10 @@ def main(): "poll_interval_listening")) poll_interval_connected = int(config.get("bitcoin-rpc", "poll_interval_connected")) + certfile = config.get("electrum-server", "certfile") + keyfile = config.get("electrum-server", "keyfile") run_electrum_server(hostport, rpc, address_history, unconfirmed_txes, deterministic_wallets, poll_interval_listening, - poll_interval_connected) + poll_interval_connected, certfile, keyfile) main()