def test_set_rpcuser(litecoin: Litecoin):
     litecoin.file['rpcuser'] = '******'
     changed = ConfigurationFile(litecoin.file.path)
     assert changed['rpcuser'] == 'test_user'
     litecoin.file['rpcuser'] = '******'
     changed_again = ConfigurationFile(litecoin.file.path)
     assert changed_again['rpcuser'] == 'test_user_2'
Exemple #2
0
 def test_setattr_bool(self, configuration_file: ConfigurationFile):
     configuration_file.test_bool_false = False
     configuration_file.test_bool_true = True
     with open(configuration_file.path, 'r') as f:
         text = f.read()
         assert 'test_bool_false=0' in text
         assert 'test_bool_true=1' in text
Exemple #3
0
 def test_set_rpcuser(bitcoin: Bitcoin):
     bitcoin.file.rpcuser = '******'
     changed = ConfigurationFile(bitcoin.file.path)
     assert changed.rpcuser == 'test_user'
     bitcoin.file.rpcuser = '******'
     changed_again = ConfigurationFile(bitcoin.file.path)
     assert changed_again.rpcuser == 'test_user_2'
Exemple #4
0
 def test_set_prune(bitcoin: Bitcoin):
     bitcoin.set_prune(True)
     pruned = ConfigurationFile(bitcoin.file.path)
     assert pruned.prune
     assert not pruned.txindex
     bitcoin.set_prune(False)
     unpruned = ConfigurationFile(bitcoin.file.path)
     assert not unpruned.prune
     assert unpruned.txindex
 def test_set_prune(litecoin: Litecoin):
     litecoin.set_prune(True)
     pruned = ConfigurationFile(litecoin.file.path)
     assert pruned['prune']
     assert not pruned['txindex']
     litecoin.set_prune(False)
     unpruned = ConfigurationFile(litecoin.file.path)
     assert not unpruned['prune']
     assert unpruned['txindex']
Exemple #6
0
    def __init__(self, network: str, configuration_file_path: str):
        self.network = network
        self.hard_drives = HardDrives()
        self.software = BitcoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.process = self.find_running_node()

        if self.file.rpcuser is None:
            self.file.rpcuser = '******'

        if self.file.rpcpassword is None:
            self.file.rpcpassword = get_random_password()

        if self.file.datadir is None:
            self.autoconfigure_datadir()

        if self.file.prune is None:
            should_prune = self.hard_drives.should_prune(self.file.datadir,
                                                         has_bitcoin=True)
            self.set_prune(should_prune)

        if not self.detect_zmq_ports():
            self.zmq_block_port = get_zmq_port()
            self.zmq_tx_port = get_zmq_port()

        if self.file.dbcache is None:
            # noinspection PyBroadException
            try:
                memory = psutil.virtual_memory()
                free_mb = round(memory.available / 1000000)
                self.file.dbcache = free_mb
            except:
                self.file.dbcache = 1000
Exemple #7
0
    def __init__(self, configuration_file_path: str, lnd: Lnd):
        self.lnd = lnd
        self.bitcoin = lnd.bitcoin
        self.file = ConfigurationFile(configuration_file_path, ' ')
        #self.software = TorSoftware()

        self.tordir = TOR_DIR_PATH[OPERATING_SYSTEM]

        # torrc edits
        self.file['ControlPort'] = '9051'
        self.file['CookieAuthentication'] = '1'
        self.file['HiddenServiceDir'] = os.path.join(self.tordir, 'bitcoin-service')
        self.file['HiddenServicePort'] = '8333 127.0.0.1:8333'
        self.file['HiddenServicePort'] = '18333 127.0.0.1:18333'

        # bitcoin.conf edits
        self.bitcoin.file['proxy'] = '127.0.0.1:9050'
        self.bitcoin.file['listen'] = '1'
        self.bitcoin.file['bind'] = '127.0.0.1'
        self.bitcoin.file['debug'] = 'tor'

        # lnd.conf edits
        self.lnd.file['listen'] = 'localhost'
        self.lnd.file['tor.active'] = '1'
        self.lnd.file['tor.v3'] = '1'
        self.lnd.file['tor.streamisolation'] = '1'
Exemple #8
0
    def __init__(self, network: Network, configuration_file_path: str,
                 bitcoin: Bitcoin):
        self.running = False
        self.is_unlocked = False
        self.network = network
        self.bitcoin = bitcoin
        self.file = ConfigurationFile(configuration_file_path)
        self.process = self.find_running_node()
        self.software = LndSoftware()

        self.file['lnddir'] = LND_DIR_PATH[OPERATING_SYSTEM]

        if self.file['debuglevel'] is None:
            self.file['debuglevel'] = 'info'

        self.file['bitcoin.active'] = True
        self.file['bitcoin.node'] = 'bitcoind'
        self.file['bitcoind.rpchost'] = '127.0.0.1'
        self.file['bitcoind.rpcuser'] = self.bitcoin.file['rpcuser']
        self.file['bitcoind.rpcpass'] = self.bitcoin.file['rpcpassword']
        self.file['bitcoind.zmqpubrawblock'] = self.bitcoin.file[
            'zmqpubrawblock']
        self.file['bitcoind.zmqpubrawtx'] = self.bitcoin.file['zmqpubrawtx']

        if self.file['restlisten'] is None:
            if self.network == TESTNET:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT + 1)
            else:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT)
            self.file['restlisten'] = f'127.0.0.1:{self.rest_port}'
        else:
            self.rest_port = self.file['restlisten'].split(':')[-1]

        if self.file['listen'] is None:
            if self.network == TESTNET:
                self.node_port = get_port(LND_DEFAULT_PEER_PORT + 1)
            else:
                self.node_port = get_port(LND_DEFAULT_PEER_PORT)
            self.file['listen'] = f'127.0.0.1:{self.node_port}'
        else:
            self.node_port = self.file['listen'].split(':')[-1]

        if self.file['rpclisten'] is None:
            if self.network == TESTNET:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT + 1)
            else:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT)
            self.file['rpclisten'] = f'0.0.0.0:{self.grpc_port}'
        else:
            self.grpc_port = self.file['rpclisten'].split(':')[-1]

        if self.file['tlsextraip'] is None:
            self.tlsextraip = socket.gethostbyname(socket.gethostname())
            self.file['tlsextraip'] = f'{self.tlsextraip}'
        else:
            self.tlsextraip = self.file['tlsextraip'].split('=')[-1]
Exemple #9
0
 def test_assign_op(self, configuration_file: ConfigurationFile):
     configuration_file['key'] = 'value'
     new_object = ConfigurationFile(configuration_file.path, ' ')
     with open(new_object.path, 'r') as f:
         text = f.read()
         assert 'key=value' in text
     new_object['key'] = 'value'
     with open(new_object.path, 'r') as f:
         text = f.read()
         assert 'key=value' not in text
         assert 'key value' in text
Exemple #10
0
    def __init__(self, network: str, configuration_file_path: str,
                 bitcoin: Bitcoin):
        self.network = network
        self.bitcoin = bitcoin
        self.file = ConfigurationFile(configuration_file_path)
        self.software = LndSoftware()

        self.lnddir = LND_DIR_PATH[OPERATING_SYSTEM]
        if not os.path.exists(self.lnddir):
            os.mkdir(self.lnddir)

        self.rest_port = get_port(8080)
        self.node_port = get_port(9735)
        self.grpc_port = get_port(10009)
Exemple #11
0
    def __init__(self, configuration_file_path: str, bitcoin: Bitcoin):
        self.running = False
        self.is_unlocked = False
        self.bitcoin = bitcoin
        self.file = ConfigurationFile(configuration_file_path)
        self.process = self.find_running_node()
        self.software = LndSoftware()

        self.lnddir = LND_DIR_PATH[OPERATING_SYSTEM]

        # Previous versions of the launcher set lnddir in the config file,
        # but it is not a valid key so this helps old users upgrading
        if self.file['lnddir'] is not None:
            self.file['lnddir'] = None

        if self.file['debuglevel'] is None:
            self.file['debuglevel'] = 'info'

        self.file['bitcoin.active'] = True
        self.file['bitcoin.node'] = 'bitcoind'
        self.file['bitcoind.rpchost'] = '127.0.0.1'
        self.file['bitcoind.rpcuser'] = self.bitcoin.file['rpcuser']
        self.file['bitcoind.rpcpass'] = self.bitcoin.file['rpcpassword']
        self.file['bitcoind.zmqpubrawblock'] = self.bitcoin.file[
            'zmqpubrawblock']
        self.file['bitcoind.zmqpubrawtx'] = self.bitcoin.file['zmqpubrawtx']

        if self.file['restlisten'] is None:
            if self.bitcoin.file['testnet']:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT + 1)
            else:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT)
            self.file['restlisten'] = f'127.0.0.1:{self.rest_port}'
        else:
            self.rest_port = self.file['restlisten'].split(':')[-1]

        if not self.file['rpclisten']:
            if self.bitcoin.file['testnet']:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT + 1)
            else:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT)
            self.file['rpclisten'] = f'127.0.0.1:{self.grpc_port}'
        else:
            self.grpc_port = int(self.file['rpclisten'].split(':')[-1])

        if self.file['color'] is None:
            self.file['color'] = '#000000'

        self.macaroon_path = os.path.join(self.lnddir, 'data', 'chain',
                                          'bitcoin', str(self.bitcoin.network))
Exemple #12
0
    def __init__(self, network: Network, configuration_file_path: str):
        self.network = network
        self.hard_drives = HardDrives()
        self.software = BitcoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.running = False
        self.process = None

        if self.file['server'] is None:
            self.file['server'] = True

        if self.file['disablewallet'] is None:
            self.file['disablewallet'] = True

        if self.file['timeout'] is None:
            self.file['timeout'] = 6000

        if self.file['rpcuser'] is None:
            self.file['rpcuser'] = '******'

        if self.file['rpcpassword'] is None:
            self.file['rpcpassword'] = get_random_password()

        if self.file['datadir'] is None:
            self.autoconfigure_datadir()

        if self.file['prune'] is None:
            should_prune = self.hard_drives.should_prune(self.file['datadir'],
                                                         has_bitcoin=True)
            self.set_prune(should_prune)

        if not self.detect_zmq_ports():
            self.zmq_block_port = get_zmq_port()
            self.zmq_tx_port = get_zmq_port()

        self.file['zmqpubrawblock'] = f'tcp://127.0.0.1:{self.zmq_block_port}'
        self.file['zmqpubrawtx'] = f'tcp://127.0.0.1:{self.zmq_tx_port}'

        # noinspection PyBroadException
        try:
            memory = psutil.virtual_memory()
            free_mb = round(memory.available / 1000000)
            free_mb -= int(free_mb * .3)
            self.file['dbcache'] = free_mb
        except:
            self.file['dbcache'] = 1000

        self.check_process()
Exemple #13
0
    def __init__(self, network: str, configuration_file_path: str):
        self.network = network
        self.hard_drives = HardDrives()
        self.software = BitcoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.process = self.find_running_node()

        if self.file.rpcuser is None:
            self.file.rpcuser = '******'

        if self.file.rpcpassword is None:
            self.file.rpcpassword = get_random_password()

        if self.file.datadir is None:
            self.autoconfigure_datadir()

        if self.file.prune is None:
            self.set_prune(self.hard_drives.should_prune(self.file.datadir, True))

        if not self.detect_zmq_ports():
            self.zmq_block_port = get_zmq_port()
            self.zmq_tx_port = get_zmq_port()
Exemple #14
0
 def test_getattr(self, configuration_file: ConfigurationFile):
     configuration_file['test_attribute'] = test_value
     new_object = ConfigurationFile(configuration_file.path)
     assert new_object['test_attribute'] == test_value
    def __init__(self, configuration_file_path: str):
        self.hard_drives = HardDrives()
        self.software = LitecoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.running = False
        self.process = None

        if self.file['datadir'] is None:
            self.autoconfigure_datadir()

        if 'litecoin.conf' in os.listdir(self.file['datadir']):
            actual_conf_file = os.path.join(self.file['datadir'], 'litecoin.conf')
            log.info(
                'datadir_redirect',
                configuration_file_path=configuration_file_path,
                actual_conf_file=actual_conf_file
            )
            self.file = ConfigurationFile(actual_conf_file)
            if self.file['datadir'] is None:
                self.autoconfigure_datadir()

        if os.path.exists(os.path.join(self.file['datadir'], 'blocks')):
            if self.file['prune'] is None:
                self.set_prune(False)

        self.wallet_paths = self.get_wallet_paths()

        if self.file['server'] is None:
            self.file['server'] = True

        if self.file['disablewallet'] is None and not self.wallet_paths:
            self.file['disablewallet'] = True
        elif self.file['disablewallet'] is None and self.wallet_paths:
            self.file['disablewallet'] = False

        if self.file['timeout'] is None:
            self.file['timeout'] = 6000

        if self.file['rpcuser'] is None:
            self.file['rpcuser'] = '******'

        if self.file['rpcpassword'] is None:
            self.file['rpcpassword'] = get_random_password()

        if self.file['prune'] is None:
            should_prune = self.hard_drives.should_prune(self.file['datadir'], has_litecoin=True)
            self.set_prune(should_prune)

        self.zmq_block_port = get_zmq_port()
        self.zmq_tx_port = get_zmq_port()

        self.file['zmqpubrawblock'] = f'tcp://127.0.0.1:{self.zmq_block_port}'
        self.file['zmqpubrawtx'] = f'tcp://127.0.0.1:{self.zmq_tx_port}'

        # noinspection PyBroadException
        try:
            memory = psutil.virtual_memory()
            free_mb = round(memory.available / 1000000)
            free_mb -= int(free_mb * .3)
            self.file['dbcache'] = free_mb
        except:
            log.warning(
                'dbcache psutil.virtual_memory',
                exc_info=True
            )
            self.file['dbcache'] = 1000

        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)

        self.process = QProcess()
        self.process.setProgram(self.software.litecoind)
        self.process.setCurrentReadChannel(0)
        self.process.setArguments(self.args)
        self.process.start()
class Litecoin(object):
    file: ConfigurationFile
    hard_drives: HardDrives
    process: QProcess
    software: LitecoinSoftware
    zmq_block_port: int
    zmq_tx_port: int

    def __init__(self, configuration_file_path: str):
        self.hard_drives = HardDrives()
        self.software = LitecoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.running = False
        self.process = None

        if self.file['datadir'] is None:
            self.autoconfigure_datadir()

        if 'litecoin.conf' in os.listdir(self.file['datadir']):
            actual_conf_file = os.path.join(self.file['datadir'], 'litecoin.conf')
            log.info(
                'datadir_redirect',
                configuration_file_path=configuration_file_path,
                actual_conf_file=actual_conf_file
            )
            self.file = ConfigurationFile(actual_conf_file)
            if self.file['datadir'] is None:
                self.autoconfigure_datadir()

        if os.path.exists(os.path.join(self.file['datadir'], 'blocks')):
            if self.file['prune'] is None:
                self.set_prune(False)

        self.wallet_paths = self.get_wallet_paths()

        if self.file['server'] is None:
            self.file['server'] = True

        if self.file['disablewallet'] is None and not self.wallet_paths:
            self.file['disablewallet'] = True
        elif self.file['disablewallet'] is None and self.wallet_paths:
            self.file['disablewallet'] = False

        if self.file['timeout'] is None:
            self.file['timeout'] = 6000

        if self.file['rpcuser'] is None:
            self.file['rpcuser'] = '******'

        if self.file['rpcpassword'] is None:
            self.file['rpcpassword'] = get_random_password()

        if self.file['prune'] is None:
            should_prune = self.hard_drives.should_prune(self.file['datadir'], has_litecoin=True)
            self.set_prune(should_prune)

        self.zmq_block_port = get_zmq_port()
        self.zmq_tx_port = get_zmq_port()

        self.file['zmqpubrawblock'] = f'tcp://127.0.0.1:{self.zmq_block_port}'
        self.file['zmqpubrawtx'] = f'tcp://127.0.0.1:{self.zmq_tx_port}'

        # noinspection PyBroadException
        try:
            memory = psutil.virtual_memory()
            free_mb = round(memory.available / 1000000)
            free_mb -= int(free_mb * .3)
            self.file['dbcache'] = free_mb
        except:
            log.warning(
                'dbcache psutil.virtual_memory',
                exc_info=True
            )
            self.file['dbcache'] = 1000

        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)

        self.process = QProcess()
        self.process.setProgram(self.software.litecoind)
        self.process.setCurrentReadChannel(0)
        self.process.setArguments(self.args)
        self.process.start()

    @property
    def network(self):
        if self.file['testnet']:
            return TESTNET
        return MAINNET

    def get_wallet_paths(self):
        exclude_files = {
            'addr.dat',
            'banlist.dat',
            'fee_estimates.dat',
            'mempool.dat',
            'peers.dat'
        }
        candidate_paths = []
        if self.file['testnet']:
            datadir = os.path.join(self.file['datadir'], 'testnet4')
            wallet_dir = self.file['test.walletdir']
            wallets = self.file['test.wallet']
        else:
            datadir = self.file['datadir']
            wallet_dir = self.file['main.walletdir']
            wallets = self.file['main.wallet']
        for file in os.listdir(datadir):
            if file not in exclude_files:
                path = os.path.join(datadir, file)
                candidate_paths.append(path)
        default_walletdir = os.path.join(datadir, 'wallets')
        if os.path.exists(default_walletdir):
            for file in os.listdir(default_walletdir):
                if file not in exclude_files:
                    candidate_paths.append(
                        os.path.join(default_walletdir, file))
        if wallet_dir is not None:
            for file in os.listdir(wallet_dir):
                if file not in exclude_files:
                    candidate_paths += os.path.join(
                        os.path.join(wallet_dir, file))
        dat_files = [f for f in candidate_paths if f.endswith('.dat')
                     and not f.startswith('blk')]
        dat_files = set(dat_files)
        wallet_paths = set(dat_files - exclude_files)
        if wallets is not None:
            if isinstance(wallets, list):
                for wallet in wallets:
                    wallet_paths.add(wallet)
            else:
                wallet_paths.add(wallets)
        return wallet_paths

    @property
    def node_port(self):
        if self.file['testnet']:
            custom_port = self.file['test.port']
        else:
            custom_port = self.file['main.port']
        if custom_port is not None:
            return custom_port
        if self.file['testnet']:
            return LITECOIN_TESTNET_PEER_PORT
        return LITECOIN_MAINNET_PEER_PORT

    @property
    def rpc_port(self):
        if self.file['testnet']:
            custom_port = self.file['test.rpcport']
        else:
            custom_port = self.file['main.rpcport']
        if custom_port is not None:
            return custom_port
        if self.file['testnet']:
            return LITECOIN_TESTNET_RPC_PORT
        return LITECOIN_MAINNET_RPC_PORT

    def set_prune(self, should_prune: bool = None):

        if should_prune is None:
            should_prune = self.hard_drives.should_prune(self.file['datadir'],
                                                         has_litecoin=True)
        if should_prune:
            if self.file['testnet']:
                prune = TESTNET_PRUNE
            else:
                prune = MAINNET_PRUNE
            self.file['prune'] = prune
        else:
            self.file['prune'] = 0
        self.file['txindex'] = not should_prune

    def autoconfigure_datadir(self):
        default_datadir = LITECOIN_DATA_PATH[OPERATING_SYSTEM]
        big_drive = self.hard_drives.get_big_drive()
        default_is_big_enough = not self.hard_drives.should_prune(
            input_directory=default_datadir,
            has_litecoin=True
        )
        default_is_biggest = self.hard_drives.is_default_partition(big_drive)
        log.info(
            'autoconfigure_datadir',
            default_is_big_enough=default_is_big_enough,
            default_is_biggest=default_is_biggest
        )
        if default_is_big_enough or default_is_biggest:
            self.file['datadir'] = default_datadir
            log.info(
                'autoconfigure_datadir',
                datadir=default_datadir
            )
            return

        if not self.hard_drives.should_prune(big_drive.mountpoint, False):
            datadir = os.path.join(big_drive.mountpoint, 'Litecoin')
            self.file['datadir'] = datadir
            log.info(
                'autoconfigure_datadir',
                datadir=datadir
            )
            if not os.path.exists(self.file['datadir']):
                os.mkdir(self.file['datadir'])
        else:
            self.file['datadir'] = default_datadir
            log.info(
                'autoconfigure_datadir',
                datadir=default_datadir
            )

    @property
    def args(self) -> List[str]:
        return [f'-conf={self.file.path}']

    @property
    def litecoin_cli(self) -> str:
        command = [
            f'"{self.software.litecoin_cli}"',
            f'-conf="{self.file.path}"',
        ]
        return ' '.join(command)

    def config_file_changed(self):
        # Refresh config file
        self.file.file_watcher.blockSignals(True)
        self.file.populate_cache()
        self.file.file_watcher.blockSignals(False)
        self.zmq_block_port = int(self.file['zmqpubrawblock'].split(':')[-1])
        self.zmq_tx_port = int(self.file['zmqpubrawtx'].split(':')[-1])
        # Some text editors do not modify the file, they delete and replace the file
        # Check if file is still in file_watcher list of files, if not add back
        files_watched = self.file.file_watcher.files()
        if len(files_watched) == 0:
            self.file.file_watcher.addPath(self.file.path)

    @property
    def restart_required(self):
        old_config = self.config_snapshot.copy()
        new_config = self.file.snapshot

        # First check that both config files are still on the same network
        old_config_network = 'testnet' in old_config.keys()
        new_config_network = 'testnet' in new_config.keys()

        if (old_config_network == new_config_network) and self.running:
            common_fields = [
                'rpcuser', 'rpcpassword', 'disablewallet', 'datadir', 'disablewallet',
                'zmqpubrawblock', 'zmqpubrawtx', 'prune', 'txindex', 'timeout'
            ]

            for field in common_fields:

                # First check if field is found in both configs
                found_in_old_config = field in old_config.keys()
                found_in_new_config = field in new_config.keys()
                if found_in_old_config != found_in_new_config:
                    return True

                # Now check that values are the same
                if found_in_old_config:
                    if old_config[field] != new_config[field]:
                        return True

            if self.file['testnet']:
                # Only check testnet fields if currently running testnet
                testnet_fields = [
                    'test.rpcport', 'test.port', 'test.wallet', 'test.walletdir'
                ]
                for field in testnet_fields:
                    # First check if field is found in both configs
                    found_in_old_config = field in old_config.keys()
                    found_in_new_config = field in new_config.keys()

                    if found_in_old_config != found_in_new_config:
                        return True

                    # Now check that values are the same
                    if found_in_old_config:
                        if old_config[field] != new_config[field]:
                            return True

            else:
                # Only check mainnet fields if currently running mainnet
                mainnet_fields = [
                    'rpcport', 'port'
                ]

                for field in mainnet_fields:
                    # First check if field is found in both configs
                    found_in_old_config = field in old_config.keys()
                    found_in_new_config = field in new_config.keys()
                    if found_in_old_config != found_in_new_config:
                        return True

                    # Now check that values are the same
                    if found_in_old_config:
                        if old_config[field] != new_config[field]:
                            return True

            return False
        elif self.running:
            # Network has changed and the node is running - Restart is required
            return True

        return False
Exemple #17
0
    def __init__(self, configuration_file_path: str, litecoin: Litecoin):
        self.running = False
        self.is_unlocked = False
        self.litecoin = litecoin
        self.file = ConfigurationFile(configuration_file_path)
        self.software = LndSoftware()

        self.lnddir = LND_DIR_PATH[OPERATING_SYSTEM]

        # Previous versions of the launcher set lnddir in the config file,
        # but it is not a valid key so this helps old users upgrading
        if self.file['lnddir'] is not None:
            self.file['lnddir'] = None

        if self.file['debuglevel'] is None:
            self.file['debuglevel'] = 'info'

        self.file['litecoin.active'] = True
        self.file['litecoin.node'] = 'litecoind'
        self.file['litecoind.rpchost'] = f'127.0.0.1:{self.litecoin.rpc_port}'
        self.file['litecoind.rpcuser'] = self.litecoin.file['rpcuser']
        self.file['litecoind.rpcpass'] = self.litecoin.file['rpcpassword']
        self.file['litecoind.zmqpubrawblock'] = self.litecoin.file[
            'zmqpubrawblock']
        self.file['litecoind.zmqpubrawtx'] = self.litecoin.file['zmqpubrawtx']

        if self.file['restlisten'] is None:
            if self.litecoin.file['testnet']:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT + 1)
            else:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT)
            self.file['restlisten'] = f'127.0.0.1:{self.rest_port}'
        else:
            self.rest_port = self.file['restlisten'].split(':')[-1]

        if not self.file['rpclisten']:
            if self.litecoin.file['testnet']:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT + 1)
            else:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT)
            self.file['rpclisten'] = f'127.0.0.1:{self.grpc_port}'
        else:
            self.grpc_port = int(self.file['rpclisten'].split(':')[-1])

        if not self.file['tlsextraip']:
            self.file['tlsextraip'] = '127.0.0.1'

        if self.file['color'] is None:
            self.file['color'] = '#000000'

        self.macaroon_path = os.path.join(
            self.lnddir,
            'data',
            'chain',
            'litecoin',
            str(self.litecoin.network)
        )
        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)
        self.litecoin.file.file_watcher.fileChanged.connect(self.litecoin_config_file_changed)

        self.process = QProcess()
        self.process.setProgram(self.software.lnd)
        self.process.setCurrentReadChannel(0)
        self.process.setArguments(self.args)
        self.process.start()
Exemple #18
0
class Lnd(object):
    litecoin: Litecoin
    file: ConfigurationFile
    software: LndSoftware
    process: QProcess

    def __init__(self, configuration_file_path: str, litecoin: Litecoin):
        self.running = False
        self.is_unlocked = False
        self.litecoin = litecoin
        self.file = ConfigurationFile(configuration_file_path)
        self.software = LndSoftware()

        self.lnddir = LND_DIR_PATH[OPERATING_SYSTEM]

        # Previous versions of the launcher set lnddir in the config file,
        # but it is not a valid key so this helps old users upgrading
        if self.file['lnddir'] is not None:
            self.file['lnddir'] = None

        if self.file['debuglevel'] is None:
            self.file['debuglevel'] = 'info'

        self.file['litecoin.active'] = True
        self.file['litecoin.node'] = 'litecoind'
        self.file['litecoind.rpchost'] = f'127.0.0.1:{self.litecoin.rpc_port}'
        self.file['litecoind.rpcuser'] = self.litecoin.file['rpcuser']
        self.file['litecoind.rpcpass'] = self.litecoin.file['rpcpassword']
        self.file['litecoind.zmqpubrawblock'] = self.litecoin.file[
            'zmqpubrawblock']
        self.file['litecoind.zmqpubrawtx'] = self.litecoin.file['zmqpubrawtx']

        if self.file['restlisten'] is None:
            if self.litecoin.file['testnet']:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT + 1)
            else:
                self.rest_port = get_port(LND_DEFAULT_REST_PORT)
            self.file['restlisten'] = f'127.0.0.1:{self.rest_port}'
        else:
            self.rest_port = self.file['restlisten'].split(':')[-1]

        if not self.file['rpclisten']:
            if self.litecoin.file['testnet']:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT + 1)
            else:
                self.grpc_port = get_port(LND_DEFAULT_GRPC_PORT)
            self.file['rpclisten'] = f'127.0.0.1:{self.grpc_port}'
        else:
            self.grpc_port = int(self.file['rpclisten'].split(':')[-1])

        if not self.file['tlsextraip']:
            self.file['tlsextraip'] = '127.0.0.1'

        if self.file['color'] is None:
            self.file['color'] = '#000000'

        self.macaroon_path = os.path.join(
            self.lnddir,
            'data',
            'chain',
            'litecoin',
            str(self.litecoin.network)
        )
        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)
        self.litecoin.file.file_watcher.fileChanged.connect(self.litecoin_config_file_changed)

        self.process = QProcess()
        self.process.setProgram(self.software.lnd)
        self.process.setCurrentReadChannel(0)
        self.process.setArguments(self.args)
        self.process.start()

    @property
    def args(self):
        if IS_WINDOWS:
            arg_list = [
                f'--configfile={self.file.path}',
            ]
        else:
            arg_list = [
                f'--configfile="{self.file.path}"',
            ]

        if self.litecoin.file['testnet']:
            arg_list += [
                '--litecoin.testnet'
            ]
        else:
            arg_list += [
                '--litecoin.mainnet'
            ]
        return arg_list

    @property
    def node_port(self) -> str:
        if self.file['listen'] is None:
            if self.litecoin.file['testnet']:
                port = get_port(LND_DEFAULT_PEER_PORT + 1)
            else:
                port = get_port(LND_DEFAULT_PEER_PORT)
            self.file['listen'] = f'127.0.0.1:{port}'
        else:
            if not isinstance(self.file['listen'], list):
                port = self.file['listen'].split(':')[-1]
            else:
                port = self.file['listen'][0].split(':')[-1]
        return port

    def test_tls_cert(self):
        context = ssl.create_default_context()
        context.load_verify_locations(cafile=self.tls_cert_path)
        conn = context.wrap_socket(socket.socket(socket.AF_INET),
                                   server_hostname='127.0.0.1')
        conn.connect(('127.0.0.1', int(self.rest_port)))
        cert = conn.getpeercert()
        return cert

    @property
    def admin_macaroon_path(self) -> str:
        path = os.path.join(self.macaroon_path, 'admin.macaroon')
        return path

    @property
    def wallet_path(self) -> str:
        wallet_path = os.path.join(self.macaroon_path, 'wallet.db')
        return wallet_path

    @property
    def has_wallet(self) -> bool:
        return os.path.isfile(self.wallet_path)

    @property
    def tls_cert_path(self) -> str:
        tls_cert_path = os.path.join(self.lnddir, 'tls.cert')
        return tls_cert_path

    def lncli_arguments(self) -> List[str]:
        args = []
        if self.grpc_port != LND_DEFAULT_GRPC_PORT:
            args.append(f'--rpcserver=127.0.0.1:{self.grpc_port}')
        if self.litecoin.file['testnet']:
            args.append(f'--network={self.litecoin.network}')
        if self.lnddir != LND_DIR_PATH[OPERATING_SYSTEM]:
            args.append(f'''--lnddir="{self.lnddir}"''')
            args.append(f'--macaroonpath="{self.macaroon_path}"')
            args.append(f'--tlscertpath="{self.tls_cert_path}"')
        return args

    @property
    def lncli(self) -> str:
        base_command = [
            f'"{self.software.lncli}"',
        ]
        base_command += self.lncli_arguments()
        return ' '.join(base_command)

    @property
    def rest_url(self) -> str:
        return f'https://127.0.0.1:{self.rest_port}'

    @property
    def grpc_url(self) -> str:
        return f'127.0.0.1:{self.grpc_port}'

    def config_file_changed(self):
        # Refresh config file
        self.file.file_watcher.blockSignals(True)
        self.file.populate_cache()
        self.file.file_watcher.blockSignals(False)
        self.rest_port = int(self.file['restlisten'].split(':')[-1])
        self.grpc_port = int(self.file['rpclisten'].split(':')[-1])

        # Some text editors do not modify the file, they delete and replace the file
        # Check if file is still in file_watcher list of files, if not add back
        files_watched = self.file.file_watcher.files()
        if len(files_watched) == 0:
            self.file.file_watcher.addPath(self.file.path)

    def litecoin_config_file_changed(self):
        # Refresh config file
        self.file.file_watcher.blockSignals(True)
        self.file.populate_cache()
        self.file.file_watcher.blockSignals(False)
        self.file['litecoind.rpchost'] = f'127.0.0.1:{self.litecoin.rpc_port}'
        self.file['litecoind.rpcuser'] = self.litecoin.file['rpcuser']
        self.file['litecoind.rpcpass'] = self.litecoin.file['rpcpassword']
        self.file['litecoind.zmqpubrawblock'] = self.litecoin.file['zmqpubrawblock']
        self.file['litecoind.zmqpubrawtx'] = self.litecoin.file['zmqpubrawtx']

    @property
    def restart_required(self):
        if self.running:
            # Did litecoin details change
            if self.litecoin.restart_required:
                return True and self.running

            old_config = self.config_snapshot.copy()
            new_config = self.file.snapshot

            fields = [
                'restlisten', 'listen', 'rpclisten'
            ]

            for field in fields:
                # First check if field is found in both configs
                found_in_old_config = field in old_config.keys()
                found_in_new_config = field in new_config.keys()
                if found_in_old_config != found_in_new_config:
                    return True

                # Now check that values are the same
                if found_in_old_config:
                    if old_config[field] != new_config[field]:
                        return True

        return False
Exemple #19
0
    def __init__(self, configuration_file_path: str):
        self.hard_drives = HardDrives()
        self.software = BitcoinSoftware()
        self.file = ConfigurationFile(configuration_file_path)
        self.running = False
        self.process = None

        if self.file['datadir'] is None:
            self.autoconfigure_datadir()

        if 'bitcoin.conf' in os.listdir(self.file['datadir']):
            actual_conf_file = os.path.join(self.file['datadir'],
                                            'bitcoin.conf')
            log.info('datadir_redirect',
                     configuration_file_path=configuration_file_path,
                     actual_conf_file=actual_conf_file)
            self.file = ConfigurationFile(actual_conf_file)
            if self.file['datadir'] is None:
                self.autoconfigure_datadir()

        self.wallet_paths = self.get_wallet_paths()

        if self.file['server'] is None:
            self.file['server'] = True

        if self.file['disablewallet'] is None and not self.wallet_paths:
            self.file['disablewallet'] = True
        elif self.file['disablewallet'] is None and self.wallet_paths:
            self.file['disablewallet'] = False

        if self.file['timeout'] is None:
            self.file['timeout'] = 6000

        if self.file['rpcuser'] is None:
            self.file['rpcuser'] = '******'

        if self.file['rpcpassword'] is None:
            self.file['rpcpassword'] = get_random_password()

        if self.file['prune'] is None:
            should_prune = self.hard_drives.should_prune(self.file['datadir'],
                                                         has_bitcoin=True)
            self.set_prune(should_prune)

        if not self.detect_zmq_ports():
            self.zmq_block_port = get_zmq_port()
            self.zmq_tx_port = get_zmq_port()

        self.file['zmqpubrawblock'] = f'tcp://127.0.0.1:{self.zmq_block_port}'
        self.file['zmqpubrawtx'] = f'tcp://127.0.0.1:{self.zmq_tx_port}'

        # noinspection PyBroadException
        try:
            memory = psutil.virtual_memory()
            free_mb = round(memory.available / 1000000)
            free_mb -= int(free_mb * .3)
            self.file['dbcache'] = free_mb
        except:
            log.warning('dbcache psutil.virtual_memory', exc_info=True)
            self.file['dbcache'] = 1000

        self.check_process()
Exemple #20
0
def configuration_file():
    with NamedTemporaryFile(suffix='.conf', delete=True) as f:
        name = f.name
    configuration_file = ConfigurationFile(name)
    return configuration_file
Exemple #21
0
 def test_setattr(self, configuration_file: ConfigurationFile):
     configuration_file.test_attribute = test_value
     with open(configuration_file.path, 'r') as f:
         text = f.read()
         assert test_value in text
Exemple #22
0
 def test_getattr_bool(self, configuration_file: ConfigurationFile):
     configuration_file['test_bool_true'] = True
     configuration_file['test_bool_false'] = False
     new_object = ConfigurationFile(configuration_file.path)
     assert new_object['test_bool_true']
     assert not new_object['test_bool_false']