On the Lightning network, there’s potential for a malicious (or mistaken) channel counter-party to close your channel with old state. To combat this, you need to stay vigilant (read: online) at all times, watching to punish someone who tries at a moment’s notice.
For nodes unable to stay online 24/7, or anyone who’s worried about some malicious transaction censoring, the idea is that you could have a reliable third party server that keeps an eye on the chain, and punishes anyone who tries to close out your channels with an old invalid state. These are known as Watchtowers.
There’s been talk about Watchtowers since long before I started working with Lightning, but we’re now finally at a point where watchtowers aren’t just talk; The v0.7.0 release of LND means we can actually run them ourselves today. And that’s exactly what we’re here to do.
I’ll walk you through the current setup of running a watchtower, simulate a breach between 2 nodes that I control, and give you the tools you need to try it out yourself.
To run watchtowers at the time of writing, we’ll need to build a version of LND using the v0.7.0-beta-rc1 release. It includes the recently merged watchtower integration pull request. If you haven’t previously setup LND, you can follow the install instructions and come back when you’re done.
Run the following to grab the code from the pull request, and rebuild LND:
git checkout v0.7.0-beta-rc1
make clean && make && make install
We’re also going to need btcd to run a simulated network to test out our breach, so that we don’t put any real money at risk, and we won’t have to wait for long block confirmation times.
Meet The Nodes
For this example, we have 3 players. The victim node in white, who will be receiving a channel from the attacker in black. But unbeknownst to the attacker, the watchtower in blue will be keeping an eye out for the victim.
We’ll seed our attacker with some money to begin the attack, but our victim starts out with a zero balance.
[victim] $ lncli walletbalance
If all goes according to plan, our innocent victim should end up with a wallet balance of slightly less than the breached channel.
Configuring the Watchtower
Our watchtower node is setup with a config that opens a new RPC server that allows nodes to connect to it and start sending their channel state to be watched. We just need to add this to the bottom of the watchtower’s lnd.conf:
Our victim-to-be can then connect to it by adding one configuration to their lnd.conf:
Now when you start them both back up, you should see some logging that lets us know we’re being taken care of.
Priming the Attack
To setup our channel breach, we’ll start with opening a channel to the victim, and then backup our node data while we have a state where all of the balance is on our side. We then make a payment to the victim to put some of the balance on their end, and end up with a new channel state.
Channel states are managed by each individual node, not on any kind of shared ledger like a blockchain. So our attacker can just wait until our victim node goes offline, and then roll back their channel state to the earlier version on the left and attempt a force close.
Thwarting The Breach
With everything in place, the attack need only do a forced channel close, which broadcasts the node’s latest channel state as a transaction on chain. This moves the channel funds into a time-locked UTXO that the attacker would have to wait for before moving.
However, once this transaction is confirmed in a block, our watchtower strikes. It will broadcast a punishment transaction that will move the time-locked UTXO that the attacker had into an address controlled by the victim (Minus any chain or watchtower fees.) This means the attacker loses all of the channel funds in the event of a breach, not just the amount they were trying to steal.
And that’s all there is to it! Justice is served without our victim having to do any work beyond the initial setup.
Trying It Out Yourself
While hopefully you got a good sense of how attacks happen and how watchtowers can punish attackers from the post, it helps to run through it yourself. If that’s something you’re interested in doing, I’ve made a github repository with instructions and configurations for you to do just that. Just clone the repo, and start the README walkthrough. Don’t hesitate to open an issue or shoot me a message on Twitter if something’s not working right.
A special thanks to Conner from Lightning Labs for helping me test this out.