mynode/rootfs/standard/var/www/mynode/lightning_info.py

324 lines
10 KiB
Python
Raw Normal View History

2019-06-15 23:02:44 +00:00
import copy
import requests
import subprocess
import os
import time
import re
2020-11-08 21:13:03 +00:00
from flask import current_app as app
2019-06-15 23:02:44 +00:00
from threading import Timer
from bitcoin_info import *
2020-10-08 02:59:44 +00:00
from systemctl_info import *
2019-06-15 23:02:44 +00:00
# Variables
lightning_info = None
lnd_ready = False
2019-08-01 04:27:16 +00:00
lnd_version = None
2020-08-21 00:56:31 +00:00
loopd_version = None
lightning_peers = None
lightning_channels = None
lightning_channel_balance = None
lightning_wallet_balance = None
lightning_desync_count = 0
2019-06-15 23:02:44 +00:00
LND_FOLDER = "/mnt/hdd/mynode/lnd/"
MACAROON_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/admin.macaroon"
WALLET_FILE = "/mnt/hdd/mynode/lnd/data/chain/bitcoin/mainnet/wallet.db"
TLS_CERT_FILE = "/mnt/hdd/mynode/lnd/tls.cert"
CHANNEL_BACKUP_FILE = "/home/bitcoin/lnd_backup/channel.backup"
LND_REST_PORT = "10080"
# Functions
def update_lightning_info():
global lightning_info
global lightning_peers
global lightning_channels
global lightning_channel_balance
global lightning_wallet_balance
global lightning_desync_count
2019-06-15 23:02:44 +00:00
global lnd_ready
# Get latest LN info
lightning_info = lnd_get("/getinfo")
# Set is LND ready
if lightning_info != None and "synced_to_chain" in lightning_info and lightning_info['synced_to_chain']:
lnd_ready = True
# Check for LND de-sync (this can happen unfortunately)
# See https://github.com/lightningnetwork/lnd/issues/1909
# See https://github.com/bitcoin/bitcoin/pull/14687
# Hopefully patch comes soon to enable TCP keepalive to prevent this from happening
if lnd_ready and lightning_info != None and "synced_to_chain" in lightning_info and not lightning_info['synced_to_chain']:
lightning_desync_count += 1
os.system("printf \"%s | LND De-sync!!! Count: {} \\n\" \"$(date)\" >> /tmp/lnd_failures".format(lightning_desync_count))
if lightning_desync_count >= 8:
os.system("printf \"%s | De-sync count too high! Retarting LND... \\n\" \"$(date)\" >> /tmp/lnd_failures")
restart_lnd()
lightning_desync_count = 0
return True
if lnd_ready:
if lightning_desync_count > 0:
os.system("printf \"%s | De-sync greater than 0 (was {}), but now synced! Setting to 0. \\n\" \"$(date)\" >> /tmp/lnd_failures".format(lightning_desync_count))
lightning_desync_count = 0
lightning_peers = lnd_get("/peers")
lightning_channels = lnd_get("/channels")
lightning_channel_balance = lnd_get("/balance/channels")
lightning_wallet_balance = lnd_get("/balance/blockchain")
2019-06-15 23:02:44 +00:00
return True
def get_new_deposit_address():
address = "NEW_ADDR"
try:
addressdata = lnd_get("/newaddress")
address = addressdata["address"]
except:
address = "ERROR"
return address
2019-06-15 23:02:44 +00:00
def get_lightning_info():
global lightning_info
return copy.deepcopy(lightning_info)
def get_lightning_peers():
global lightning_peers
return copy.deepcopy(lightning_peers)
2020-10-01 00:55:24 +00:00
def get_lightning_peer_count():
info = get_lightning_info()
num_peers = 0
2020-10-08 02:59:44 +00:00
if info != None and "num_peers" in info:
2020-10-01 00:55:24 +00:00
num_peers = info['num_peers']
return num_peers
def get_lightning_channels():
global lightning_channels
return copy.deepcopy(lightning_channels)
2020-10-01 00:55:24 +00:00
def get_lightning_channel_count():
channeldata = get_lightning_channels()
if channeldata != None and "channels" in channeldata:
return len(channeldata["channels"])
return 0
def get_lightning_channel_balance():
global lightning_channel_balance
return copy.deepcopy(lightning_channel_balance)
def get_lightning_wallet_balance():
global lightning_wallet_balance
return copy.deepcopy(lightning_wallet_balance)
2020-10-01 00:55:24 +00:00
def get_lightning_balance_info():
channel_balance_data = get_lightning_channel_balance()
wallet_balance_data = get_lightning_wallet_balance()
balance_data = {}
balance_data["channel_balance"] = "N/A"
balance_data["channel_pending"] = "N/A"
balance_data["wallet_balance"] = "N/A"
balance_data["wallet_pending"] = "N/A"
channel_balance_data = get_lightning_channel_balance()
if channel_balance_data != None and "balance" in channel_balance_data:
balance_data["channel_balance"] = channel_balance_data["balance"]
if channel_balance_data != None and "pending_open_balance" in channel_balance_data:
balance_data["channel_pending"] = channel_balance_data["pending_open_balance"]
wallet_balance_data = get_lightning_wallet_balance()
if wallet_balance_data != None and "confirmed_balance" in wallet_balance_data:
balance_data["wallet_balance"] = wallet_balance_data["confirmed_balance"]
if wallet_balance_data != None and "unconfirmed_balance" in wallet_balance_data:
balance_data["wallet_pending"] = wallet_balance_data["unconfirmed_balance"]
return balance_data
2019-06-15 23:02:44 +00:00
def is_lnd_ready():
global lnd_ready
return lnd_ready
def lnd_get(path):
try:
macaroon = get_macaroon()
headers = {"Grpc-Metadata-macaroon":macaroon}
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1"+path, verify=TLS_CERT_FILE,headers=headers)
except Exception as e:
2020-11-08 21:13:03 +00:00
app.logger.info("ERROR in lnd_get: "+str(e))
return {"error": str(e)}
2019-06-15 23:02:44 +00:00
return r.json()
def gen_new_wallet_seed():
seed = subprocess.check_output("python3 /usr/bin/gen_seed.py", shell=True)
return seed
def restart_lnd_actual():
2019-07-03 21:24:01 +00:00
global lnd_ready
lnd_ready = False
2019-06-15 23:02:44 +00:00
os.system("systemctl restart lnd")
os.system("systemctl restart lnd_unlock")
2019-11-04 04:50:47 +00:00
os.system("systemctl restart lnd_admin")
2019-06-15 23:02:44 +00:00
def restart_lnd():
t = Timer(1.0, restart_lnd_actual)
t.start()
def get_macaroon():
m = subprocess.check_output("xxd -ps -u -c 1000 "+MACAROON_FILE, shell=True)
return m.strip()
def lnd_wallet_exists():
return os.path.isfile(WALLET_FILE)
def create_wallet(seed):
try:
subprocess.check_call("create_lnd_wallet.tcl \""+seed+"\"", shell=True)
# Sync FS and sleep so the success redirect understands the wallet was created
os.system("sync")
time.sleep(2)
return True
except:
return False
def is_lnd_logged_in():
try:
macaroon = get_macaroon()
headers = {"Grpc-Metadata-macaroon":macaroon}
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1/getinfo", verify=TLS_CERT_FILE,headers=headers)
if r.status_code == 200 and r.json():
return True
return False
except:
return False
def lnd_channel_backup_exists():
return os.path.isfile(CHANNEL_BACKUP_FILE)
def get_lnd_status():
if not lnd_wallet_exists():
return "Please create wallet..."
2020-10-03 04:43:30 +00:00
if not is_bitcoind_synced():
return "Waiting..."
2019-06-15 23:02:44 +00:00
if is_lnd_ready():
return "Running"
2019-09-25 01:21:33 +00:00
try:
2020-05-01 17:48:31 +00:00
#log = subprocess.check_output("tail -n 100 /var/log/lnd.log", shell=True)
log = get_journalctl_log("lnd")
2019-09-25 01:21:33 +00:00
lines = log.splitlines()
2020-05-01 17:48:31 +00:00
#lines.reverse()
2019-09-25 01:21:33 +00:00
for line in lines:
if "Caught up to height" in line:
m = re.search("height ([0-9]+)", line)
height = m.group(1)
percent = 100.0 * (float(height) / bitcoin_block_height)
return "Syncing... {:.2f}%".format(percent)
elif "Waiting for chain backend to finish sync" in line:
return "Syncing..."
elif "Started rescan from block" in line:
return "Scanning..."
2020-05-09 03:35:44 +00:00
elif "Version: " in line:
return "Launching..."
elif "Opening the main database" in line:
return "Opening DB..."
elif "Database now open" in line:
return "DB open..."
elif "Waiting for wallet encryption password" in line:
return "Logging in..."
elif "LightningWallet opened" in line:
return "Wallet open..."
2019-09-25 01:21:33 +00:00
return "Waiting..."
except:
return "Status Error"
2020-10-03 04:43:30 +00:00
def get_lnd_status_color():
if not is_bitcoind_synced():
return "yellow"
if not lnd_wallet_exists():
# This hides the restart /login attempt LND does from the GUI
return "green"
lnd_status_code = get_service_status_code("lnd")
if lnd_status_code != 0:
lnd_status_color = "red"
lnd_status = get_lnd_status()
if lnd_status == "Logging in...":
lnd_status_color = "yellow"
return "green"
2019-06-15 23:02:44 +00:00
def get_lnd_channels():
try:
macaroon = get_macaroon()
headers = {"Grpc-Metadata-macaroon":macaroon}
r = requests.get("https://localhost:"+LND_REST_PORT+"/v1/channels", verify=TLS_CERT_FILE,headers=headers)
if r.status_code == 200 and r.json():
data = r.json()
return data["channels"]
return False
except Exception as e:
print("EXCEPTION: {}".format(str(e)))
return False
2019-08-01 04:27:16 +00:00
def get_lnd_version():
global lnd_version
if lnd_version == None:
lnd_version = subprocess.check_output("lnd --version | egrep -o '[0-9]+\\.[0-9]+\\.[0-9]+' | head -n 1", shell=True)
2020-10-01 00:55:24 +00:00
return "v{}".format(lnd_version)
2019-11-04 04:50:47 +00:00
2020-08-21 00:56:31 +00:00
def get_loopd_version():
global loopd_version
if loopd_version == None:
loopd_version = subprocess.check_output("loopd --version | egrep -o '[0-9]+\\.[0-9]+\\.[0-9]+' | head -n 1", shell=True)
2020-10-01 00:55:24 +00:00
return "v{}".format(loopd_version)
2020-08-21 00:56:31 +00:00
2019-11-04 04:50:47 +00:00
def get_default_lnd_config():
try:
with open("/usr/share/mynode/lnd.conf") as f:
return f.read()
except:
return "ERROR"
def get_lnd_config():
try:
with open("/mnt/hdd/mynode/lnd/lnd.conf") as f:
return f.read()
except:
return "ERROR"
2019-11-05 01:34:19 +00:00
def get_lnd_custom_config():
2019-11-04 04:50:47 +00:00
try:
2019-11-05 01:34:19 +00:00
with open("/mnt/hdd/mynode/settings/lnd_custom.conf") as f:
2019-11-04 04:50:47 +00:00
return f.read()
except:
return "ERROR"
2019-11-05 01:34:19 +00:00
def set_lnd_custom_config(config):
2019-11-04 04:50:47 +00:00
try:
2019-11-05 01:34:19 +00:00
with open("/mnt/hdd/mynode/settings/lnd_custom.conf", "w") as f:
2019-11-04 04:50:47 +00:00
f.write(config)
os.system("sync")
return True
except:
return False
2019-11-05 01:34:19 +00:00
def using_lnd_custom_config():
return os.path.isfile("/mnt/hdd/mynode/settings/lnd_custom.conf")
2019-11-05 01:34:19 +00:00
def delete_lnd_custom_config():
2020-05-20 03:01:14 +00:00
os.system("rm -f /mnt/hdd/mynode/settings/lnd_custom.conf")
def get_lnd_alias_file_data():
try:
with open("/mnt/hdd/mynode/settings/.lndalias", "r") as f:
return f.read().strip()
except:
return "ERROR"
return "ERROR"