Occassional posts about VoIP, SIP, WebRTC and Bitcoin.
The Bitcoin Lightning Network is hopefully the first step towards instant and cheap transactions backed by the security of the Bitcoin blockchain. While that’s an easy sentence to write it’s very tricky concept to implement. I’m nowhere near qualified to delve into the trust and cryptographic issues designed to ensure the parties involved in a lightning payment can’t cheat each other. Instead this post documents the steps involved in the rather contrived experiment of attempting to transfer a 1 milli Satoshi BTC payment from a customer lightning node to a merchant lightning node.
There are a few different lightning implementations available, and hopefully more to come, the ones I have been testing out are c-lightning and lnd. For this experiment I’ve used c-lightning.
The steps to install c-lightning are available here. A bitcoin-core daemon is required to interface with the Bitcoin network.
At this point I should point out that a 1 milli satoshi payment made in isolation makes no sense. That is if a customer opened a lightning channel to a merchant, paid the 1 milli satoshi and closed the channel then the cost of the Bitcoin transaction fees to fund and withdraw from the channel are likely to be in the order of 300 Satoshis. That means the transaction fees are 300,000 times the cost of the payment BUT that’s not the point. With a lightning channel the Bitcoin fees are only paid when a channel is initially funded and withdrawn. If a merchant has a product that costs 1 milli satoshi (USD0.000004 at the time of writing) then hopefully they will be selling lots of them meaning that a customer will keep the channel open and make 100’s of payments before closing the channel (or even just keep it open until all funds are used up).
In the exchange documented below I have two separate lightning/bitcoin-core nodes. One running on my Windows 10 machine, using the customer hostname, and the second on my QNAP NAS in a Linux virtual container, using the merchant hostname.
merchant$ lightning-cli getinfo { "id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "alias": "BIZARREMONTANA", "color": "03a91f", "address": [ { "type": "ipv6", "address": "2a02:120b:2c13:a510:5054:ff:fed8:d0a4", "port": 9735 } ], "binding": [ { "type": "ipv6", "address": "::", "port": 9735 }, { "type": "ipv4", "address": "0.0.0.0", "port": 9735 } ], "version": "v0.6.2-51-gd5aaa11", "blockheight": 1445970, "network": "testnet", "msatoshi_fees_collected": 0 } customer$ lightning-cli getinfo { "id": "032465b71102c76c473f35927b1b2825c9bdeb11624fdc8d1a705f77e655f1c442", "alias": "ORANGENET", "color": "032465", "address": [ { "type": "ipv6", "address": "2a02:120b:2c13:a510:f4b9:89fb:e41c:16be", "port": 9735 } ], "binding": [ { "type": "ipv6", "address": "::", "port": 9735 }, { "type": "ipv4", "address": "0.0.0.0", "port": 9735 } ], "version": "v0.6.2-51-gd5aaa11", "blockheight": 1445970, "network": "testnet", "msatoshi_fees_collected": 0 }
After the two test nodes are running the next steps are to connect them together and fund the client channel.
customer$ lightning-cli newaddr { "address": "tb1qvf26cxv45vudsawwspl09nzvkfrw87mvyc0dr0" } # Use your favourite Bitcoin wallet to send funds your respective address (TESTNET only of course). Recommended minimum is 2000 Satoshis or 0.00002 tBTC. # Connect to the merchant node. The public key is shown in the getinfo response and you need to know the IP address. customer$ lightning-cli connect 03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be@192.168.1.10 # After the two lightning nodes are connected a channel needs to be set up and funded. # There is a minimum channel reserve of 1000 Satoshis which I assume is for the closing fee. 2000 Satoshis was what I settled on for the minimum channel funding amount. customer$ lightning-cli fundchannel 03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be 2000
Generate the 1 milli Satoshi invoice on the merchant
merchant$ lightning-cli invoice 1 onemilli onemilli { "payment_hash": "742c20e3cc37d903bd227afca050504a979fe2962a2ab14552d2f7d142409bbe", "expires_at": 1543527370, "bolt11": "lntb10p1pwqqnd6pp5wskzpc7vxlvs80fz0t72q5zsf2telc5k9g4tz32j6tmazsjqnwlqdqddahx2mtfd3kxjcqp2rzjqvjxtdc3qtrkc3elxkf8kxegyhymm6c3vf8aerg6wp0h0ej478zyy9ssfyqqqggqqqqqqqqpqqqqqzsqqcllp9hknpu5fmyvgenw3r7mp4sgukkhxy5hp3ulawgueluwav07hs6g4vzs8wshs7chdvkl5t8h0ltwrg0t57k7083rtlrfwm2ngm33gq42cn3x" }
During testing I frequently got a warning message of “No channels have sufficient incoming capacity” which I initially took as a meaning any attempt to pay the invoice would fail but as best I can tell it’s not an issue and payments will be accepted.
Pay the invoice with the client.
customer$ lightning-cli pay lntb10p1pwqqnd6pp5wskzpc7vxlvs80fz0t72q5zsf2telc5k9g4tz32j6tmazsjqnwlqdqddahx2mtfd3kxjcqp2rzjqvjxtdc3qtrkc3elxkf8kxegyhymm6c3vf8aerg6wp0h0ej478zyy9ssfyqqqggqqqqqqqqpqqqqqzsqqcllp9hknpu5fmyvgenw3r7mp4sgukkhxy5hp3ulawgueluwav07hs6g4vzs8wshs7chdvkl5t8h0ltwrg0t57k7083rtlrfwm2ngm33gq42cn3x { "id": 3, "payment_hash": "742c20e3cc37d903bd227afca050504a979fe2962a2ab14552d2f7d142409bbe", "destination": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "msatoshi": 1, "msatoshi_sent": 1, "created_at": 1543524861, "status": "complete", "payment_preimage": "2d9ede49827fdb67ec1fa9a9356aa17fcda839e2d2499b1fc2d509b346eef803", "description": "onemilli", "getroute_tries": 1, "sendpay_tries": 1, "route": [ { "id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "channel": "1445961:33:0", "msatoshi": 1, "delay": 10 } ], "failures": [ ] }
Check the merchant and customer node to confirm the payment has occurred.
merchant$ lightning-cli listpeers { "peers": [ { "id": "032465b71102c76c473f35927b1b2825c9bdeb11624fdc8d1a705f77e655f1c442", "connected": true, "netaddr": [ "[::ffff:192.168.1.50]:57236" ], "global_features": "", "local_features": "8a", "globalfeatures": "", "localfeatures": "8a", "channels": [ { "state": "CHANNELD_NORMAL", "scratch_txid": "ef8832dbc3ea36a1bb622d1db3097c368d8ed144fcf8c1b76421724ab2888146", "owner": "lightning_channeld", "short_channel_id": "1445961:33:0", "channel_id": "5da300775abce3c1fd276a37ba2f3548303bf06fe0c27f8959ca5f763f1281aa", "funding_txid": "aa81123f765fca59897fc2e06ff03b3048352fba376a27fdc1e3bc5a7700a35d", "msatoshi_to_us": 1, "msatoshi_to_us_min": 0, "msatoshi_to_us_max": 1, "msatoshi_total": 2000000, "dust_limit_satoshis": 546, "max_htlc_value_in_flight_msat": 18446744073709551615, "their_channel_reserve_satoshis": 546, "our_channel_reserve_satoshis": 546, "spendable_msatoshi": 0, "htlc_minimum_msat": 0, "their_to_self_delay": 6, "our_to_self_delay": 6, "max_accepted_htlcs": 483, "status": [ "CHANNELD_NORMAL:Funding transaction locked. Channel announced." ], "in_payments_offered": 1, "in_msatoshi_offered": 1, "in_payments_fulfilled": 1, "in_msatoshi_fulfilled": 1, "out_payments_offered": 0, "out_msatoshi_offered": 0, "out_payments_fulfilled": 0, "out_msatoshi_fulfilled": 0, "htlcs": [ ] } ] } ] } customer$ lightning-cli listpeers { "peers": [ { "id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "connected": true, "netaddr": [ "192.168.1.10:9735" ], "global_features": "", "local_features": "8a", "globalfeatures": "", "localfeatures": "8a", "channels": [ { "state": "CHANNELD_NORMAL", "scratch_txid": "0b105e7e51503471fd74992ea3cd7f73e07a713a2a88d0351f599492775f7dd4", "owner": "lightning_channeld", "short_channel_id": "1445961:33:0", "channel_id": "5da300775abce3c1fd276a37ba2f3548303bf06fe0c27f8959ca5f763f1281aa", "funding_txid": "aa81123f765fca59897fc2e06ff03b3048352fba376a27fdc1e3bc5a7700a35d", "msatoshi_to_us": 1999999, "msatoshi_to_us_min": 1999999, "msatoshi_to_us_max": 2000000, "msatoshi_total": 2000000, "dust_limit_satoshis": 546, "max_htlc_value_in_flight_msat": 18446744073709551615, "their_channel_reserve_satoshis": 546, "our_channel_reserve_satoshis": 546, "spendable_msatoshi": 1453999, "htlc_minimum_msat": 0, "their_to_self_delay": 6, "our_to_self_delay": 6, "max_accepted_htlcs": 483, "status": [ "CHANNELD_NORMAL:Funding transaction locked. Channel announced." ], "in_payments_offered": 0, "in_msatoshi_offered": 0, "in_payments_fulfilled": 0, "in_msatoshi_fulfilled": 0, "out_payments_offered": 1, "out_msatoshi_offered": 1, "out_payments_fulfilled": 1, "out_msatoshi_fulfilled": 1, "htlcs": [ ] } ] } ] }
The 1 milli Satoshi payment has now been accepted so the channel can be closed.
customer$ lightning-cli close 03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be { "tx": "02000000015da300775abce3c1fd276a37ba2f3548303bf06fe0c27f8959ca5f763f1281aa0000000000ffffffff011807000000000000160014d5f1e21cab97890c2b938318dda83024fb5ce8fa00000000", "txid": "0179d50a2b96a709d91ba36235092ed4db4341c85f881d38458700603d58b41b", "type": "mutual" } customer$ lightning-cli listpeers { "peers": [ { "id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "connected": false, "channels": [ { "state": "CLOSINGD_COMPLETE", "scratch_txid": "0179d50a2b96a709d91ba36235092ed4db4341c85f881d38458700603d58b41b", "short_channel_id": "1445961:33:0", "channel_id": "5da300775abce3c1fd276a37ba2f3548303bf06fe0c27f8959ca5f763f1281aa", "funding_txid": "aa81123f765fca59897fc2e06ff03b3048352fba376a27fdc1e3bc5a7700a35d", "msatoshi_to_us": 1999999, "msatoshi_to_us_min": 1999999, "msatoshi_to_us_max": 2000000, "msatoshi_total": 2000000, "dust_limit_satoshis": 546, "max_htlc_value_in_flight_msat": 18446744073709551615, "their_channel_reserve_satoshis": 546, "our_channel_reserve_satoshis": 546, "spendable_msatoshi": 1453999, "htlc_minimum_msat": 0, "their_to_self_delay": 6, "our_to_self_delay": 6, "max_accepted_htlcs": 483, "status": [ "CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 183 satoshi" ], "in_payments_offered": 0, "in_msatoshi_offered": 0, "in_payments_fulfilled": 0, "in_msatoshi_fulfilled": 0, "out_payments_offered": 1, "out_msatoshi_offered": 1, "out_payments_fulfilled": 1, "out_msatoshi_fulfilled": 1, "htlcs": [ ] } ] } ] }
The channel is now closed and the Bitcoin transaction that returns the funds to each lightning node has now been broadcast. The next thing that happens I don’t understand. Once the close transaction has one confirmation the channel status reports that 100 more blocks are required before the channel can be forgotten. And until that happens the funds from the channel don’t show up in the lightning node’s available funds.
customer$ lightning-cli listpeers { "peers": [ { "id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "connected": false, "channels": [ { "state": "ONCHAIN", "scratch_txid": "0179d50a2b96a709d91ba36235092ed4db4341c85f881d38458700603d58b41b", "owner": "lightning_onchaind", "short_channel_id": "1445961:33:0", "channel_id": "5da300775abce3c1fd276a37ba2f3548303bf06fe0c27f8959ca5f763f1281aa", "funding_txid": "aa81123f765fca59897fc2e06ff03b3048352fba376a27fdc1e3bc5a7700a35d", "msatoshi_to_us": 1999999, "msatoshi_to_us_min": 1999999, "msatoshi_to_us_max": 2000000, "msatoshi_total": 2000000, "dust_limit_satoshis": 546, "max_htlc_value_in_flight_msat": 18446744073709551615, "their_channel_reserve_satoshis": 546, "our_channel_reserve_satoshis": 546, "spendable_msatoshi": 1453999, "htlc_minimum_msat": 0, "their_to_self_delay": 6, "our_to_self_delay": 6, "max_accepted_htlcs": 483, "status": [ "CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 183 satoshi", "ONCHAIN:Tracking mutual close transaction", "ONCHAIN:All outputs resolved: waiting 96 more blocks before forgetting channel" ], "in_payments_offered": 0, "in_msatoshi_offered": 0, "in_payments_fulfilled": 0, "in_msatoshi_fulfilled": 0, "out_payments_offered": 1, "out_msatoshi_offered": 1, "out_payments_fulfilled": 1, "out_msatoshi_fulfilled": 1, "htlcs": [ ] } ] } ] } customer$ lightning-cli listfunds { "outputs": [ { "txid": "0179d50a2b96a709d91ba36235092ed4db4341c85f881d38458700603d58b41b", "output": 0, "value": 1816, "address": "tb1q6hc7y89tj7ysc2unsvvdm2psyna4e686pn98g5", "status": "confirmed" } ], "channels": [ { "peer_id": "03a91ff1bf824e398e07ae2c9dd3ea50081c88350ee896a3eb81c8517e5b0ab7be", "short_channel_id": "1445961:33:0", "channel_sat": 2000, "channel_total_sat": 2000, "funding_txid": "aa81123f765fca59897fc2e06ff03b3048352fba376a27fdc1e3bc5a7700a35d" } ] }
The merchant has no funds. It’s almost certain that the mutual 183 Satoshi fee for the close transaction removes any entitlement the merchant has to 1 milli Satoshi.
Approximately 28 hours later (after 100 x 10 min blocks) the funds on the client return from the channel to the outputs and can be sent from the lightning node using the withdraw <amount> all command.
The lightning channel does a fantastic job of facilitating instant Bitcoin transfers of funds. It’s also easy to get the add the initial funds into a channel. The main pain points are the inability to add funds to an existing channel, to be able to add funds to both ends of a channel and the delay on the extraction of funds.