Did you lose funds on the Lightning Network because of a disk crash? Here’s a way you might get them back. Oliver Gugger Follow Jul 26, 2019 · 8 min read

If you’ve been using the Lightning Network at any point prior to this article being written, you probably know that doing so is still considered #reckless and that there’s a real possibility of losing your bitcoins if anything goes wrong (with your hardware for example).

This is due to a protocol design decision that was only mitigated very recently with the introduction of Static Channel Backups (SCB).

Even though SCBs are great, work as advertised and will help many users being safe in the future, there are a lot of people trying out the Lightning Network that don’t read the warnings and aren’t aware SCBs even exist.

I’ve recently been approached by two people independently who have wiped their systems and wanted to reinstall everything, thinking they would be safe by having the 24 word mnemonic only. They did not back up their channel.backup file containing the SCBs and would have lost all bitcoins that they used to open their channels. So I decided to try and help them recover their funds, that’s how this article and the modified version of LND described here were created.

But before we start, here a short disclaimer: I’ve only really tested this once and was able to recover a few million satoshis from one channel. The other person that approached me is still gathering the information that is needed to start the recovery process.

UPDATE 2019–08–17: The number of channels where recovery was successful has risen to 4, including one private channel, one still open channel and one already force-closed channel. And this is only what I know from people who contacted me, so the number might be even higher.

So to not give you false hope, here are the conditions that need to be met for this to even be possible:

You used LND. This method might be ported to other implementations but it currently only works for LND. 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. 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. 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). 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.

If you can answer all of this with yes, then there is hope! Then you should at least try this guide/tutorial. This will be quite technical and it might not work in all cases. Maybe I’ll also need to tweak the code a bit more. Please DM me on the Lightning Network Community Slack if you need assistance.

Ok, let’s get to it. The following things you will need in order to do this:

Everything you need to compile LND (git, make, go), follow this tutorial. A bitcoind or btcd Bitcoin full node to connect LND to. It should also work over Neutrino but the current version of LND doesn’t allow Neutrino on mainnet yet. My Cryptography Toolkit. Please be aware that entering sensitive information like your 24 word seed or your xprv into any online website poses a risk of it being intercepted. You should use the offline version on a secure and offline computer if possible.

Now that we have everything set up, here is what you have to do:

Clone and build my modified version of LND (based on 0.7.1-beta-rc2).



$ cd lnd

$ git checkout fund-recovery

$ make && make install $ git clone https:// github.com/guggero/lnd.git $ cd lnd$ git checkout fund-recovery$ make && make install

All further commands need to be run inside this directory that was just created.

2. Run the following command and have a look at the parameters you have to provide:

$ ./lnwallet-debug fakechanbackup --help NAME:

lnwallet fakechanbackup - Fake a channel backup file to attempt fund recovery. USAGE:

lnwallet fakechanbackup [command options] [arguments...] DESCRIPTION:



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 bruteforce command). OPTIONS:

--root_key value BIP32 extended root key

--remote_node_info value information about the remote node in the format pubkey@host:port

--funding_txid value the txid of the channel's funding transaction

--output_index value the output index for the funding output of the funding transaction (default: 0)

--short_channel_id value the short channel ID in the format blockheight:transactionindex:outputindex

--capacity value the channel's capacity (default: 0)

The root key you can get using the Cryptography Toolkit. Go to the “aezeed Cipher Seed Scheme” page in the LND menu. In the second block, enter your 24 word mnemonic and your passphrase (if you set any). This should give you the HD root node key (starting with xprv…).

The other information you have to scrape together from 1ml.com. Once you have all information, this should create a file called fake.backup that contains the bare minimum data to initialize the Data Loss Protocol (DLP) with the remote node.

3. In this step we are going to start LND from the modified binary that you created earlier. But before we do so, we have to make sure we don’t overwrite something accidentally. If you have any previous installation of LND and there is a folder called .lnd in your home directory (or wherever LND stored its data), please move it away to a safe location. The next few commands will create a new wallet.db file in this folder and we don’t want your old one to be overwritten.

In terminal window 1 you start the modified LND and connect it to the Bitcoin full node (please follow any other tutorial you find online to do this, I won’t have time to support you on this, sorry). Your command might look something like this:

./lnd-debug --bitcoin.active --bitcoin.mainnet \

--bitcoin.node=bitcoind --bitcoind.rpchost=xxx:8332 \

--bitcoind.rpcuser=xxx --bitcoind.rpcpass=xxx

This will produce a few lines of output and then wait for you to create or unlock the wallet. You don’t need to do anything more in this window, just let the process run. But once the recovery process is successful, there will be a very important log message visible in this window. You will need this, this is very important!

In terminal window 2, run the following command:

./lncli-debug create --multi_file ./fake.backup

This will create a new wallet file and folder structure. But we want to use the original seed to recover from. So when it asks you if you already have a seed and you have to answer yes! Enter the 24 words (and the passphrase if applicable) to setup the wallet again from the original seed you lost funds on.

Once the command completes, follow the output on terminal window 1. LND will sync the whole chain, look for on-chain balances and finally try to connect to the remote node that we specified in the fake SCB file. This might take a while, even with an SSD it can take a few hours.

Once the Data Loss Protocol has been initiated, the following output should be seen in the console output of terminal window 1 (it won’t be in the log file as it’s printed directly to standard out):

------------------------------------------

Received last commit point from remote node!

Secret: xxxxxxxxxxxxxxxxxxxxxxxx, Commit Point: yyyyyyyyyyyyyyyyyyyy

------------------------------------------

If you see this, great! You will need the value of “Commit Point” for the next step. Save this somewhere!

Now all we can do is wait and hope that the remote node force-closes the channel. This will put our balance of the channel back on-chain. But unfortunately not to an address that is watched by the wallet by default but to a special, tweaked address. This address is a combination of a key in our wallet (derived from the seed) and the “Commit Point” we just received. Without the “Commit Point” (that ONLY the remote node knows), we would never be able to calculate the private key that can spend the balance that is now back on-chain.

To now recover the private key for the address that our part of the channel balance should now be on, we first need to find out the address where the force-close transaction output has been locked to. For this, it’s easiest if we have a look at the channel funding transaction (found on 1ml.com, we used this in a previous step) in a block explorer like www.blockstream.info for example. We should now see that this funding transaction has been spent. If that is not the case, then the remote node has not yet force-closed the channel. There might be a way to approach the owner of the node and ask them to force-close manually.

Once we see the spending transaction, we know the address our funds went to. It should be the shorter of both addresses, usually it’s the second output.

Now that we have both parameters we need to brute force the private key, we can run the last command. The root key is the same we used in the first command.

$ ./lnwallet-debug bruteforce --help NAME:

lnwallet bruteforce - Brute force a private key for a force-closed channel payout address. USAGE:

lnwallet bruteforce [command options] root-key per_commit_point payout-address DESCRIPTION:



After successfully retrieving the remote node's last per_commit_point

and instructing it to force-close a channel, the private key that

corresponds to the tweaked no-delay output of our channel balance needs

to be calculated. This command goes through the first few thousand

keys from the seed that could have been used for this. If the command fails, either the per_commit_point does not belong to

the given address or the seed/root key was wrong. OPTIONS:

--root_key value BIP32 extended root key

--per_commit_point value recovered per_commit_point of remote node for our no-delay output

--payout_address value address to brute force private key for

If we are lucky, we should get a message that says exactly that: “We are lucky!”. Followed by a hex representation of a private key. If that is the case, you can import this private key into any wallet and sweep the funds (convert it to the WIF format with my tool). Great, you just got your money back!

Feel free to send me a tip ;-) bc1qcpm6nw32ng4qv3htu8lu80ucnaw7qg276fdxqy

If you don’t get a private key out, there is a whole list of reasons what could have gone wrong. Feel free to contact me, maybe there is something we can do.

I’m glad for any feedback I receive on this guide. My goal is to help as many people as possible to recover any lost funds! Even if that makes Bitcoin less scarce because a few more satoshis are in circulation, it might make the Lightning Network a bit less #reckless.