-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathhtlcScan.sh
132 lines (111 loc) · 5.13 KB
/
htlcScan.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/bin/bash
# This script checks for pending stuck htlcs that are near expiration height (< 13 blocks).
# It collects peers of critical htlc and disconnects / reconnects them to reestablish the
# htlc. Sometimes htlcs are being resolved before expiration this way and thus costly
# force closes can be prevented.
#
# Credits to @feelancer21 & @M1ch43lV for putting this together
#
# usage: */30 * * * * /bin/bash /home/lnd/htlcScan.sh
#
# version: 1.5
# setup telegram bot
# Check if the config file exists
script_path=$(dirname "$0")
if [ -f "$script_path/config.cfg" ]; then
# Source the config file if it exists
source $script_path/config.cfg
else
# Use default values if the config file is missing
echo "Warning: config.cfg not found. Using default values."
TOKEN="YOUR_DEFAULT_TOKEN"
CHATID="YOUR_DEFAULT_CHATID"
fi
# notify me if limit of pending HTLCs > X
NOTIFYLIMIT=10
# define lncli command - (un)comment which applies
# bolt/blitz installation
[ -f ~/.bashrc ] && source ~/.bashrc
[ -z "$_CMD_LNCLI" ] && _CMD_LNCLI=/usr/local/bin/lncli
# umbrel
# _CMD_LNCLI="/home/umbrel/umbrel/scripts/app compose lightning exec -T lnd lncli"
# push message to TG bot
pushover() {
msg=$(echo -e "✉️ htlcScan\n$1")
torify curl -s \
-d parse_mode="HTML" \
-d text="$msg" \
-d chat_id="$CHATID" \
https://api.telegram.org/bot$TOKEN/sendmessage > /dev/null 2>&1
}
# disconnect and reconnect peers
function reconnect {
local output=""
output="Disconnecting:"
ok=$(timeout 10 $_CMD_LNCLI disconnect $1 2>&1 | tr -d '[:space:]')
[[ "$ok" == "{}" ]] && pushover "$output Success" || pushover "$output $1 is not connected"
sleep 30
local node_address=$(timeout 10 $_CMD_LNCLI getnodeinfo $1 | jq -r ".node.addresses[].addr" | grep -Po "([0-9]{1,3}[\.]){3}[0-9]{1,3}:[0-9]*" | head -n 1)
output="Reconnecting after 30sec: "
ok=$(timeout 10 $_CMD_LNCLI connect $1@$node_address 2>&1 | tr -d '[:space:]')
if [ "$ok" == "{}" ]; then
pushover "$output Success"
else
if echo "$ok" | grep -q "alreadyconnected"; then
pushover "$output Already reconnected"
else
pushover "$output $ok"
$_CMD_LNCLI getnodeinfo $1 | jq -r ".node.addresses[].addr" | grep -Po "([0-9]{1,3}[\.]){3}[0-9]{1,3}:[0-9]*" 1>/dev/null 2>&1
local onion_address=$(timeout 10 $_CMD_LNCLI getnodeinfo $1 | jq -r ".node.addresses[].addr" | grep -P "onion" | head -n 1)
output="Reconnecting to onion: "
ok=$(timeout 10 $_CMD_LNCLI connect $1@$onion_address 2>&1 | tr -d '[:space:]')
if [ "$ok" == "{}" ]; then
pushover "$output Success"
elif echo "$ok" | grep -q "alreadyconnected"; then
pushover "$output Already reconnected"
else
pushover "$output $ok"
fi
fi
fi
}
# calculate critical expiration height
blocks_til_expiry=13
current_block_height=$($_CMD_LNCLI getinfo | jq .block_height)
max_expiry=$((current_block_height + blocks_til_expiry))
# load channel list once
listchannels=$($_CMD_LNCLI listchannels)
# fetch pending htlcs
# check for outgoing and incoming
# reconnect predecessor and successor peer of critical htlcs
htlc_list=$(echo $listchannels | jq -r ".channels[] | .pending_htlcs[] | select(.expiration_height < $max_expiry) | .hash_lock" | sort -u)
if [ -z "$htlc_list" ]; then
echo "$(date "+%Y-%m-%d %H:%M:%S") no htlc(s) found with expiration < $blocks_til_expiry blocks"
numhtlcs=$(echo $listchannels | jq -r ".channels[] | .pending_htlcs[] | select(.expiration_height) | .hash_lock" | wc -l)
[[ "$numhtlcs" -gt $NOTIFYLIMIT ]] && pushover "No critical htlcs found.\n$numhtlcs pending htlc(s)"
exit 0
fi
for hashlock in $htlc_list; do
#check for outgoing htlcs
pubkey=$(echo $listchannels | jq -r ".channels[] | select(.pending_htlcs[]? | select(.hash_lock==\"$hashlock\" and .incoming==false)) | .remote_pubkey")
if [ ! -z "$pubkey" ]; then
alias=$(echo $listchannels | jq -r ".channels[] | select(.remote_pubkey==\"$pubkey\") | .peer_alias")
[[ -z "$alias" ]] && alias=$pubkey
htlc_expiration_height=$(echo $listchannels | jq -r ".channels[] | .pending_htlcs[] | select(.hash_lock==\"$hashlock\" and .incoming==false) | .expiration_height")
blocks_to_expire=$((htlc_expiration_height - current_block_height))
pending_htlc_info="⚠ Outgoing htlc to $alias expires in $blocks_to_expire blocks."
pushover "$pending_htlc_info"
reconnect $pubkey
fi
#check for incoming htlcs
pubkey=$(echo $listchannels | jq -r ".channels[] | select(.pending_htlcs[]? | select(.hash_lock==\"$hashlock\" and .incoming==true)) | .remote_pubkey")
if [ ! -z "$pubkey" ]; then
alias=$(echo $listchannels | jq -r ".channels[] | select(.remote_pubkey==\"$pubkey\") | .peer_alias")
[[ -z "$alias" ]] && alias=$pubkey
htlc_expiration_height=$(echo $listchannels | jq -r ".channels[] | .pending_htlcs[] | select(.hash_lock==\"$hashlock\" and .incoming==true) | .expiration_height")
blocks_to_expire=$((htlc_expiration_height - current_block_height))
pending_htlc_info="⚠ Incoming htlc to $alias expires in $blocks_to_expire blocks."
pushover "$pending_htlc_info"
reconnect $pubkey
fi
done