URI: 
       tAdd option for broadcasting txes via a system call - electrum-personal-server - Maximally lightweight electrum server for a single user
  HTML git clone https://git.parazyd.org/electrum-personal-server
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit 196e1452bb3f36469c7b55c4b68d1788027e0ca5
   DIR parent f506a9ebd4a0e9dbfafd72d81228ae149fb51be8
  HTML Author: chris-belcher <chris-belcher@users.noreply.github.com>
       Date:   Thu, 25 Apr 2019 19:21:21 +0100
       
       Add option for broadcasting txes via a system call
       
       By configuring in the config.ini file, unconfirmed transactions
       can now be broadcast by invoking an arbitrary system command.
       For example this could be used to broadcast transactions via
       SMS or radio.
       
       Diffstat:
         M config.ini_sample                   |      10 +++++++++-
         M electrumpersonalserver/server/comm… |      91 +++++++++++++++++++------------
       
       2 files changed, 65 insertions(+), 36 deletions(-)
       ---
   DIR diff --git a/config.ini_sample b/config.ini_sample
       t@@ -18,6 +18,7 @@
        # this example is a 2-of-3 multisig wallet
        #multisig_wallet = 2 xpub661MyMwAqRbcFseXCwRdRVkhVuzEiskg4QUp5XpUdNf2uGXvQmnD4zcofZ1MN6Fo8PjqQ5cemJQ39f7RTwDVVputHMFjPUn8VRp2pJQMgEF xpub661MyMwAqRbcFseXCwRdRVkhVuzEiskg4QUp5XpUdNf2uGXvQmnD4zcofZ1MN6Fo8PjqQ5cemJQ39f7RTwDVVputHMFjPUn8VRp2pJQMgEF xpub661MyMwAqRbcFseXCwRdRVkhVuzEiskg4QUp5XpUdNf2uGXvQmnD4zcofZ1MN6Fo8PjqQ5cemJQ39f7RTwDVVputHMFjPUn8VRp2pJQMgEF
        
       +
        [bitcoin-rpc]
        host = 127.0.0.1
        port = 8332
       t@@ -45,7 +46,6 @@ initial_import_count = 1000
        # number of unused addresses kept at the head of the wallet
        gap_limit = 25
        
       -
        [electrum-server]
        # 0.0.0.0 to accept connections from any IP
        #127.0.0.1 to accept from only localhost
       t@@ -69,6 +69,14 @@ keyfile = certs/cert.key
        # This is useful on low powered devices at times when the node mempool is large
        disable_mempool_fee_histogram = false
        
       +# Parameter for broadcasting unconfirmed transactions
       +# Options are:
       +# * own-node         (broadcast using the connected full node)
       +# * system <cmd> %s  (save transaction to file, and invoke system command
       +#                     with file path as parameter %s)
       +broadcast_method = own-node
       +
       +
        [watch-only-addresses]
        #Add individual addresses to this section, for example paper wallets
        #Dont use this section for adding entire wallets, instead use the
   DIR diff --git a/electrumpersonalserver/server/common.py b/electrumpersonalserver/server/common.py
       t@@ -4,7 +4,7 @@ from collections import defaultdict
        import traceback, sys, platform
        from ipaddress import ip_network, ip_address
        import logging
       -from tempfile import gettempdir
       +import tempfile
        
        from electrumpersonalserver.server.jsonrpc import JsonRpc, JsonRpcError
        import electrumpersonalserver.server.hashes as hashes
       t@@ -92,7 +92,8 @@ def on_disconnect(txmonitor):
            subscribed_to_headers[0] = False
            txmonitor.unsubscribe_all_addresses()
        
       -def handle_query(sock, line, rpc, txmonitor, disable_mempool_fee_histogram):
       +def handle_query(sock, line, rpc, txmonitor, disable_mempool_fee_histogram,
       +        broadcast_method):
            logger = logging.getLogger('ELECTRUMPERSONALSERVER')
            logger.debug("=> " + line)
            try:
       t@@ -226,14 +227,34 @@ def handle_query(sock, line, rpc, txmonitor, disable_mempool_fee_histogram):
                headers_hex, n = get_block_headers_hex(rpc, start_height, count)
                send_response(sock, query, headers_hex)
            elif method == "blockchain.transaction.broadcast":
       -        if not rpc.call("getnetworkinfo", [])["localrelay"]:
       -            result = "Broadcast disabled when using blocksonly"
       -            logger.info("Transaction broadcasting disabled when blocksonly")
       +        txhex = query["params"][0]
       +        result = None
       +        txreport = rpc.call("testmempoolaccept", [[txhex]])[0]
       +        if not txreport["allowed"]:
       +            result = txreport["reject-reason"]
                else:
       -            try:
       -                result = rpc.call("sendrawtransaction", [query["params"][0]])
       -            except JsonRpcError as e:
       -                result = str(e)
       +            result = txreport["txid"]
       +            if broadcast_method == "own-node":
       +                if not rpc.call("getnetworkinfo", [])["localrelay"]:
       +                    result = "Broadcast disabled when using blocksonly"
       +                    logger.warning("Transaction broadcasting disabled when " +
       +                        "blocksonly")
       +                else:
       +                    try:
       +                        rpc.call("sendrawtransaction", [txhex])
       +                    except JsonRpcError as e:
       +                        pass
       +            elif broadcast_method.startswith("system "):
       +                with tempfile.NamedTemporaryFile() as fd:
       +                    system_line = broadcast_method[7:].replace("%s", fd.name)
       +                    fd.write(txhex.encode())
       +                    fd.flush()
       +                    logger.debug("running command: " + system_line)
       +                    os.system(system_line)
       +            else:
       +                logger.error("Unrecognized broadcast method = "
       +                    + broadcast_method)
       +                result = "Unrecognized broadcast method"
                send_response(sock, query, result)
            elif method == "mempool.get_fee_histogram":
                if disable_mempool_fee_histogram:
       t@@ -407,11 +428,30 @@ def create_server_socket(hostport):
            logger.info("Listening for Electrum Wallet on " + str(hostport))
            return server_sock
        
       -def run_electrum_server(rpc, txmonitor, hostport, ip_whitelist,
       -        poll_interval_listening, poll_interval_connected, certfile, keyfile,
       -        disable_mempool_fee_histogram):
       +def run_electrum_server(rpc, txmonitor, config):
            logger = logging.getLogger('ELECTRUMPERSONALSERVER')
            logger.info("Starting electrum server")
       +
       +    hostport = (config.get("electrum-server", "host"),
       +            int(config.get("electrum-server", "port")))
       +    ip_whitelist = []
       +    for ip in config.get("electrum-server", "ip_whitelist").split(" "):
       +        if ip == "*":
       +            #matches everything
       +            ip_whitelist.append(ip_network("0.0.0.0/0"))
       +            ip_whitelist.append(ip_network("::0/0"))
       +        else:
       +            ip_whitelist.append(ip_network(ip, strict=False))
       +    poll_interval_listening = int(config.get("bitcoin-rpc",
       +        "poll_interval_listening"))
       +    poll_interval_connected = int(config.get("bitcoin-rpc",
       +        "poll_interval_connected"))
       +    certfile, keyfile = get_certs(config)
       +    disable_mempool_fee_histogram = config.getboolean("electrum-server",
       +        "disable_mempool_fee_histogram", fallback=False)
       +    broadcast_method = config.get("electrum-server", "broadcast_method",
       +        fallback="own-node")
       +
            server_sock = create_server_socket(hostport)
            server_sock.settimeout(poll_interval_listening)
            while True:
       t@@ -450,7 +490,8 @@ def run_electrum_server(rpc, txmonitor, hostport, ip_whitelist,
                                recv_buffer = recv_buffer[lb + 1:]
                                lb = recv_buffer.find(b'\n')
                                handle_query(sock, line.decode("utf-8"), rpc,
       -                            txmonitor, disable_mempool_fee_histogram)
       +                            txmonitor, disable_mempool_fee_histogram,
       +                            broadcast_method)
                        except socket.timeout:
                            on_heartbeat_connected(sock, rpc, txmonitor)
                except (IOError, EOFError) as e:
       t@@ -634,7 +675,7 @@ def logger_config(logger, config):
            logger.addHandler(logstream)
            filename = config.get("logging", "log_file_location", fallback="")
            if len(filename.strip()) == 0:
       -        filename= gettempdir() + "/electrumpersonalserver.log"
       +        filename= tempfile.gettempdir() + "/electrumpersonalserver.log"
            logfile = logging.FileHandler(filename, mode=('a' if
                config.get("logging", "append_log", fallback="false") else 'w'))
            logfile.setFormatter(formatter)
       t@@ -712,28 +753,8 @@ def main():
                    deterministic_wallets, logger)
                if not txmonitor.build_address_history(relevant_spks_addrs):
                    return
       -        hostport = (config.get("electrum-server", "host"),
       -                int(config.get("electrum-server", "port")))
       -        ip_whitelist = []
       -        for ip in config.get("electrum-server", "ip_whitelist").split(" "):
       -            if ip == "*":
       -                #matches everything
       -                ip_whitelist.append(ip_network("0.0.0.0/0"))
       -                ip_whitelist.append(ip_network("::0/0"))
       -            else:
       -                ip_whitelist.append(ip_network(ip, strict=False))
       -        poll_interval_listening = int(config.get("bitcoin-rpc",
       -            "poll_interval_listening"))
       -        poll_interval_connected = int(config.get("bitcoin-rpc",
       -            "poll_interval_connected"))
       -        certfile, keyfile = get_certs(config)
       -        disable_mempool_fee_histogram = config.getboolean("electrum-server",
       -            "disable_mempool_fee_histogram", fallback=False)
                try:
       -            run_electrum_server(rpc, txmonitor, hostport, ip_whitelist,
       -                                poll_interval_listening,
       -                                poll_interval_connected, certfile, keyfile,
       -                                disable_mempool_fee_histogram)
       +            run_electrum_server(rpc, txmonitor, config)
                except KeyboardInterrupt:
                    logger.info('Received KeyboardInterrupt, quitting')