Android Lightning Tutorial

Aleksa Jovanovic
STK Token
Published in
11 min readFeb 8, 2019
Android and Me :)

Getting Started

In the final part of our Lightning series we will be walking you through running your own Lightning node locally and from an Android phone! Once both nodes are running we will fund the wallet attached to our Android node with test Bitcoin, open a payment channel between our Lightning nodes and make some payments.

Disclaimer: unfortunately this tutorial is tailored for mac users only :(

Overview

To start off, we are going to install btcd and its dependencies and download the Bitcoin testnet blockchain. Next, we will install lnd and its dependencies. While we wait for the testnet blockchain to finish downloading we will break down and set-up the Android code responsible for the Lightning network functionality. Lastly, we will run all of our nodes, open up some payment channels and make it rain.

Toolchain

  • btcd, a Go implementation of the Bitcoin protocol
  • lnd, a Go implemention of the Lightning protocol
  • Android Studio for compiling and running your Android code
  • serveo to expose your lnd node incase the port 9735 is blocked

Installation

Installing btcd and Dependencies

Since the btcd project was made in Go, we will first need to install Go. The easiest way, by far, to install Go is via homebrew. If you dont have homebrew, then you can follow instructions here. If you have hombrew, then simply write the command $ brew install go in your terminal.

After you have installed Go make sure to export your GOPATH and add it to your PATH.

$ export GOPATH=~/gocode
$ export PATH=$PATH:$GOPATH/bin

I’ve created the directory gocode and used it as my GOPATH directory to store any dependencies installed with go. You can use the same directory name or create your own.

Next, let’s install btcd and its dependencies.

$ go get -u github.com/Masterminds/glide
$ git clone https://github.com/btcsuite/btcd $GOPATH/src/github.com/btcsuite/btcd
$ cd $GOPATH/src/github.com/btcsuite/btcd
$ glide install
$ go install . ./cmd/...

Make sure not to get confused with line 2 and 3 as it is one command. Now, let’s spin up our Bitcoin node and download the testnet blockchain.

btcd --testnet --txindex

The --txindex flag tells the Bitcoin node to maintain a full hash-based transaction index. This will greatly improve the speed of our Lightning node.

Let btcd run and download the blockchain, this should take about 4 hours. In the meantime, let’s open up a new terminal window where we can set-up lnd.

Installing lnd and Dependencies

To install lnd and all of its dependencies run the following commands.

$ go get -u github.com/golang/dep/cmd/dep
$ go get -d github.com/lightningnetwork/lnd
$ cd $GOPATH/src/github.com/lightningnetwork/lnd
$ make && make install

lnd and lncli, lnd’s command-line interface, should now be installed on your machine.

Alright, let’s create a config file for lnd so that we don’t have to provide a tome of command-line flags every time we want to start our node. By default lnd will look for its config file in $HOME/Library/Application\ Support/Lnd or you can specify an alternate location using the flag --configfile=/path/to/config. A sample config file that contains all the possible configuration options can be found here. The configuration we will be using will be much more concise and looks like this:

bitcoin.active=1
externalip=<YOUR EXTERNAL IP>
btcd.rpcpass=kek
btcd.rpcuser=kek
bitcoin.testnet=1
bitcoin.node=btcd
btcd.rpchost=localhost

Make sure the config file is named lnd.conf.

Setting-up Our Android App

You can download the Android code from our public github repo here. Most of the major lifting is done inside either MainActivity.java or App.java Let’s start by breaking down what some of the code does.

Pro tip: Press shift-shift to search the whole Android project and use cmd+click on a member or function name to find where it’s used.

This is the wallet initialization code inside MainActivity.java. Basically, using the getWallet(final File datadir) function, if a wallet doesn’t exist it generates a wallet seed file and sets the encryption password to the specified password. If one does exist, it retrieves it. Then, it initializes an Electrum wallet with the local wallet so that the Lightning node can use the Bitcoin backend provided by Electrum.

Side note: The password is set inside of the getWallet(final File datadir) function and you should probably make it something more secure than “123456”

If you want to see your wallet address so you can send test Bitcoins uncomment the following code inside the initWalletNode(App... params) function.

Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Log.d("address", app.getWalletAddress());
}
}, 20000);

Then, inside Logcat you will see your address logged under the identifier address.

The next block of code we are going to look it is the function openChannel(String deposit).

For testing purposes, breakpoints on lines 11, 13, 16 and 25 are very useful!

It’s fairly simple so I’ll just give you a quick explanation. This function makes an asynchronous call to openChannel(final FiniteDuration timeout, final OnComplete<Object> onComplete, final NodeURI nodeURI, final Peer.OpenChannel open) inside App.java and then waits for the OnComplete<Object> to return a result.

Let’s take a quick look at openChannel inside App.java.

For testing purposes, breakpoints on lines 7, 10, 14 and 19 are very useful!

Essentially, line 19 is calling the the Scala module to open a connection with a peer and from lines 4–18 are waiting for that call to complete. If the connections fails, then an error is thrown. If it succeeds, then the Scala module is called again on line 12 to create a payment channel using the final Peer.OpenChannel open object. This object was passed from MainActivity.java and contains data such as amount of satoshis to fund the payment channel, the node uri you are opening a payment channel with and the amount of fees you are paying for the transaction.

Lastly, let’s check out how Lightning payments are made.

Initially, the expiry for the payment request is checked and the fees are set for the transaction. Then, on line 7 an asynchronous call to the Scala module is made to initiate a payment, passing in the amount to be paid, the node id derived from the uri of the node you are paying and some routing info . If the payment succeeds, then all is well, otherwise the onFailure(Throwable failure) throws Throwable method is evoked. Right now this method doesn’t do anything, but ideally you would have some sort of notification appear in the GUI.

Running

Hopefully, btcd has finished downloading the blockchain. You’ll be able to tell if it’s finished if new valid peers are connecting to your node.

Blockchain Finished Downloading

Now, shutdown btcd by pressing Ctrl-c and restart it with the command btcd --testnet --txindex --rpcuser=kek --rpcpass=kek. The last two flags are the username and password lnd will use to connect to btcd. I chose kek for the fun of it, but you should probably choose something more secure 😛

Next up, let’s run lnd in a separate terminal window using the command lnd, but make sure you have set-up your lnd.conf file. Upon first start-up you will be prompted to create your first wallet, so go ahead and open up a new terminal window and type lncli create and follow the directions on screen.

Once you have created your wallet you can switch back to terminal with lnd and see some cool action taking place! Here are a few useful commands that will come in handy:

  • lncli --macaroonpath <PATH TO YOUR ADMIN.MACAROON FILE> macaroons are used as a means of wallet authentication and sometimes lncli won’t be able to find the admin.macaroon file. If lncli can’t find your macaroon file then it will throw and error when you try to run anyone of its commands.The location of the macaroon file is $HOME/Library/Application\ Support/Lnd/data/chain/bitcoin/testnet/
  • lncli listpeers lists peers connected to your Lightning node
  • lncli getinfo gets info about your Lightning node
  • lncli addinvoice -amt <AMOUNT IN SATOSHIS> generates a pay request to be paid by someone participating in a payment channel with you
  • lncli connect <NODE URI> connects to a peer using their node uri
  • lncli disconnect <NODE PUB_KEY> disconnects from a connected peer using their pub_key found when you use the command lncli listpeers. You’ll notice that the pub_key is just the first part of the node uri without the ip address or the port
  • lncli unlock unlocks your wallet when you start-up lnd. You will be asked for the password you used when you created the wallet during the initial start-up of lnd
  • lncli listchannels lists all active payment channels you currently have with other nodes
  • lncli openchannel <NODE PUB_KEY> <AMOUNT IN SATOSHIS> opens a channel with a node with a specified amount committed to the channel
  • lncli closechannel <FUNDING_TXID> closes the provided channel cooperatively using its funding_txid from its channel point. The channel point has the format funding_txid:output_index. If you want to close the channel unilaterally, then use the flag --force as well
  • lncli pendingchannels shows you payment channels awaiting confirmations
  • lncli walletbalance shows us our wallet balance

Alright, now that we have covered some of lnd’s basic commands we can move onto actually connecting our nodes.

You may have noticed that the port which lnd accepts peers on is 9735. This port is most likely closed by your firewall so we will need to use serveo in order to forward traffic to us. Run the command ssh -o ServerAliveInterval=999 -R 9735:localhost:9735 serveo.net. Essentially, this is telling serveo to forward traffic from their port 9735 to ours using the domain name serveo.net.

Make sure to put serveo.net in place of <YOUR EXTERNAL IP> in your lnd.conf file.

Now, we need to get our nodes uri by using the lncli getinfo command. The uri will be inside of the uris block and there should only be one with the format id@ip_address:9735. We will pass this uri in on the simple Android GUI provided in the github repo so that our mobile node can connect.

Let’s start up our Android app. If you have an Android phone you can plug it in now, if not then you can just run the app on a simulator. Run the app in debug mode because some of the debug logs I’ve placed throughout can be useful.

Once the app gets going you’ll be greeted with this screen:

Android Landing Screen

If you remember earlier, I mentioned how you can retrieve your wallet address. Go ahead and do that and use this site to send yourself some test Bitcoins 💸 Since this little demo is pretty primitive, you can restart the app and you should see your wallet balance updated, however sometimes getting the transaction confirmed takes a little bit.

Grab your node uri from earlier and pop it into the Node URI field. If you are using an actual Android phone I suggest checking out Vysor’s free viewing software because then you’ll have a continuous clipboard from your mac to your phone and you’ll be able to use copy and paste! The minimum amount allowed for a deposit is 0.002BTC. I usually use the amount 0.00211 for the deposit amount so that it’s easily recognizable in the feed of lnd. After you have filled out the Deposit field and the Node URI field, you can smash that CONNECT button.

Sometimes you will get “could not connect” errors, if it persists try restarting your serveo ssh server, I’ve found that to help when my node is behaving unpredictably.

Behind the scenes, the Android node is connecting to your local Lightning node and opening up a payment channel simultaneously. This may take a while, but over on your lnd feed in your terminal you should be able to see the fundingRequest coming through.

fundingRequest

You’ll know its the right one because of the unique amount of 0.00211 😄

If you lncli listpeers you should be able to see a new node connected that had the same uri as the one shown in the funding request.

Congrats! Your nodes have made contact 👽

Connected Nodes

Confirming the channel will take a little longer, but you should be able to see it in your pending channels by using the command lncli pendingchannels.

After some time, mine took 1 hr, you should be able to see your newly confirmed payment channel with lncli listchannels. Using mine as an example, from my fundingRequest we can see that my Android nodes uri is 02d1ec413020849d509826c8636efcefc3e2011bb60e51693663d5973dbb6baec2 and here is my open channel:

Open Payment Channel

Bang 💥 we are almost there. Let’s get that Lightning cash flowing now. Using lncli addinvoice -amt 1000 we can generate a pay request for 1000 satoshis.

Pay Request

Back on the Android screen, enter the pay request into the Payment Request field. You can find the payment request in the invoice generated as the value for the pay_req key. In our case it’s lntb10u1pwp4dgdpp5mwsv6nha0jpzngjwl8nuku8xc4a18xaq68khkcz4xw0r0y94rzesdqqcqzys8sacssefge8157zjrsskrgf5d6xnhd4jd3fnyte5k0hcyguxd9rxsg2ky27y5a7xa2kfmeynw23hrppy6mw92fkvngu3zvnu422xthsqwaj96f Now, hit the SEND PAYMENT button.

Payment Received!

Would you look at that, the payment has been received by our local node. If we check out the payment channel with lncli listpeers we see that the local_balance is now 1000 satoshis! How cool 😎

Payment Channel Updated

Now, let’s close up the channel and claim the funds we were sent by our Android node. Wait, first let’s check how much we have in our wallet prior to closing the channel with lncli walletbalance.

You’ll notice that this channels point differs from the channel point in the image above, unfortunately I had to restart the process and forgot to grab a new snapshot. Bare with me.

Balance Pre-closing

Alright, now let’s close up the channel. Notice the funding_txindex we grabbed from the channel_point.

Closing the Channel

Side note: whenever you receive a txid of any sort, you can plug it into this site to see how many confirmations you have because sometimes you’ll be waiting for an hour… Just make sure you are on the test BTC network.

Since we did a force close we will have to wait for the CheckSequenceVerify(CSV) timelock on the contract to expire and that could take up to a day or two.

If we take a look at our pendingchannels, we see our channel, under pending_force_closing_channels, with a field called blocks_till_maturity. This is how many blocks need to be confirmed in order for the timelock to expire.

About Two Days to be Precise

Well, that was underwhelming. As you can see, we have passed the number of blocks required for maturity, but the 1000 satoshis are still in limbo.

The Sweeper is Broken!

Unfortunately, there are some issues going on right now with the lnd’s Lightning Network sweeper. These issues will probably be resolved by the time this article is released. Essentially, a sweeper is a part of the codebase that helps finalize inputs and outputs when a payment channel is closed.

I reached out to the lnd team and they said that they are currently working on this.

And thats all she wrote folks.

Hope you guys enjoyed our Lightning series and took something away from it. This last tutorial was quite dense, but for a real blockchain diehard I think some really valuable information can be gleaned from it. Thanks for reading and make sure to check out the rest of our content and stay tuned for cool things we have coming up.

--

--

Aleksa Jovanovic
STK Token

I’m a blockchain developer and I love building cool things and tinkering with new tech.