Пример #1
0
def init_daemon(config_options):
    config = SimpleConfig(config_options)
    wallet_path = config.get_wallet_path()
    if not WalletStorage.files_are_matched_by_path(wallet_path):
        print("Error: Wallet file not found.")
        print("Type 'electrum-sv create' to create a new wallet, "
              "or provide a path to a wallet with the -w option")
        sys.exit(0)
    storage = WalletStorage(wallet_path)
    if storage.is_encrypted():
        if 'wallet_password' in config_options:
            print(
                'Warning: unlocking wallet with commandline argument \"--walletpassword\"'
            )
            password = config_options['wallet_password']
        elif config.get('password'):
            password = config.get('password')
        else:
            password = prompt_password('Password:'******'password'] = password
Пример #2
0
 def test_simple_config_key_rename(self):
     """auto_cycle was renamed auto_connect"""
     fake_read_user = lambda _: {"auto_cycle": True}
     read_user_dir = lambda: self.user_dir
     config = SimpleConfig(options=self.options,
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     self.assertEqual(config.get("auto_connect"), True)
     self.assertEqual(config.get("auto_cycle"), None)
     fake_read_user = lambda _: {"auto_connect": False, "auto_cycle": True}
     config = SimpleConfig(options=self.options,
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     self.assertEqual(config.get("auto_connect"), False)
     self.assertEqual(config.get("auto_cycle"), None)
Пример #3
0
 def test_can_set_options_set_in_user_config(self):
     another_path = tempfile.mkdtemp()
     fake_read_user = lambda _: {"electrum_sv_path": self.electrum_dir}
     read_user_dir = lambda: self.user_dir
     config = SimpleConfig(options={},
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     config.set_key("electrum_sv_path", another_path)
     self.assertEqual(another_path, config.get("electrum_sv_path"))
Пример #4
0
 def test_cannot_set_options_passed_by_command_line(self):
     fake_read_user = lambda _: {"electrum_sv_path": "b"}
     read_user_dir = lambda: self.user_dir
     config = SimpleConfig(options=self.options,
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     config.set_key("electrum_sv_path", "c")
     self.assertEqual(self.options.get("electrum_sv_path"),
                      config.get("electrum_sv_path"))
Пример #5
0
 def test_simple_config_user_config_is_used_if_others_arent_specified(self):
     """If no system-wide configuration and no command-line options are
     specified, the user configuration is used instead."""
     fake_read_user = lambda _: {"electrum_sv_path": self.electrum_dir}
     read_user_dir = lambda: self.user_dir
     config = SimpleConfig(options={},
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     self.assertEqual(self.options.get("electrum_sv_path"),
                      config.get("electrum_sv_path"))
Пример #6
0
 def test_simple_config_command_line_overrides_everything(self):
     """Options passed by command line override all other configuration
     sources"""
     fake_read_user = lambda _: {"electrum_sv_path": "b"}
     read_user_dir = lambda: self.user_dir
     config = SimpleConfig(options=self.options,
                           read_user_config_function=fake_read_user,
                           read_user_dir_function=read_user_dir)
     self.assertEqual(self.options.get("electrum_sv_path"),
                      config.get("electrum_sv_path"))
Пример #7
0
def init_cmdline(config_options, server):
    config = SimpleConfig(config_options)
    cmdname = config.get('cmd')
    cmd = known_commands[cmdname]

    if cmdname == 'signtransaction' and config.get('privkey'):
        cmd.requires_wallet = False
        cmd.requires_password = False

    if cmdname in ['payto', 'paytomany'] and config.get('unsigned'):
        cmd.requires_password = False

    if cmdname in ['payto', 'paytomany'] and config.get('broadcast'):
        cmd.requires_network = True

    wallet_path = config.get_wallet_path()
    if cmd.requires_wallet and not WalletStorage.files_are_matched_by_path(
            wallet_path):
        print("Error: Wallet file not found.")
        print("Type 'electrum-sv create' to create a new wallet, "
              "or provide a path to a wallet with the -w option")
        sys.exit(0)

    # instantiate wallet for command-line
    storage = WalletStorage(wallet_path)

    # important warning
    if cmd.name in ['getprivatekeys']:
        print("WARNING: ALL your private keys are secret.", file=sys.stderr)
        print(
            "Exposing a single private key can compromise your entire wallet!",
            file=sys.stderr)
        print(
            "In particular, DO NOT use 'redeem private key' services "
            "proposed by third parties.",
            file=sys.stderr)

    # commands needing password
    if ((cmd.requires_wallet and storage.is_encrypted() and server is None)
            or (cmd.requires_password and
                (storage.get('use_encryption') or storage.is_encrypted()))):
        if config.get('password'):
            password = config.get('password')
        else:
            password = prompt_password('Password:'******'password'] = password

    if cmd.name == 'password':
        new_password = prompt_password('New password:'******'new_password'] = new_password

    return cmd, password
Пример #8
0
def get_peers():
    config = SimpleConfig()
    peers = {}
    # 1. get connected interfaces
    server = config.get('server')
    interfaces = get_interfaces([server])
    if not interfaces:
        print("No connection to", server)
        return []
    # 2. get list of peers
    interface = interfaces[server]
    interface.queue_request('server.peers.subscribe', [], 0)
    responses = wait_on_interfaces(interfaces).get(server)
    if responses:
        response = responses[0][1]  # One response, (req, response) tuple
        peers = parse_servers(response.get('result'))
    return peers
Пример #9
0
def main():
    # The hook will only be used in the Qt GUI right now
    setup_thread_excepthook()
    # on osx, delete Process Serial Number arg generated for apps launched in Finder
    sys.argv = [x for x in sys.argv if not x.startswith('-psn')]

    # old 'help' syntax
    if len(sys.argv) > 1 and sys.argv[1] == 'help':
        sys.argv.remove('help')
        sys.argv.append('-h')

    # read arguments from stdin pipe and prompt
    for i, arg in enumerate(sys.argv):
        if arg == '-':
            if not sys.stdin.isatty():
                sys.argv[i] = sys.stdin.read()
                break
            else:
                raise Exception('Cannot get argument from stdin')
        elif arg == '?':
            sys.argv[i] = input("Enter argument:")
        elif arg == ':':
            sys.argv[i] = prompt_password('Enter argument (will not echo):',
                                          False)

    # parse command line
    parser = get_parser()
    args = parser.parse_args()

    # config is an object passed to the various constructors (wallet, interface, gui)
    config_options = args.__dict__
    config_options = {
        key: value
        for key, value in config_options.items()
        if value is not None and key not in config_variables.get(args.cmd, {})
    }

    logs.set_level(config_options['verbose'])

    if config_options.get('server'):
        config_options['auto_connect'] = False
    config_options['cwd'] = os.getcwd()

    # fixme: this can probably be achieved with a runtime hook (pyinstaller)
    try:
        if is_bundle and os.path.exists(
                os.path.join(sys._MEIPASS, 'is_portable')):
            config_options['portable'] = True
    except AttributeError:
        config_options['portable'] = False

    if config_options.get('portable'):
        config_options['electrum_sv_path'] = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), 'electrum_sv_data')

    if config_options.get('file_logging'):
        log_path = os.path.join(platform.user_dir(prefer_local=True), "logs")
        os.makedirs(log_path, exist_ok=True)
        log_path = os.path.join(log_path,
                                time.strftime("%Y%m%d-%H%M%S") + ".log")
        logs.add_file_output(log_path)

    if config_options.get('testnet'):
        Net.set_to(SVTestnet)

    # check uri
    uri = config_options.get('url')
    if uri:
        if not web.is_URI(uri):
            print('unknown command:', uri, file=sys.stderr)
            sys.exit(1)
        config_options['url'] = uri

    # todo: defer this to gui
    config = SimpleConfig(config_options)
    cmdname = config.get('cmd')

    # Set the app state proxy
    if cmdname == 'gui':
        try:
            from electrumsv.gui.qt.app_state import QtAppStateProxy
        except ImportError as e:
            platform.missing_import(e)
        QtAppStateProxy(config, 'qt')
    else:
        AppStateProxy(config, 'cmdline')

    # run non-RPC commands separately
    if cmdname in ['create', 'restore']:
        run_non_RPC(config)
        sys.exit(0)

    if cmdname == 'gui':
        fd, server = daemon.get_fd_or_server(config)
        if fd is not None:
            d = daemon.Daemon(fd, True)
            d.start()
            app_state.app.run_gui()
            sys.exit(0)
        else:
            result = server.gui(config_options)

    elif cmdname == 'daemon':
        subcommand = config.get('subcommand')
        if subcommand in ['load_wallet']:
            init_daemon(config_options)

        if subcommand in [None, 'start']:
            fd, server = daemon.get_fd_or_server(config)
            if fd is not None:
                if subcommand == 'start':
                    pid = os.fork()
                    if pid:
                        print("starting daemon (PID %d)" % pid,
                              file=sys.stderr)
                        sys.exit(0)
                d = daemon.Daemon(fd, False)
                d.start()
                if config.get('websocket_server'):
                    try:
                        from electrumsv import websockets
                    except ImportError as e:
                        platform.missing_import(e)
                    websockets.WebSocketServer(config, d.network).start()
                if config.get('requests_dir'):
                    path = os.path.join(config.get('requests_dir'),
                                        'index.html')
                    if not os.path.exists(path):
                        print("Requests directory not configured.")
                        print("You can configure it using "
                              "https://github.com/spesmilo/electrum-merchant")
                        sys.exit(1)
                d.join()
                sys.exit(0)
            else:
                result = server.daemon(config_options)
        else:
            server = daemon.get_server(config)
            if server is not None:
                result = server.daemon(config_options)
            else:
                print("Daemon not running")
                sys.exit(1)
    else:
        # command line
        server = daemon.get_server(config)
        init_cmdline(config_options, server)
        if server is not None:
            result = server.run_cmdline(config_options)
        else:
            cmd = known_commands[cmdname]
            if cmd.requires_network:
                print("Daemon not running; try 'electrum-sv daemon start'")
                sys.exit(1)
            else:
                result = run_offline_command(config, config_options)
                # print result
    if isinstance(result, str):
        print(result)
    elif type(result) is dict and result.get('error'):
        print(result.get('error'), file=sys.stderr)
    elif result is not None:
        print(json_encode(result))
    sys.exit(0)
Пример #10
0
def main():
    enforce_requirements()
    setup_windows_console()

    # The hook will only be used in the Qt GUI right now
    setup_thread_excepthook()

    # on osx, delete Process Serial Number arg generated for apps launched in Finder
    sys.argv = [x for x in sys.argv if not x.startswith('-psn')]

    # old 'help' syntax
    if len(sys.argv) > 1 and sys.argv[1] == 'help':
        sys.argv.remove('help')
        sys.argv.append('-h')

    # read arguments from stdin pipe and prompt
    for i, arg in enumerate(sys.argv):
        if arg == '-':
            if not sys.stdin.isatty():
                sys.argv[i] = sys.stdin.read()
                break
            else:
                raise Exception('Cannot get argument from stdin')
        elif arg == '?':
            sys.argv[i] = input("Enter argument:")
        elif arg == ':':
            sys.argv[i] = prompt_password('Enter argument (will not echo):',
                                          False)

    # parse command line
    parser = get_parser()
    args = parser.parse_args()

    # config is an object passed to various constructors
    config_options = args.__dict__
    config_options = {
        key: value
        for key, value in config_options.items()
        if value is not None and key not in config_variables.get(args.cmd, {})
    }

    logs.set_level(config_options['verbose'])

    if config_options.get('server'):
        config_options['auto_connect'] = False
    config_options['cwd'] = os.getcwd()

    # fixme: this can probably be achieved with a runtime hook (pyinstaller)
    portable_base_path = None
    try:
        if startup.is_bundle and os.path.exists(
                os.path.join(sys._MEIPASS, 'is_portable')):
            config_options['portable'] = True
            # Ensure the wallet data is stored in the same directory as the executable.
            portable_base_path = os.path.dirname(sys.executable)
    except AttributeError:
        config_options['portable'] = False

    if config_options.get('portable'):
        if portable_base_path is None:
            # Default to the same directory the 'electrum-sv' script is in.
            portable_base_path = os.path.dirname(os.path.realpath(sys.argv[0]))
        config_options['electrum_sv_path'] = os.path.join(
            portable_base_path, 'electrum_sv_data')

    if config_options.get('file_logging'):
        if config_options.get('portable'):
            log_path = os.path.join(config_options['electrum_sv_path'], "logs")
        else:
            log_path = os.path.join(platform.user_dir(prefer_local=True),
                                    "logs")
        os.makedirs(log_path, exist_ok=True)
        log_path = os.path.join(log_path,
                                time.strftime("%Y%m%d-%H%M%S") + ".log")
        logs.add_file_output(log_path)

    if config_options.get('testnet'):
        Net.set_to(SVTestnet)
    elif config_options.get('scalingtestnet'):
        Net.set_to(SVScalingTestnet)

    # check uri
    uri = config_options.get('url')
    if uri:
        if not web.is_URI(uri):
            print('unknown command:', uri, file=sys.stderr)
            sys.exit(1)
        config_options['url'] = uri

    # todo: defer this to gui
    config = SimpleConfig(config_options)
    cmdname = config.get('cmd')

    # Set the app state proxy
    if cmdname == 'gui':
        try:
            from electrumsv.gui.qt.app_state import QtAppStateProxy
        except ImportError as e:
            platform.missing_import(e)
        QtAppStateProxy(config, 'qt')
    elif cmdname == 'daemon' and 'daemon_app_module' in config_options:
        load_app_module(config_options['daemon_app_module'], config)
    else:
        AppStateProxy(config, 'cmdline')
        app_state.set_app(DefaultApp())

    # run non-RPC commands separately
    if cmdname in ['create', 'restore']:
        run_non_RPC(config)
        sys.exit(0)

    if cmdname == 'gui':
        fd, server = daemon.get_fd_or_server(config)
        if fd is not None:
            run_app_with_daemon(fd, True, config_options)
        else:
            result = server.gui(config_options)

    elif cmdname == 'daemon':
        subcommand = config.get('subcommand')
        if subcommand in ['load_wallet']:
            init_daemon(config_options)

        if subcommand in [None, 'start']:
            fd, server = daemon.get_fd_or_server(config)
            if fd is not None:
                if not app_state.has_app():
                    print("No application present to run.")
                    sys.exit(0)

                if subcommand == 'start':
                    if not hasattr(os, "fork"):
                        print(
                            f"Starting the daemon is not supported on {sys.platform}."
                        )
                        sys.exit(0)
                    pid = os.fork()
                    if pid:
                        print("Starting daemon (PID %d)" % pid,
                              file=sys.stderr)
                        sys.exit(0)

                run_app_with_daemon(fd, False, config_options)
            else:
                result = server.daemon(config_options)
        else:
            server = daemon.get_server(config)
            if server is not None:
                result = server.daemon(config_options)
            else:
                print("Daemon not running")
                sys.exit(1)
    else:
        # command line
        server = daemon.get_server(config)
        init_cmdline(config_options, server)
        if server is not None:
            result = server.run_cmdline(config_options)
        else:
            cmd = known_commands[cmdname]
            if cmd.requires_network:
                print("Daemon not running; try 'electrum-sv daemon start'")
                sys.exit(1)
            else:
                result = run_offline_command(config, config_options)
                # print result
    if isinstance(result, str):
        print(result)
    elif type(result) is dict and result.get('error'):
        print(result.get('error'), file=sys.stderr)
    elif result is not None:
        print(json_encode(result))
    sys.exit(0)