Did you lose funds on the Lightning Network because of a disk crash? Here’s a way you might get them back.

  1. You used LND. This method might be ported to other implementations but it currently only works for LND.
  2. The remote node you opened the channel with is still online with the same public key and can be looked up on 1ml.com. This is absolutely crucial. If the other node is not online and/or also suffered from data loss, there is simply no way of recovery, sorry.
  3. You do have the 24 word seed of the LND wallet that you got when setting it up. If you set a seed passphrase you also need to know that.
  4. You know exactly which channel(s) you want to recover funds from. And the channels can be seen on 1ml.com too (therefore, no private channels, unless you know the remote node ID and the channel funding TXID from somewhere).
  5. It hasn’t been a long time since you had the accident. I’m not sure how important this is but I guess the longer you haven’t been re-establishing the channel with the remote node the more likely it is they simply “forgot” the information we need.
  6. It’s an old, legacy channel, not one you opened with lnd v0.8.0 or later (those might be even easier to recover, see my new guide linked at the top).
  1. Everything you need to compile LND (git, make, go), follow this tutorial.
  2. A bitcoind or btcd Bitcoin full node to connect LND to. It should also work over Neutrino.
  3. The latest version of my Channel Tools (chantools).
  1. Clone and build my modified version of LND (based on 0.12.0-beta-rc6).
$ git clone https://github.com/guggero/lnd.git
$ cd lnd
$ git checkout fund-recovery
$ make && make install
$ chantools fakechanbackup --help
If for any reason a node suffers from data loss and there is no
channel.backup for one or more channels, then the funds in the channel would
theoretically be lost forever.
If the remote node is still online and still knows about the channel, there is
hope. We can initiate DLP (Data Loss Protocol) and ask the remote node to
force-close the channel and to provide us with the per_commit_point that is
needed to derive the private key for our part of the force-close transaction
output. But to initiate DLP, we would need to have a channel.backup file.
Fortunately, if we have enough information about the channel, we can create a
faked/skeleton channel.backup file that at least lets us talk to the other node
and ask them to do their part. Then we can later brute-force the private key for
the transaction output of our part of the funds (see rescueclosed command).
Usage:
chantools fakechanbackup [flags]
Examples:
chantools fakechanbackup --rootkey xprvxxxxxxxxxx \
--capacity 123456 \
--channelpoint f39310xxxxxxxxxx:1 \
--initiator \
--remote_node_addr 022c260xxxxxxxx@213.174.150.1:9735 \
--short_channel_id 566222x300x1 \
--multi_file fake.backup
Flags:
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--capacity uint the channel's capacity in satoshis
--channelpoint string funding transaction outpoint of the channel to rescue (<txid>:<txindex>) as it is displayed on 1ml.com
-h, --help help for fakechanbackup
--initiator whether our node was the initiator (funder) of the channel
--multi_file string the fake channel backup file to create (default "results/fake-2021-01-23-14-41-03.backup")
--remote_node_addr string the remote node connection information in the format pubkey@host:port
--rootkey string BIP32 HD root key of the wallet to use for encrypting the backup; leave empty to prompt for lnd 24 word aezeed
--short_channel_id string the short channel ID in the format <blockheight>x<transactionindex>x<outputindex>
Global Flags:
-r, --regtest Indicates if regtest parameters should be used
-t, --testnet Indicates if testnet parameters should be used
./lnd-debug --bitcoin.active --bitcoin.mainnet \
--bitcoin.node=bitcoind --bitcoind.rpchost=xxx:8332 \
--bitcoind.rpcuser=xxx --bitcoind.rpcpass=xxx
./lncli-debug create --multi_file ./fake.backup
2021-01-23 14:09:44.306 [DBG] LNWL: ChannelPoint(f39310xxxxxx:1): Peer sent commit_point=020df4d7c539a63589dbb0115a49484d70096b2792bc733fc56ea02d2f3bb4a00c
$ chantools rescueclosed --help
If channels have already been force-closed by the remote
peer, this command tries to find the private keys to sweep the funds from the
output that belongs to our side. This can only be used if we have a channel DB
that contains the latest commit point. Normally you would use SCB to get the
funds from those channels. But this method can help if the other node doesn't
know about the channels any more but we still have the channel.db from the
moment they force-closed.
The alternative use case for this command is if you got the commit point by
running the fund-recovery branch of my guggero/lnd fork in combination with the
fakechanbackup command. Then you need to specify the --commit_point and
--force_close_addr flags instead of the --channeldb and --fromsummary flags.
Usage:
chantools rescueclosed [flags]
Examples:
chantools rescueclosed --rootkey xprvxxxxxxxxxx \
--fromsummary results/summary-xxxxxx.json \
--channeldb ~/.lnd/data/graph/mainnet/channel.db
chantools rescueclosed --rootkey xprvxxxxxxxxxx \
--force_close_addr bc1q... \
--commit_point 03xxxx
Flags:
--bip39 read a classic BIP39 seed and passphrase from the terminal instead of asking for lnd seed format or providing the --rootkey flag
--channeldb string lnd channel.db file to use for rescuing force-closed channels
--commit_point string the commit point that was obtained from the logs after running the fund-recovery branch of guggero/lnd
--force_close_addr string the address the channel was force closed to
--fromchanneldb string channel input is in the format of an lnd channel.db file
--fromsummary string channel input is in the format of chantool's channel summary; specify '-' to read from stdin
-h, --help help for rescueclosed
--listchannels string channel input is in the format of lncli's listchannels format; specify '-' to read from stdin
--pendingchannels string channel input is in the format of lncli's pendingchannels format; specify '-' to read from stdin
--rootkey string BIP32 HD root key of the wallet to use for decrypting the backup; leave empty to prompt for lnd 24 word aezeed
Global Flags:
-r, --regtest Indicates if regtest parameters should be used
-t, --testnet Indicates if testnet parameters should be used

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store