From 5e60a0145eab119c1f4274a5860ad582a73d1a5c Mon Sep 17 00:00:00 2001 From: Yang Yang Date: Tue, 13 Oct 2020 17:39:38 +0800 Subject: [PATCH] feat: external mode of lnd --- images/utils/launcher/check_wallets.py | 28 ++--- images/utils/launcher/config/config.py | 124 ++++++++++++++++++++-- images/utils/launcher/config/mainnet.conf | 12 +++ images/utils/launcher/config/simnet.conf | 12 +++ images/utils/launcher/config/template.py | 24 +++++ images/utils/launcher/config/testnet.conf | 12 +++ images/utils/launcher/node/base.py | 5 +- images/utils/launcher/node/lnd.py | 7 ++ images/utils/launcher/node/xud.py | 33 +++++- images/xud/entrypoint.sh | 80 ++++++++++++-- setup.sh | 10 ++ 11 files changed, 313 insertions(+), 34 deletions(-) diff --git a/images/utils/launcher/check_wallets.py b/images/utils/launcher/check_wallets.py index 13826ce96..af6c53009 100644 --- a/images/utils/launcher/check_wallets.py +++ b/images/utils/launcher/check_wallets.py @@ -3,7 +3,7 @@ import os import docker import time -from concurrent.futures import ThreadPoolExecutor +from concurrent.futures import ThreadPoolExecutor, wait from docker.models.containers import Container from datetime import datetime import re @@ -276,7 +276,10 @@ def ensure_layer2_ready(self) -> None: nodes = self.config.nodes if self.node_manager.newly_installed: if self.network == "simnet": - self.lnd_cfheaders["bitcoin"] = CFHeaderState() + if self.config.nodes["lndbtc"]["mode"] == "native": + self.lnd_cfheaders["bitcoin"] = CFHeaderState() + if self.config.nodes["lndltc"]["mode"] == "native": + self.lnd_cfheaders["litecoin"] = CFHeaderState() self.lnd_cfheaders["litecoin"] = CFHeaderState() if "bitcoind" in nodes and nodes["bitcoind"]["mode"] in ["neutrino", "light"]: self.lnd_cfheaders["bitcoin"] = CFHeaderState() @@ -287,19 +290,18 @@ def ensure_layer2_ready(self) -> None: print("Syncing light clients:") self._print_lnd_cfheaders(erase_last_line=False) - with ThreadPoolExecutor(max_workers=2, thread_name_prefix="LndReady") as executor: - f1 = executor.submit(self.ensure_lnd_ready, "bitcoin") - f2 = executor.submit(self.ensure_lnd_ready, "litecoin") + with ThreadPoolExecutor(max_workers=len(self.lnd_cfheaders), thread_name_prefix="LndReady") as executor: + futs = {} + for chain in self.lnd_cfheaders: + futs[executor.submit(self.ensure_lnd_ready, chain)] = chain - try: - f1.result() - except Exception as e: - raise FatalError("Failed to wait for lndbtc to be ready") from e + done, not_done = wait(futs) - try: - f2.result() - except Exception as e: - raise FatalError("Failed to wait for lndltc to be ready") from e + if len(not_done) > 0: + for f in not_done: + f.cancel() + lnds = ", ".join([futs[f] for f in not_done]) + raise FatalError("Failed to wait for {} to be ready".format(lnds)) if self.node_manager.newly_installed: print() diff --git a/images/utils/launcher/config/config.py b/images/utils/launcher/config/config.py index 3d5afce81..64900b9b6 100644 --- a/images/utils/launcher/config/config.py +++ b/images/utils/launcher/config/config.py @@ -265,6 +265,33 @@ def parse_command_line_arguments(self): action="store_true", help="Preserve lndbtc lnd.conf file during updates" ) + group.add_argument( + "--lndbtc.mode", + metavar="", + choices=["native", "external"], + help="Lndbtc service mode" + ) + group.add_argument( + "--lndbtc.rpc-host", + metavar="", + help="External lndbtc RPC hostname" + ) + group.add_argument( + "--lndbtc.rpc-port", + type=int, + metavar="", + help="External lndbtc RPC port" + ) + group.add_argument( + "--lndbtc.certpath", + metavar="", + help="External lndbtc TLS certificate file" + ) + group.add_argument( + "--lndbtc.macaroonpath", + metavar="", + help="External lndbtc admin.macaroon path" + ) group = parser.add_argument_group("lndltc") group.add_argument( @@ -277,6 +304,33 @@ def parse_command_line_arguments(self): action="store_true", help="Preserve lndltc lnd.conf file during updates" ) + group.add_argument( + "--lndltc.mode", + metavar="", + choices=["native", "external"], + help="Lndltc service mode" + ) + group.add_argument( + "--lndltc.rpc-host", + metavar="", + help="External lndltc RPC hostname" + ) + group.add_argument( + "--lndltc.rpc-port", + type=int, + metavar="", + help="External lndltc RPC port" + ) + group.add_argument( + "--lndltc.certpath", + metavar="", + help="External lndltc TLS certificate file" + ) + group.add_argument( + "--lndltc.macaroonpath", + metavar="", + help="External lndltc admin.macaroon path" + ) group = parser.add_argument_group("connext") group.add_argument( @@ -665,6 +719,44 @@ def update_geth(self, parsed): value = getattr(self.args, opt) node["cache"] = value + def _get_value(self, key, node, parsed, validator=None, converter=None, default=None): + result = None + + node_name = node["name"] + + def process(value, hint): + if converter: + try: + value = converter(value) + except Exception as e: + raise ValueError("({}) Invalid value: {}".format(hint, value)) from e + + if validator and not validator(value): + raise ValueError(value) + + return value + + if key in parsed: + value = parsed[key] + value = process(value, "{}.conf > {} > {}".format(self.network, node_name, key)) + result = value + + opt = "{}.{}".format(node_name, key.replace("-", "_")) + + if hasattr(self.args, opt): + value = getattr(self.args, opt) + value = process(value, "--{}".format(opt.replace("_", "-"))) + result = value + + if not result: + if default: + return default + msg = "configuration \"{}.{}\" missing (please specify command-line option \"--{}\" or add \"{}\" in your {}.conf \"{}\" section)".format( + node_name, key, opt.replace("_", "-"), key, self.network, node_name) + raise ValueError(msg) + + return result + def update_lndbtc(self, parsed): """Update lndbtc related configurations from parsed TOML lndbtc section :param parsed: Parsed lndbtc TOML section @@ -672,6 +764,13 @@ def update_lndbtc(self, parsed): node = self.nodes["lndbtc"] self.update_ports(node, parsed) + node["mode"] = self._get_value("mode", node, parsed, validator=lambda v: v in ["native", "external"], default="native") + if node["mode"] == "external": + node["rpc_host"] = self._get_value("rpc_host", node, parsed) + node["rpc_port"] = self._get_value("rpc_port", node, parsed, converter=lambda v: int(v)) + node["certpath"] = self._get_value("certpath", node, parsed) + node["macaroonpath"] = self._get_value("macaroonpath", node, parsed) + def update_lndltc(self, parsed): """Update lndltc related configurations from parsed TOML lndltc section :param parsed: Parsed lndltc TOML section @@ -679,6 +778,13 @@ def update_lndltc(self, parsed): node = self.nodes["lndltc"] self.update_ports(node, parsed) + node["mode"] = self._get_value("mode", node, parsed, validator=lambda v: v in ["native", "external"], default="native") + if node["mode"] == "external": + node["rpc_host"] = self._get_value("rpc_host", node, parsed) + node["rpc_port"] = self._get_value("rpc_port", node, parsed, converter=lambda v: int(v)) + node["certpath"] = self._get_value("certpath", node, parsed) + node["macaroonpath"] = self._get_value("macaroonpath", node, parsed) + def update_connext(self, parsed): """Update Connext related configurations from parsed TOML connext section :param parsed: Parsed connext TOML section @@ -975,6 +1081,7 @@ def dump_attr(attr: str) -> None: if isinstance(value, bool): value = str(value).lower() print("{}=\"{}\"".format(key, value), file=f) + dump_attr("branch") dump_attr("disable_update") dump_attr("external_ip") @@ -1024,16 +1131,21 @@ def dump_node_attr(node: str, attr: str) -> None: if node in ["bitcoind", "litecoind"]: dump_node_attr(node, "external_rpc_host") dump_node_attr(node, "external_rpc_port") - #dump_node_attr(node, "external_rpc_user") - #dump_node_attr(node, "external_rpc_password") + # dump_node_attr(node, "external_rpc_user") + # dump_node_attr(node, "external_rpc_password") dump_node_attr(node, "external_zmqpubrawblock") dump_node_attr(node, "external_zmqpubrawtx") elif node == "geth": dump_node_attr(node, "external_rpc_host") dump_node_attr(node, "external_rpc_port") - #dump_node_attr(node, "infura_project_id") - #dump_node_attr(node, "infura_project_secret") + # dump_node_attr(node, "infura_project_id") + # dump_node_attr(node, "infura_project_secret") dump_node_attr(node, "cache") + elif node in ["lndbtc", "lndltc"]: + dump_node_attr(node, "rpc_host") + dump_node_attr(node, "rpc_port") + dump_node_attr(node, "certpath") + dump_node_attr(node, "macaroonpath") elif node == "arby": dump_node_attr(node, "test_centralized_baseasset_balance") dump_node_attr(node, "test_centralized_quoteasset_balance") @@ -1044,6 +1156,6 @@ def dump_node_attr(node: str, attr: str) -> None: dump_node_attr(node, "live_cex") dump_node_attr(node, "test_mode") dump_node_attr(node, "cex") - #dump_node_attr(node, "cex_api_key") - #dump_node_attr(node, "cex_api_secret") + # dump_node_attr(node, "cex_api_key") + # dump_node_attr(node, "cex_api_secret") dump_node_attr(node, "margin") diff --git a/images/utils/launcher/config/mainnet.conf b/images/utils/launcher/config/mainnet.conf index 75007a3d8..86adc0d7e 100644 --- a/images/utils/launcher/config/mainnet.conf +++ b/images/utils/launcher/config/mainnet.conf @@ -104,12 +104,24 @@ # 10010 - REST port #expose-ports = ["9735", "10009", "10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/bitcoin/mainnet/admin.macaroon" + [lndltc] # 10735 - P2P port # 11009 - gRPC port # 11010 - REST port #expose-ports = ["10735", "11009:10009", "11010:10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/litecoin/mainnet/admin.macaroon" + [connext] # 5040 - connext API port #expose-ports = ["5040"] diff --git a/images/utils/launcher/config/simnet.conf b/images/utils/launcher/config/simnet.conf index 5639ea2ec..a37427d52 100644 --- a/images/utils/launcher/config/simnet.conf +++ b/images/utils/launcher/config/simnet.conf @@ -17,12 +17,24 @@ # 30010 - REST port #expose-ports = ["29735", "30009:10009", "30010:10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/bitcoin/simnet/admin.macaroon" + [lndltc] # 30735 - P2P port # 31009 - gRPC port # 31010 - REST port #expose-ports = ["30735", "31009:10009", "31010:10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/litecoin/simnet/admin.macaroon" + [connext] # 25040 - connext API port #expose-ports = ["25040:5040"] diff --git a/images/utils/launcher/config/template.py b/images/utils/launcher/config/template.py index 117f140e5..5daae991e 100644 --- a/images/utils/launcher/config/template.py +++ b/images/utils/launcher/config/template.py @@ -87,6 +87,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "lndltc": { "name": "lndltc", @@ -101,6 +105,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "connext": { "name": "connext", @@ -282,6 +290,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "lndltc": { "name": "lndltc", @@ -296,6 +308,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "connext": { "name": "connext", @@ -500,6 +516,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "lndltc": { "name": "lndltc", @@ -514,6 +534,10 @@ def __str__(self): "mode": "native", "preserve_config": False, "use_local_image": False, + "rpc_host": None, + "rpc_port": None, + "certpath": None, + "macaroonpath": None, }, "connext": { "name": "connext", diff --git a/images/utils/launcher/config/testnet.conf b/images/utils/launcher/config/testnet.conf index 7c482bd20..abb3ec857 100644 --- a/images/utils/launcher/config/testnet.conf +++ b/images/utils/launcher/config/testnet.conf @@ -104,12 +104,24 @@ # 20010 - REST port #expose-ports = ["19735", "20009:10009", "20010:10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/bitcoin/testnet/admin.macaroon" + [lndltc] # 20735 - P2P port # 21009 - gRPC port # 21010 - REST port #expose-ports = ["20735", "21009:10009", "21010:10010"] +#mode = "external" +#rpc-host = "127.0.0.1" +#rpc-port = 10009 +#certpath = "$HOME/.lnd/tls.cert" +#macaroonpath = "$HOME/.lnd/data/chain/litecoin/testnet/admin.macaroon" + [connext] # 15040 - connext API port #expose-ports = ["15040:5040"] diff --git a/images/utils/launcher/node/base.py b/images/utils/launcher/node/base.py index 7c5e8d242..6d08b0b32 100644 --- a/images/utils/launcher/node/base.py +++ b/images/utils/launcher/node/base.py @@ -367,10 +367,7 @@ def ignored(item): if old_set != new_set: old.diff = old_set - new_set new.diff = new_set - old_set - if len(new.diff) == 0: - return CompareResult(True, "", old, new) - else: - return CompareResult(False, "Environments are different", old, new) + return CompareResult(False, "Environments are different", old, new) return CompareResult(True, "", old, new) diff --git a/images/utils/launcher/node/lnd.py b/images/utils/launcher/node/lnd.py index 0f81da586..f33cd252f 100644 --- a/images/utils/launcher/node/lnd.py +++ b/images/utils/launcher/node/lnd.py @@ -116,7 +116,14 @@ def get_current_height(self): except: return None + def get_external_status(self) -> str: + # TODO check external status + return "Ready (connected to external)" + def status(self): + if self.mode == "external": + return self.get_external_status() + status = super().status() if status == "exited": # TODO analyze exit reason diff --git a/images/utils/launcher/node/xud.py b/images/utils/launcher/node/xud.py index 7196853b5..e8ca4fe75 100644 --- a/images/utils/launcher/node/xud.py +++ b/images/utils/launcher/node/xud.py @@ -1,6 +1,8 @@ import json -from .base import Node, CliBackend, CliError import re +from typing import List + +from .base import Node, CliBackend, CliError class XudApiError(Exception): @@ -40,12 +42,39 @@ class Xud(Node): def __init__(self, name, ctx): super().__init__(name, ctx) - self.container_spec.environment.append("NODE_ENV=production") + self.container_spec.environment.extend(self._get_environment()) self._cli = "xucli" self.api = XudApi(CliBackend(self.client, self.container_name, self._logger, self._cli)) + def _get_environment(self) -> List[str]: + env = [ + "NODE_ENV=production" + ] + + lndbtc = self.config.nodes["lndbtc"] + env.append("LNDBTC_MODE={}".format(lndbtc["mode"])) + if lndbtc["mode"] == "external": + env.extend([ + "LNDBTC_RPC_HOST={}".format(lndbtc["rpc_host"]), + "LNDBTC_RPC_PORT={}".format(lndbtc["rpc_port"]), + "LNDBTC_CERTPATH={}".format(lndbtc["certpath"]), + "LNDBTC_MACAROONPATH={}".format(lndbtc["macaroonpath"]), + ]) + + lndltc = self.config.nodes["lndltc"] + env.append("LNDLTC_MODE={}".format(lndltc["mode"])) + if lndltc["mode"] == "external": + env.extend([ + "LNDLTC_RPC_HOST={}".format(lndbtc["rpc_host"]), + "LNDLTC_RPC_PORT={}".format(lndbtc["rpc_port"]), + "LNDLTC_CERTPATH={}".format(lndbtc["certpath"]), + "LNDLTC_MACAROONPATH={}".format(lndbtc["macaroonpath"]), + ]) + + return env + def status(self): status = super().status() if status == "exited": diff --git a/images/xud/entrypoint.sh b/images/xud/entrypoint.sh index fa4719ccb..99859f4c2 100755 --- a/images/xud/entrypoint.sh +++ b/images/xud/entrypoint.sh @@ -66,16 +66,41 @@ CONNEXT_IP=$(getent hosts connext || echo '' | awk '{ print $1 }') echo "$CONNEXT_IP connext" >> /etc/hosts -while [[ ! -e /root/.lndbtc/tls.cert ]]; do +while [[ $LNDBTC_MODE == "native" && ! -e /root/.lndbtc/tls.cert ]]; do echo "[entrypoint] Waiting for /root/.lndbtc/tls.cert to be created..." sleep 1 done -while [[ ! -e /root/.lndltc/tls.cert ]]; do +while [[ $LNDLTC_MODE == "native" && ! -e /root/.lndltc/tls.cert ]]; do echo "[entrypoint] Waiting for /root/.lndltc/tls.cert to be created..." sleep 1 done +if [[ -z ${LNDBTC_RPC_HOST:-} ]]; then + LNDBTC_RPC_HOST="lndbtc" +fi +if [[ -z ${LNDBTC_RPC_PORT:-} ]]; then + LNDBTC_RPC_PORT="10009" +fi +if [[ -z ${LNDBTC_CERTPATH:-} ]]; then + LNDBTC_CERTPATH="/root/.lndbtc/tls.cert" +fi +if [[ -z ${LNDBTC_MACAROONPATH:-} ]]; then + LNDBTC_MACAROONPATH="/root/.lndbtc/data/chain/bitcoin/$NETWORK/admin.macaroon" +fi + +if [[ -z ${LNDLTC_RPC_HOST:-} ]]; then + LNDLTC_RPC_HOST="lndltc" +fi +if [[ -z ${LNDLTC_RPC_PORT:-} ]]; then + LNDLTC_RPC_PORT="10009" +fi +if [[ -z ${LNDLTC_CERTPATH:-} ]]; then + LNDLTC_CERTPATH="/root/.lndltc/tls.cert" +fi +if [[ -z ${LNDLTC_MACAROONPATH:-} ]]; then + LNDLTC_MACAROONPATH="/root/.lndltc/data/chain/litecoin/$NETWORK/admin.macaroon" +fi [[ -e $XUD_CONF && $PRESERVE_CONFIG == "true" ]] || { cp /app/sample-xud.conf $XUD_CONF @@ -84,11 +109,15 @@ done sed -i 's/noencrypt.*/noencrypt = false/' $XUD_CONF sed -i '/\[http/,/^$/s/host.*/host = "0.0.0.0"/' $XUD_CONF sed -i "/\[http/,/^$/s/port.*/port = $HTTP_PORT/" $XUD_CONF - sed -i '/\[lnd\.BTC/,/^$/s/host.*/host = "lndbtc"/' $XUD_CONF - sed -i "/\[lnd\.BTC/,/^$/s|^$|certpath = \"/root/.lndbtc/tls.cert\"\nmacaroonpath = \"/root/.lndbtc/data/chain/bitcoin/$NETWORK/admin.macaroon\"\n|" $XUD_CONF - sed -i '/\[lnd\.LTC/,/^$/s/host.*/host = "lndltc"/' $XUD_CONF - sed -i '/\[lnd\.LTC/,/^$/s/port.*/port = 10009/' $XUD_CONF - sed -i "/\[lnd\.LTC/,/^$/s|^$|certpath = \"/root/.lndltc/tls.cert\"\nmacaroonpath = \"/root/.lndltc/data/chain/litecoin/$NETWORK/admin.macaroon\"\n|" $XUD_CONF + + sed -i "/\[lnd\.BTC/,/^$/s/host.*/host = \"$LNDBTC_RPC_HOST\"/" $XUD_CONF + sed -i "/\[lnd\.BTC/,/^$/s/port.*/port = $LNDBTC_RPC_PORT/" $XUD_CONF + sed -i "/\[lnd\.BTC/,/^$/s|^$|certpath = \"$LNDBTC_CERTPATH\"\nmacaroonpath = \"$LNDBTC_MACAROONPATH\"\n|" $XUD_CONF + + sed -i "/\[lnd\.LTC/,/^$/s/host.*/host = \"$LNDLTC_RPC_HOST\"/" $XUD_CONF + sed -i "/\[lnd\.LTC/,/^$/s/port.*/port = $LNDLTC_RPC_PORT/" $XUD_CONF + sed -i "/\[lnd\.LTC/,/^$/s|^$|certpath = \"$LNDLTC_CERTPATH\"\nmacaroonpath = \"$LNDLTC_MACAROONPATH\"\n|" $XUD_CONF + sed -i "/\[p2p/,/^$/s/addresses.*/addresses = \[\"$XUD_ADDRESS\"]/" $XUD_CONF sed -i "/\[p2p/,/^$/s/port.*/port = $P2P_PORT/" $XUD_CONF sed -i '/\[p2p/,/^$/s/tor = .*/tor = true/' $XUD_CONF @@ -103,8 +132,41 @@ done sed -i "/\[connext/,/^$/s/webhookport.*/webhookport = $HTTP_PORT/" $XUD_CONF } -echo "[entrypoint] Launch with xud.conf:" -cat $XUD_CONF +function get_value() { + sed -nE "/\[$1/,/^$/s/^.*$2 = (.+)$/\1/p" "$XUD_CONF" +} + +function set_value() { + sed -iE "/\[$1/,/^$/s|$2.*|$2 = $3|" "$XUD_CONF" +} + +ARR=( + "lnd\.BTC" "host" "\"$LNDBTC_RPC_HOST\"" + "lnd\.BTC" "port" "$LNDBTC_RPC_PORT" + "lnd\.BTC" "certpath" "\"$LNDBTC_CERTPATH\"" + "lnd\.BTC" "macaroonpath" "\"$LNDBTC_MACAROONPATH\"" + + "lnd\.LTC" "host" "\"$LNDLTC_RPC_HOST\"" + "lnd\.LTC" "port" "$LNDLTC_RPC_PORT" + "lnd\.LTC" "certpath" "\"$LNDLTC_CERTPATH\"" + "lnd\.LTC" "macaroonpath" "\"$LNDLTC_MACAROONPATH\"" +) + +function update_lnds() { + local SECTION KEY VALUE + while [[ $# -gt 0 ]]; do + SECTION=$1 + KEY=$2 + VALUE=$3 + shift 3 + if [[ $(get_value "$SECTION" "$KEY") != "$VALUE" ]]; then + set_value "$SECTION" "$KEY" "$VALUE" + echo "[entrypoint] Update $SECTION $KEY to $VALUE" + fi + done +} + +update_lnds "${ARR[@]}" /xud-backup.sh & diff --git a/setup.sh b/setup.sh index 94ecc0238..4abc0aedc 100644 --- a/setup.sh +++ b/setup.sh @@ -61,10 +61,20 @@ Geth options: Lndbtc options: --lndbtc.expose-ports [,] Expose lndbtc service ports to your host machine --lndbtc.preserve-config Preserve lndbtc lnd.conf file during updates + --lndbtc.mode [native|external] Lndbtc service mode (default: native) + --lndbtc.rpc-host External lndbtc RPC hostname + --lndbtc.rpc-port External lndbtc RPC port + --lndbtc.certpath External lndbtc TLS certificate file + --lndbtc.macaroonpath External lndbtc admin.macaroon path Lndbtc options: --lndltc.expose-ports [,] Expose lndltc service ports to your host machine --lndltc.preserve-config Preserve lndltc lnd.conf file during updates + --lndltc.mode [native|external] Lndltc service mode (default: native) + --lndltc.rpc-host External lndltc RPC hostname + --lndltc.rpc-port External lndltc RPC port + --lndltc.certpath External lndltc TLS certificate file + --lndltc.macaroonpath External lndltc admin.macaroon path Connext options: --connext.expose-ports [,] Expose connext service ports to your host machine