In this workshop, we are going to setup a shared, private lightning network. Each of you will have your own Lightning Network node with which you will participate in the network. You will:

  • Create and fund your own bitcoin wallet
  • Connect to and open a channel with a "hub"
  • Send a payment to one of the other participants
  • Receive a payment

Here is a diagram to illustrate:

      LND                           LND                          LND
+ ----------- +                   + --- +                   + ----------- +
| participant | <--- channel ---> | hub | <--- channel ---> | participant |
+ ----------- +                   + --- +                   + ----------- +
       |                             |                            |
       |                             |                            |
       + - - - -  - - - - - - - - + - - - - - - - - - - - - - - - +
                           + ----------- +
                           | BTC network | <--- BTCD
                           + ----------- +

This setup will allow all of the participants to send payments to each other.

What is the Lightning Network?

First let's start with a brief, high-level explanation of what the Lightning Network is and how it works. From the community documentation:

The Lightning Network scales blockchains and enables trustless instant payments by keeping most transactions off-chain and leveraging the security of the underlying blockchain as an arbitration layer.
This is accomplished primarily through "payment channels", wherein two parties commit funds and pay each other by updating the balance redeemable by either party in the channel. This process is instant and saves users from having to wait for block confirmations before they can render goods or services.

And the key word to remember is network. Payment channels by themselves are not so interesting. But when a transaction can be passed along from one peer to the next until it reaches its recipient - without the need for a direct connection between the payer and payee - now that is interesting.

Our Own Private Bitcoin Network

Your LN node will communicate with a remote bitcoin node that we are running specifically for this workshop. This bitcoin node is be running in "simnet" mode, which gives us full control over the blockchain. This allows us to instantly mine blocks so that we don't have to wait 10 minutes for each block, which is the average time per block on the mainnet or testnet networks.

Lightning Network nodes need to communicate with a bitcoin node to be able to create on-chain transactions, watch the blockchain for updates, and to open/close channels.

Sharing Information During the Workshop

To make it easy for us to share information with each other during this workshop, we will use an open IRC channel:

  • In your browser go to
  • In the "Channels" field enter #ln-workshop
  • You can send private messages or just post in the general chat

Install and Configure Your Lightning Network Node

Download and install GoLang:

tar -xvf go1.10.3.linux-amd64.tar.gz
mv go ~/.go

Add GoLang-related environment variables to your user's .profile:

cat >> ~/.profile << EOL
export GOROOT="\$HOME/.go"
export GOPATH="\$GOROOT/packages"

Reload your user's .profile to load the new environment variables into the current terminal session:

source ~/.profile

Test GoLang setup:

go version

The previous command should output something like this:

go version go1.10.3.linux/amd64

Install lnd (Lightning Network Daemon):

go get -v -d
cd $GOPATH/src/
make && make install

Create an lnd configuration file:

mkdir -p ~/.lnd;
cat > ~/.lnd/lnd.conf << EOL

One last step to be able to communicate with the btcd node via a TLS-encrypted connection. Save the remote btcd node's TLS certificate to a file locally:

cat >> ~/.btcd/rpc.cert << EOL

Test your lnd setup:

lnd --version

You should see something like this:

lnd version 0.4.2-beta commit=2e838abb3f552e6d4d2186453b739da7cbcefa54

Great! Now let's move on to the next step.

Create and Fund Your Wallet

Start lnd:


You should see something like this:

2018-06-22 11:45:00.734 [INF] LTND: Version 0.4.2-beta commit=2e838abb3f552e6d4d2186453b739da7cbcefa54
2018-06-22 11:45:00.734 [INF] LTND: Active chain: Bitcoin (network=simnet)
2018-06-22 11:45:00.738 [INF] CHDB: Checking for schema update: latest_version=1, db_version=1
2018-06-22 11:45:00.759 [INF] RPCS: password gRPC proxy started at
2018-06-22 11:45:00.759 [INF] RPCS: password RPC server listening on
2018-06-22 11:45:00.759 [INF] LTND: Waiting for wallet encryption password. Use `lncli create` to create a wallet, `lncli unlock` to unlock an existing wallet, or `lncli changepassword` to change the password of an existing wallet and unlock it.

Leave lnd running.

In a new terminal window, run the following command:

lncli create

Follow the prompts to complete the LN wallet creation process.

If successful you should see the following message:

lnd successfully initialized!

Switch back to the terminal window where your lnd is running. You should now see something like this:

2018-06-22 13:07:13.868 [INF] LTND: Version 0.4.2-beta commit=18f17ad49b4cc58635a285e53441d82a0c54fd99
2018-06-22 13:07:13.868 [INF] LTND: Active chain: Bitcoin (network=simnet)
2018-06-22 13:07:13.868 [INF] CHDB: Checking for schema update: latest_version=1, db_version=1
2018-06-22 13:07:13.950 [INF] LTND: Primary chain is set to: bitcoin
2018-06-22 13:07:13.984 [INF] BTCN: Loaded 0 addresses from file '/path/to/LND/data/chain/bitcoin/simnet/peers.json'
2018-06-22 13:07:13.984 [DBG] CMGR: Attempting to connect to BTCD_IP:18555 (reqid 1)
2018-06-22 13:07:14.005 [DBG] CMGR: Connected to BTCD_IP:18555 (reqid 1)
2018-06-22 13:07:14.005 [DBG] BTCN: Sending version (agent /btcwire:0.5.0/neutrino:0.0.1-alpha/, pver 70013, block 0) to BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.026 [DBG] BTCN: Received version (agent /btcwire:0.5.0/btcd:0.12.0/, pver 70013, block 0) from BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.026 [DBG] BTCN: Negotiated protocol version 70013 for peer BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.026 [DBG] BTCN: Added time sample of 0s (total: 1)
2018-06-22 13:07:14.027 [DBG] BTCN: Connected to BTCD_IP:18555
2018-06-22 13:07:14.027 [INF] BTCN: New valid peer BTCD_IP:18555 (outbound) (/btcwire:0.5.0/btcd:0.12.0/)
2018-06-22 13:07:14.027 [DBG] BTCN: Received verack from BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.027 [DBG] BTCN: New peer BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.027 [INF] BTCN: Syncing to block height 0 from peer BTCD_IP:18555
2018-06-22 13:07:14.027 [DBG] BTCN: Sending verack to BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.027 [DBG] BTCN: Sending getblocks (locator 683e86bd5c6d110d91b94b97137ba6bfe02dbbdb8e3dff722a669b5d69d77af6, stop 0000000000000000000000000000000000000000000000000000000000000000) to BTCD_IP:18555 (outbound)
2018-06-22 13:07:14.727 [INF] LNWL: Opened wallet
2018-06-22 13:07:15.509 [INF] LNWL: The wallet has been unlocked without a time limit
2018-06-22 13:07:15.509 [INF] LTND: LightningWallet opened

Funding Your New Wallet

Create a new bitcoin address:

lncli newaddress np2wkh

Note that the address type here is important - np2wkh ("Pay to nested witness key hash").

Example output:

    "address": "<new address printed here>"

Copy and paste this address to the IRC channel.

The workshop organizer should now re-start the btcd node with the address as the recipient "mining" address:

btcd --miningaddr=<ADDRESS>

Then the organizer should generate new blocks using the btcctl utility:

btcctl generate 100

This will generate 100 new blocks.

Example output:

  "... more block hashes omitted"

Normally blocks are mined about once every 10 minutes. But we don't have that kind of time, so we use the above command to generate blocks on-demand as we need them.

Now check your wallet balance:

lncli walletbalance

Example output:

    "total_balance": "5000000000",
    "confirmed_balance": "5000000000",
    "unconfirmed_balance": "0"
  • The amounts shown are in satoshis
  • 1 bitcoin = 100 million satoshis

The above steps should be repeated for each workshop participant.

Opening a Channel

Before you can open channels, you will need to be connected to other lightning nodes ("peers"). To see your current peer connections:

lncli listpeers

Since you haven't connected to any peers yet, the result will be an empty array:

  "peers": []

To connect to the "hub":

lncli connect 0200eacbb299639eb19f4afd39d572e87398062e500e6b63ceb1ebded31fddd3b7@

Now when you list your peers, you should see the hub's node listed:

lncli listpeers


    "peers": [
            "pub_key": "0200eacbb299639eb19f4afd39d572e87398062e500e6b63ceb1ebded31fddd3b7",
            "address": "",
            "bytes_sent": "279",
            "bytes_recv": "279",
            "sat_sent": "0",
            "sat_recv": "0",
            "inbound": false,
            "ping_time": "0"

But all we've done so far is make two lightning nodes aware of each other. We haven't opened any channels yet.

Try to open a channel with your new peer:

lncli openchannel --node_key=<PEER_PUBKEY> --local_amt=1000000

Each channel has two sides ("local" and "remote"). The local_amt argument in the above command is how much you want to add to the channel on the local (your) side.

Example output on success:

  "funding_txid": "41f045e8d3a33cceff237183e37eeabff3aea0cf4d64e28238807afe5df2dfa5"

If you see the following error:

[lncli] rpc error: code = Unknown desc = not enough witness outputs to create funding transaction, need 0.01 BTC only have 0 BTC  available

Then you need to go back to the Create and Fund Your Wallet step above and check that you are using the correct address type.

If you see an error similar to the following:

[lncli] rpc error: code = Unknown desc = has witness data, but segwit isn't active yet

This means that the block height of the simnet blockchain is not high enough. The threshold for segwit activation is 300 blocks on simnet.

When your lightning node tries to open a new channel, it creates and broadcasts a special bitcoin transaction. Before the channel is considered "open", this transaction needs to be confirmed. The default number of confirmations (blocks) is 6. Whoever is controlling the btcd node should generate 6 new blocks:

btcctl generate 6

Check that the channel was created:

lncli listchannels

You should see your new channel:

    "channels": [
            "active": true,
            "remote_pubkey": "0200eacbb299639eb19f4afd39d572e87398062e500e6b63ceb1ebded31fddd3b7",
            "channel_point": "a8ea16394e1c759f57b3486eea33e3977b0a39d7ea70f409c3519bd581b52573:0",
            "chan_id": "1181974999924736",
            "capacity": "1000000",
            "local_balance": "990950",
            "remote_balance": "0",
            "commit_fee": "9050",
            "commit_weight": "600",
            "fee_per_kw": "12500",
            "unsettled_balance": "0",
            "total_satoshis_sent": "0",
            "total_satoshis_received": "0",
            "num_updates": "0",
            "pending_htlcs": [
            "csv_delay": 144,
            "private": false

Super! With your newly opened channel, you can start sending and receiving lightning payments.

Sending and Receiving Payments

The first step in receiving a payment via the Lightning Network, is to generate an invoice. Use the following command to create your first invoice:

lncli addinvoice --amt=10000

Example output:

  "r_hash": "a9b22eca10de08426f11f3f59b8a733f1af831a699c1b3f6ca632533239dc1dd",
  "pay_req": "lnsb1pd8pxdzpp54xezajssmcyyymc3706ehznn8ud0svdxn8qm8ak2vvjnxguac8wsdqqcqzyse0qkh2fdn4adwlz598s4v9l2ulner3jalncsjf33za0r3hksv2u3m7vw2663ypaqcc4fjsuzeh5n5hfsqyggwk3rzp6neng4hza8stgp4aaszp"

The pay_req field is what we will share with our customer (or whoever will pay the invoice).

Share the above payment request invoice via the IRC chat so that one of the other workshop participants can send you a payment.

Some other participant should run the following command to send the payment:

lncli payinvoice <The Payment Request>

But wait, something went wrong:

    "payment_error": "unable to route payment to destination: TemporaryChannelFailure: insufficient capacity in available outgoing links: need 9002018 mSAT, max available is 1312000 mSAT",
    "payment_preimage": "",
    "payment_route": null

We are seeing this error because the hub doesn't have any funds on its side of your channel. In order for the payment to be successfully routed from the other participant to you via the hub, the hub must have a local balance equal to or greater than the requested amount. Here is a series of diagrams to illustrate:

+ ----- +                      + --- +                      + --------- +
| payor | <-- 1000000 -- 0 --> | hub | <-- 0 -- 1000000 --> | recipient |
+ ----- +                      + --- +                      + --------- +

The next step of the failing payment looks like this:

+ ----- +                         + --- +                      + --------- +
| payor | <-- 990000 -- 10000 --> | hub | <-- 0 -- 1000000 --> | recipient |
+ ----- +                         + --- +                      + --------- +

And then where the payment finally fails:

+ ----- +                         + --- +                            + --------- +
| payor | <-- 990000 -- 10000 --> | hub | <-- (10000) -- 1010000 --> | recipient |
+ ----- +                         + --- +       !!!                  + --------- +

Payments are routed by transferring value from one side of a channel to another so that the transacted amount is effectively moved through the network until it reaches its final destination. You can only ever transfer value between the two peers involved in a channel by manipulating the local and remote balances in that channel. It is not possible to transfer value directly between channels. If one side of a channel does not have enough value to transfer to the other side, the routing will fail - as in the example above.

To fix this, you must first send some funds to the hub.

Whoever is controlling the hub should create a second payment request:

lncli addinvoice --amt=10000

Once they've shared the payment request via IRC, go ahead and pay it:

lncli payinvoice <The Hub's Payment Request>

Check the balances in your channel to see that the payment was sent:

lncli listchannels

Now you should see that the remote balance is enough for your previous payment request to be routed.

    "channels": [
            "active": true,
            "remote_pubkey": "0200eacbb299639eb19f4afd39d572e87398062e500e6b63ceb1ebded31fddd3b7",
            "channel_point": "a8ea16394e1c759f57b3486eea33e3977b0a39d7ea70f409c3519bd581b52573:0",
            "chan_id": "1181974999924736",
            "capacity": "1000000",
            "local_balance": "980950",
            "remote_balance": "10000",
            "commit_fee": "9050",
            "commit_weight": "724",
            "fee_per_kw": "12500",
            "unsettled_balance": "0",
            "total_satoshis_sent": "10000",
            "total_satoshis_received": "0",
            "num_updates": "2",
            "pending_htlcs": [
            "csv_delay": 144,
            "private": false

Ask another workshop participant to try to pay your invoice. This time it should be successful. Cool!

That's it for this workshop. The remaining sections are part of the setup guide for the workshop organizer.

Thanks for participating!

Setup Private Bitcoin Network

In order to create a private bitcoin network, you will need to setup at least one bitcoin node. In this workshop, we will be using btcd. Steps to install btcd:

go get -v -u
git clone $GOPATH/src/
cd $GOPATH/src/
glide install
go install . ./cmd/...

Create btcd configuration file. RPC usernames and passwords will be randomly generated when you create the file:

mkdir -p ~/.btcd;
cat > ~/.btcd/btcd.conf << EOL
rpcuser=$(date '+%s%N-ln-workshop' | sha256sum | head -c 20)
rpcpass=$(date '+%s%N-ln-workshop' | sha256sum | head -c 32)
rpclimituser=$(date '+%s%N-ln-workshop' | sha256sum | head -c 20)
rpclimitpass=$(date '+%s%N-ln-workshop' | sha256sum | head -c 32)

Create the btcctl configuration file:

mkdir -p ~/.btcctl;
cat > ~/.btcctl/btcctl.conf << EOL
$(cat ~/.btcd/btcd.conf | grep rpcuser=)
$(cat ~/.btcd/btcd.conf | grep rpcpass=)

Start btcd:


You should see something like the following:

2018-08-17 16:27:16.360 [INF] BTCD: Version 0.12.0-beta
2018-08-17 16:27:16.360 [INF] BTCD: Loading block database from '/home/user/.btcd/data/simnet/blocks_ffldb'
2018-08-17 16:27:16.365 [INF] BTCD: Block database loaded
2018-08-17 16:27:16.373 [INF] INDX: Transaction index is enabled
2018-08-17 16:27:16.374 [INF] INDX: cf index is enabled
2018-08-17 16:27:16.374 [DBG] INDX: Current internal block ID: 0
2018-08-17 16:27:16.374 [DBG] INDX: Current transaction index tip (height -1, hash 0000000000000000000000000000000000000000000000000000000000000000)
2018-08-17 16:27:16.374 [DBG] INDX: Current committed filter index tip (height -1, hash 0000000000000000000000000000000000000000000000000000000000000000)
2018-08-17 16:27:16.374 [INF] INDX: Catching up indexes from height -1 to 0
2018-08-17 16:27:16.374 [INF] INDX: Indexes caught up to height 0
2018-08-17 16:27:16.374 [INF] CHAN: Chain state (height 0, hash 683e86bd5c6d110d91b94b97137ba6bfe02dbbdb8e3dff722a669b5d69d77af6, totaltx 1, work 2)
2018-08-17 16:27:16.375 [INF] RPCS: Generating TLS certificates...
2018-08-17 16:27:16.408 [INF] RPCS: Done generating TLS certificates
2018-08-17 16:27:16.423 [INF] RPCS: RPC server listening on
2018-08-17 16:27:16.423 [INF] AMGR: Loaded 0 addresses from file '/home/user/.btcd/data/simnet/peers.json'
2018-08-17 16:27:16.423 [INF] CMGR: Server listening on [::]:18555
2018-08-17 16:27:16.423 [INF] CMGR: Server listening on

If you have a firewall enabled (always a good idea!), then you will need to allow connections to the btcd node's RPC port:

sudo ufw allow 18556

Print your local area network IP address:

hostname -I

And the credentials for the limited RPC user:

cat ~/.btcd/btcd.conf | grep rpclimit

And finally the btcd node's RPC certificate:

cat ~/.btcd/rpc.cert

Share the output of the above commands with the workshop's IRC channel, so that the workshop attendees can finish the configuration of their lnd nodes.

Follow the participant instructions (links at the top of the page), to setup your lnd node and to create and fund its bitcoin wallet. Your lnd node will act as the "hub" during this workshop.