예제 #1
0
    def __init__(self):
        file_name = 'bitcoin.conf'
        bitcoin_data_path = BITCOIN_DATA_PATH[OPERATING_SYSTEM]
        self.bitcoin_configuration_file_path = os.path.join(
            bitcoin_data_path, file_name)
        log.info('bitcoin_configuration_file_path',
                 bitcoin_configuration_file_path=self.
                 bitcoin_configuration_file_path)
        self.bitcoin = Bitcoin(
            configuration_file_path=self.bitcoin_configuration_file_path)

        file_name = 'lnd.conf'
        lnd_dir_path = LND_DIR_PATH[OPERATING_SYSTEM]
        self.lnd_configuration_file_path = os.path.join(
            lnd_dir_path, file_name)
        log.info('lnd_configuration_file_path',
                 lnd_configuration_file_path=self.lnd_configuration_file_path)
        self.lnd = Lnd(
            configuration_file_path=self.lnd_configuration_file_path,
            bitcoin=self.bitcoin)
        self.lnd_client = LndClient(self.lnd)

        file_name = 'torrc'
        tor_dir_path = TOR_DIR_PATH[OPERATING_SYSTEM]
        self.tor_configuration_file_path = os.path.join(
            tor_dir_path, file_name)
        log.info('tor_configuration_file_path',
                 tor_configuration_file_path=self.tor_configuration_file_path)
        self.tor = Tor(
            configuration_file_path=self.tor_configuration_file_path,
            lnd=self.lnd)
예제 #2
0
 def lnd_poll(lnd: Lnd, progress_callback, password: str):
     client = LndClient(lnd)
     try:
         response = client.unlock(password)
     except _Rendezvous as e:
         details = e.details()
         return details
예제 #3
0
    def __init__(self):
        file_name = 'litecoin.conf'
        litecoin_data_path = LITECOIN_DATA_PATH[OPERATING_SYSTEM]
        self.litecoin_configuration_file_path = os.path.join(litecoin_data_path,
                                                            file_name)
        log.info(
            'litecoin_configuration_file_path',
            litecoin_configuration_file_path=self.litecoin_configuration_file_path
        )
        self.litecoin = Litecoin(
            configuration_file_path=self.litecoin_configuration_file_path
        )

        file_name = 'lnd-ltc.conf'
        lnd_dir_path = LND_DIR_PATH[OPERATING_SYSTEM]
        self.lnd_configuration_file_path = os.path.join(lnd_dir_path, file_name)
        log.info(
            'lnd_configuration_file_path',
            lnd_configuration_file_path=self.lnd_configuration_file_path
        )
        self.lnd = Lnd(
            configuration_file_path=self.lnd_configuration_file_path,
            litecoin=self.litecoin
        )
        self.lnd_client = LndClient(self.lnd)
예제 #4
0
 def lnd_poll(lnd: Lnd, progress_callback, password: str):
     client = LndClient(lnd)
     try:
         client.unlock(password)
     except _Rendezvous as e:
         details = e.details()
         log.warning('lnd_poll', details=details, exc_info=True)
         return details
예제 #5
0
 def unlock_wallet(lnd, progress_callback, password: str):
     if password is None:
         return 'wallet not found'
     client = LndClient(lnd)
     try:
         client.unlock(password)
         return None
     except _Rendezvous as e:
         details = e.details()
         return details
예제 #6
0
class NodeSet(object):
    lnd_client: LndClient
    bitcoin: Bitcoin
    lnd: Lnd
    tor: Tor

    def __init__(self):
        file_name = 'bitcoin.conf'
        bitcoin_data_path = BITCOIN_DATA_PATH[OPERATING_SYSTEM]
        self.bitcoin_configuration_file_path = os.path.join(
            bitcoin_data_path, file_name)
        log.info('bitcoin_configuration_file_path',
                 bitcoin_configuration_file_path=self.
                 bitcoin_configuration_file_path)
        self.bitcoin = Bitcoin(
            configuration_file_path=self.bitcoin_configuration_file_path)

        file_name = 'lnd.conf'
        lnd_dir_path = LND_DIR_PATH[OPERATING_SYSTEM]
        self.lnd_configuration_file_path = os.path.join(
            lnd_dir_path, file_name)
        log.info('lnd_configuration_file_path',
                 lnd_configuration_file_path=self.lnd_configuration_file_path)
        self.lnd = Lnd(
            configuration_file_path=self.lnd_configuration_file_path,
            bitcoin=self.bitcoin)
        self.lnd_client = LndClient(self.lnd)

        file_name = 'torrc'
        tor_dir_path = TOR_DIR_PATH[OPERATING_SYSTEM]
        self.tor_configuration_file_path = os.path.join(
            tor_dir_path, file_name)
        log.info('tor_configuration_file_path',
                 tor_configuration_file_path=self.tor_configuration_file_path)
        self.tor = Tor(
            configuration_file_path=self.tor_configuration_file_path,
            lnd=self.lnd)

    @property
    def is_testnet(self) -> bool:
        return self.bitcoin.file['testnet']

    @property
    def is_mainnet(self) -> bool:
        return not self.bitcoin.file['testnet']

    def reset_tls(self):
        was_running = self.lnd.running
        if was_running:
            self.lnd.stop()
        os.remove(self.lnd_client.tls_cert_path)
        os.remove(self.lnd_client.tls_key_path)
        if was_running:
            self.lnd.launch()
        self.lnd_client.reset()
예제 #7
0
    def __init__(self, network: Network):
        self.network = network

        self.bitcoin = Bitcoin(
            network=self.network,
            configuration_file_path=self.bitcoin_configuration_file_path)
        self.lnd = Lnd(
            network=self.network,
            configuration_file_path=self.lnd_configuration_file_path,
            bitcoin=self.bitcoin)
        self.lnd_client = LndClient(self.lnd)
예제 #8
0
class NodeSet(object):
    lnd_client: LndClient
    bitcoin: Bitcoin
    lnd: Lnd
    network: Network

    def __init__(self, network: Network):
        self.network = network

        self.bitcoin = Bitcoin(
            network=self.network,
            configuration_file_path=self.bitcoin_configuration_file_path)
        self.lnd = Lnd(
            network=self.network,
            configuration_file_path=self.lnd_configuration_file_path,
            bitcoin=self.bitcoin)
        self.lnd_client = LndClient(self.lnd)

    @property
    def is_testnet(self) -> bool:
        return self.network == TESTNET

    @property
    def is_mainnet(self) -> bool:
        return self.network == MAINNET

    @property
    def lnd_configuration_file_path(self) -> str:
        file_name = 'lnd.conf'
        if self.is_testnet:
            file_name = 'lnd-testnet.conf'
        lnd_dir_path = LND_DIR_PATH[OPERATING_SYSTEM]
        return os.path.join(lnd_dir_path, file_name)

    @property
    def bitcoin_configuration_file_path(self) -> str:
        file_name = 'bitcoin.conf'
        if self.is_testnet:
            file_name = 'bitcoin-testnet.conf'
        bitcoin_data_path = BITCOIN_DATA_PATH[OPERATING_SYSTEM]
        return os.path.join(bitcoin_data_path, file_name)

    def reset_tls(self):
        was_running = self.lnd.running
        if was_running:
            self.lnd.stop()
        os.remove(self.lnd_client.tls_cert_path)
        os.remove(self.lnd_client.tls_key_path)
        if was_running:
            self.lnd.launch()
        self.lnd_client.reset()
예제 #9
0
class NodeSet(object):
    lnd_client: LndClient
    litecoin: Litecoin
    lnd: Lnd

    def __init__(self):
        file_name = 'litecoin.conf'
        litecoin_data_path = LITECOIN_DATA_PATH[OPERATING_SYSTEM]
        self.litecoin_configuration_file_path = os.path.join(litecoin_data_path,
                                                            file_name)
        log.info(
            'litecoin_configuration_file_path',
            litecoin_configuration_file_path=self.litecoin_configuration_file_path
        )
        self.litecoin = Litecoin(
            configuration_file_path=self.litecoin_configuration_file_path
        )

        file_name = 'lnd-ltc.conf'
        lnd_dir_path = LND_DIR_PATH[OPERATING_SYSTEM]
        self.lnd_configuration_file_path = os.path.join(lnd_dir_path, file_name)
        log.info(
            'lnd_configuration_file_path',
            lnd_configuration_file_path=self.lnd_configuration_file_path
        )
        self.lnd = Lnd(
            configuration_file_path=self.lnd_configuration_file_path,
            litecoin=self.litecoin
        )
        self.lnd_client = LndClient(self.lnd)

    @property
    def is_testnet(self) -> bool:
        return self.litecoin.file['testnet']

    @property
    def is_mainnet(self) -> bool:
        return not self.litecoin.file['testnet']

    def reset_tls(self):
        was_running = self.lnd.running
        if was_running:
            self.lnd.stop()
        os.remove(self.lnd_client.tls_cert_path)
        os.remove(self.lnd_client.tls_key_path)
        if was_running:
            self.lnd.launch()
        self.lnd_client.reset()
예제 #10
0
    def __init__(self, network: str):
        self.network = network
        self.lnd_configuration_file_path = os.path.join(
            LND_DIR_PATH[OPERATING_SYSTEM], 'lnd.conf')

        self.bitcoin_configuration_file_path = os.path.join(
            BITCOIN_DATA_PATH[OPERATING_SYSTEM], 'bitcoin.conf')

        self.bitcoin = Bitcoin(
            network=self.network,
            configuration_file_path=self.bitcoin_configuration_file_path)
        self.lnd = Lnd(
            network=self.network,
            configuration_file_path=self.lnd_configuration_file_path,
            bitcoin=self.bitcoin)
        self.lnd_client = LndClient(self.lnd)
예제 #11
0
 def test_generate_seed(self, mocked_lnd_client: LndClient):
     mocked_lnd_client.generate_seed()
     assert mocked_lnd_client.wallet_unlocker.called_once()
예제 #12
0
import os

from node_launcher.node_set.lnd_client import LndClient

network = 'mainnet'
class_file_path = os.path.realpath(__file__)
tools_directory_path = os.path.abspath(
    os.path.join(class_file_path, os.path.pardir))
remote_host_path = os.path.join(tools_directory_path, 'remote')
if not os.path.exists(remote_host_path):
    os.mkdir(remote_host_path)
macaroons_path = os.path.join(remote_host_path, 'macaroons')
if not os.path.exists(macaroons_path):
    os.mkdir(macaroons_path)

lnd_client = LndClient(lnddir=remote_host_path,
                       grpc_host='localhost',
                       grpc_port=10009,
                       macaroon_path=macaroons_path)
예제 #13
0
class Lnd(object):
    bitcoin: Bitcoin
    client: LndClient
    file: ConfigurationFile
    software: LndSoftware
    process: QProcess

    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.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'] = f'127.0.0.1:{self.bitcoin.rpc_port}'
        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 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',
            'bitcoin',
            str(self.bitcoin.network)
        )
        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)
        self.bitcoin.file.file_watcher.fileChanged.connect(
            self.bitcoin_config_file_changed)

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

        self.client = LndClient(self)

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

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

    @property
    def node_port(self) -> str:
        if self.file['listen'] is None:
            if self.bitcoin.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.bitcoin.file['testnet']:
            args.append(f'--network={self.bitcoin.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)
        if self.file['restlisten']:
            self.rest_port = int(self.file['restlisten'].split(':')[-1])
        if self.file['rpclisten']:
            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 bitcoin_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['bitcoind.rpchost'] = f'127.0.0.1:{self.bitcoin.rpc_port}'
        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']

    @property
    def restart_required(self):
        if self.running:
            # Did bitcoin details change
            if self.bitcoin.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

    @staticmethod
    def base64URL_from_base64(s):
        return s.replace('+', '-').replace('/', '_').rstrip('=')

    @property
    def lndconnect_url(self):
        host = self.grpc_url.split(':')[0]
        port = self.grpc_url.split(':')[1]
        return f'lndconnect://{host}:{port}' \
            f'?cert={self.tls_cert_path}&macaroon={self.admin_macaroon_path}'

    @property
    def lndconnect_qrcode(self):
        img = qrcode.make(self.lndconnect_url)
        return img

    def reset_tls(self):
        os.remove(self.client.tls_cert_path)
        os.remove(self.client.tls_key_path)
        self.process.terminate()
        self.client.reset()
예제 #14
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.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'] = f'127.0.0.1:{self.bitcoin.rpc_port}'
        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 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',
            'bitcoin',
            str(self.bitcoin.network)
        )
        self.config_snapshot = self.file.snapshot.copy()
        self.file.file_watcher.fileChanged.connect(self.config_file_changed)
        self.bitcoin.file.file_watcher.fileChanged.connect(
            self.bitcoin_config_file_changed)

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

        self.client = LndClient(self)
예제 #15
0
def mocked_lnd_client(lnd_client: LndClient) -> LndClient:
    lnd_client._wallet_unlocker = MagicMock()
    lnd_client._lnd_client = MagicMock()
    return lnd_client
예제 #16
0
 def test_unlock(self, mocked_lnd_client: LndClient):
     mocked_lnd_client.unlock('test_password')
     assert mocked_lnd_client.wallet_unlocker.called_once()
예제 #17
0
 def test_initialize_wallet(self, mocked_lnd_client: LndClient):
     mocked_lnd_client.initialize_wallet(
         wallet_password='******',
         seed=['test', 'mnemonic']
     )
     assert mocked_lnd_client.wallet_unlocker.called_once()
예제 #18
0
def lnd_client(lnd: Lnd) -> LndClient:
    lnd_client = LndClient(lnd)
    return lnd_client