LNDでchannelを開く

LNDでchannelを開く。
改めて、実験じゃなくて、使うレベルで運用しようとすると本当に複雑な仕組みだと思う。 なぜか資産が減っている(感覚になる)し、こんなもの、どうやったらマスアダプションするのか。

実験先はionのtestnet。 前提として、testnetがGKEに構築済で、syncは終わっているものとする。

下記コマンドを叩いて、対象のclusterが間違っていないことを確認する。

$ kubectl config get-contexts

まず、すべてのblockがsync済であることを確認する。

$ kubectl exec -it lnd-btcd-0 -c btcd bash
$ btcctl --rpcuser=devuser --rpcpass=devpass --rpccert=/rpc/rpc.cert --testnet getinfo
{
  "version": 120000,
  "protocolversion": 70002,
  "blocks": 1583596,
  "timeoffset": -1,
  "connections": 8,
  "proxy": "",
  "difficulty": 1,
  "testnet": true,
  "relayfee": 0.00001,
  "errors": ""
}
exit  

では、いよいよLNDを使っていこう。

connect & openchannel

早速ionとchannelを開く。その前に、peersがあるかを確認してみると、いくつか存在する。これは自動的に接続するためだ。

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet listpeers"
{
  "pub_key": "02312627fdf07fbdd7e5ddb136611bdde9b00d26821d14d94891395452f67af248",
  "address": "23.237.77.12:9735",
  "bytes_sent": "118626",
  "bytes_recv": "1348019",
  "sat_sent": "0",
  "sat_recv": "0",
  "inbound": false,
  "ping_time": "162128",
  "sync_type": "ACTIVE_SYNC"
}

ややこしいことに、connectとchannelは違う。connectは暗号化通信が確立している状態、openchannelはfundingまでできている状態だ。

connect

では、connectして見よう。

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet connect 03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003@tbtc.ion.radar.tech:9735"

peersはどんどん増えてしまうので、ここではjqを使ってfileteringして確認する。

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet listpeers" | jq '.peers[] | select(.pub_key=="03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003")'
{
  "pub_key": "03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003",
  "address": "3.16.119.191:9735",
  "bytes_sent": "172798",
  "bytes_recv": "1332749",
  "sat_sent": "0",
  "sat_recv": "0",
  "inbound": false,
  "ping_time": "159747",
  "sync_type": "ACTIVE_SYNC"
}

このdomainをlookupすると一致していることが確認できる。

$ nslookup tbtc.ion.radar.tech
Non-authoritative answer:  
Name:    tbtc.ion.radar.tech  
Address: 3.16.119.191  

openchannel

チャンネルを開くためには、BTCが必要になる。チャンネルを開く行為自体がbitcoinのトランザクションだし、このchannelにデポジットしないと意味がない。パスモを500円で買って、1000円チャージするようなイメージだ。pasmoと違うのは、返却するときもお金を払わないと行けない。

これはUX上最悪だ。不審感がある。この比喩的な説明は裏の仕組みを理解しないと説得力がないが、裏の仕組みを理解する人は仮にマスアダプションしたとしても0.1%を超えることはないだろう。

testnetの世界のお金を手に入れないと行けないので、財布を作って、貰いに行こう。
まず、財布を作る。

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet newaddress np2wkh" 
{
    "address": "2MvrebQm8r899vV1dmXCDcG65xys9v9fWEm"
}
$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet walletbalance"{
    "total_balance": "0",
    "confirmed_balance": "0",
    "unconfirmed_balance": "0"
}

このnp2wkgはnested-pay-to-witness-key-hash の略で、onn chain addressのこと、ここもたくさんのpointがあるけれどきりがないので一旦見ない。

ここに、どこかのfaucetからbtcを送る。ここのconfirmationはすぐに終わる(3分位)印象だ。testnetのdifficultyは低く、確認回数も少ないからだと思う。

balanceがconfirmされたら、チャンネルを開く。
このあと、listchannelをするとチャンネルに追加されるわけだが、これにはそれなりに時間がかかる。多分こっちは6 confみてる?

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet openchannel --node_key=03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003 --local_amt=20000"
{
    "funding_txid": "7ba84960392c27bb677d549254dca48d0b203ba4876c545dfe3aab43f98ae149"
}
$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet listchannels"                                                                         2019/10/22 7:51:00 +[master]
{
    "channels": [
    ]
}
$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet channelbalance"                                                                       2019/10/22 7:53:03 +[master]
{
    "balance": "0",
    "pending_open_balance": "19817"
}

ここで、20000satをdepositしたのに、"pendingopenbalance": "19817"になっているのがわかる。これは、fundingトランザクション作成の手数料のせいだ。

一定時間が立つと、channelが開かれる。

$ kubectl exec lnd-btcd-0 -c lnd -- sh -c "lncli --network=testnet listchannels"                                                                         2019/10/22 8:13:25 +[master]
{
    "channels": [
        {
            "active": true,
            "remote_pubkey": "03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003",
            "channel_point": "7ba84960392c27bb677d549254dca48d0b203ba4876c545dfe3aab43f98ae149:0",
            "chan_id": "1741182215701397504",
            "capacity": "20000",
            "local_balance": "19817",
            "remote_balance": "0",
            "commit_fee": "183",
            "commit_weight": "600",
            "fee_per_kw": "253",
            "unsettled_balance": "0",
            "total_satoshis_sent": "0",
            "total_satoshis_received": "0",
            "num_updates": "0",
            "pending_htlcs": [
            ],
            "csv_delay": 144,
            "private": false,
            "initiator": true,
            "chan_status_flags": "ChanStatusDefault",
            "local_chan_reserve_sat": "573",
            "remote_chan_reserve_sat": "573"
        }
    ]
}

channelも開けばいいというものではない。今の状態は、自分が開いた状態なので、outbound capacityのみがある状態などという。
要は、自分のほうにしかバランスが存在しないので、送ることしかできないのだ。これだと、主にroutingが発生する際に不都合が生じる可能性がある。下記の図のようなイメージだ。

この問題の詳細は、The Inbound Capacity Problem in the Lightning Network Share thisで理解できる。

今回は、とにかくchannelを開くという概念は、inbound、outboundキャパシティ双方を得た時に成立する。という理解をしておこう。

なので、次はoutbound capacityを得る。

ionから掲示された請求書に支払いをおこなう。
payinvoiceを実施する際にはinteractiveなやり取りが必要になるので、bashでcontainerにログインして操作を行う。

$ kubectl exec -it lnd-btcd-0 -c lnd bash 
bash-5.0# lncli --network=testnet sendpayment --pay_req=lntb10u1pw6u3jypp5tky3hfkmxa0hlatqdjf60v9fczej8xnhf38h5yq7724ufvpnf6tsdzyvehhygzjv9jxzu3qf985ugrfde3x7atwvssxx6rpdehx2mpqgqsryvpsxqczqumpw3escqzpgxqrpcgu0ud0gdn9299kt9k0esc345fwk3sf6skv5nnjr85cega0trwcv5kjnzne542crf38vtk3enzzcqrg9kwm4j4mgcc4na336mprav893qqwfsj6w  
Description: for Radar ION inbound channel @ 20000 sats  
Amount (in satoshis): 1000  
Destination: 03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003  
Confirm payment (yes/no): yes  
{
    "payment_error": "",
    "payment_preimage": "c21c0de3918f2b370a5bfce8a6423f5ead6c4e19db02fabb18dfd56ab14eb138",
    "payment_route": {
        "total_time_lock": 1583644,
        "total_amt": 1000,
        "hops": [
            {
                "chan_id": 1741182215701397504,
                "chan_capacity": 20000,
                "amt_to_forward": 1000,
                "expiry": 1583644,
                "amt_to_forward_msat": 1000000,
                "pub_key": "03d5e17a3c213fe490e1b0c389f8cfcfcea08a29717d50a9f453735e0ab2a7c003"
            }
        ],
        "total_amt_msat": 1000000
    }
}

作業が完了すると、ionのページが下記のように変わる。

今回の実験はここまでとする。