エンジニアの光田(@34ro)です。lightning networkの動作を検証可能な実装が公開されていると知り、さっそく送金を試してみました。
今回試したのはBlockstreamのElementsProject/lightningです。
単に送金手数料を下げられるだけではなく、受け取る側が金額を指定でき、一瞬で残高が移動することからユーザ体験を大きく向上させる可能性を感じます。
ビットコインを初めて送った時の「え?これでお金が送れたの?」という驚きに似たものを感じました。
今回は
① 2者間で送金
② 2者間で送金の逆方向
③ 中間者を挟んだ送金
の3通りの検証を行い、最後に残高の移動をブロックチェーン上のtxとともにまとめました。
環境構築
OSとサーバ
今回は1つのサーバ上でbitcoindのプロセスと複数のlightningdのプロセスを動かしました。
現時点で環境構築が最も簡単なのはOSはUbuntu 16.04です。
2017年1月現在のtestnetのブロックの合計サイズは10GB程度なのでそれに見合ったストレージを用意する必要があります。
ビルドと起動
bitcoindのビルドについては長いので省略します。公式ドキュメントが参考になります。
lightningdは内部でbitcoin-cliを使うのでPATHが通っている場所にbitcoin-cliが必要なため、make installまで行いました。
bitcoindを起動し、testnetのブロックを同期しておきます。
lightningdもビルドする必要があります。以下のコマンドでビルドできました。詳細な手順はこちら。
git clone https://github.com/ElementsProject/lightning.git
cd lightning
make
① 2者間で送金
lightningdの起動
AliceとBobのlightningdをそれぞれ起動します。
lightning-dirとportを分ければ同一サーバ上で複数のlightningdを動かすことができます。
# Alice
$ ./daemon/lightningd –port 42481 –lightning-dir ~/.lightning-test1
# Bob
$ ./daemon/lightningd –port 42482 –lightning-dir ~/.lightning-test2
lightning-cliで状態を確認します。idがアドレスのような役割をします。
{ “id” : “02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2”, “port” : 42481, “testnet” : true, “version” : “v0.5.2-2016-11-21-130-gcae2830”, “blockheight” : 1086982 }
Aliceに入金
testnetのビットコインはこちらのfausetから入手できます。
同じチャンネルに2回入金してしまうとデータが壊れてしまうので要注意。
{ “address” : “2MsXaEmPZ8NSpepkKm9rxnxP6ezdtjxVx9W” }
$ bitcoin-cli -testnet sendtoaddress 2MsXaEmPZ8NSpepkKm9rxnxP6ezdtjxVx9W 0.001
410d4864a2154245c50e4b5056506fc6a68f7b2df4b610a0d99cded3db07827d
connectコマンドで入金txを渡します。
この入金用txのoutputを使ってAlice,Bobのmultisigアドレスに送金するトランザクションが作られ、ブロードキャストされます。
ブロックに取り込まれるまでコマンドが返ってこないので10分程度止まったままになります。
410d4864a2154245c50e4b5056506fc6a68f7b2df4b610a0d99cded3db07827d
0200000001b9b788dc4ab82b8d897b44be74719f825c2777caa3f2e7a94205d3001a8020db010000006a4730440220690251b35a1056e2b73e53545462d106aba29caa5d765e127f7469a6ae610779022055a746474fae9516eefe1548ae869b8268038b8fcce4f2ca5072484dfb251d610121039dd8ac9596c1eaa4fcb0e316e8d2bc0d04e75b233b22c3718c23a513bb5e6794feffffff02a08601000000000017a91403178f196156cd46014d646c1a160f7db3844191877bb53c00000000001976a914f7f375ae26d1b4b62f4b4c37a9e462a8b1dffc1488acbd951000
# lightning-cli connect
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 connect localhost 42482 0200000001b9b788dc4ab82b8d897b44be74719f825c2777caa3f2e7a94205d3001a8020db010000006a4730440220690251b35a1056e2b73e53545462d106aba29caa5d765e127f7469a6ae610779022055a746474fae9516eefe1548ae869b8268038b8fcce4f2ca5072484dfb251d610121039dd8ac9596c1eaa4fcb0e316e8d2bc0d04e75b233b22c3718c23a513bb5e6794feffffff02a08601000000000017a91403178f196156cd46014d646c1a160f7db3844191877bb53c00000000001976a914f7f375ae26d1b4b62f4b4c37a9e462a8b1dffc1488acbd951000
{ “id” : “026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700” }
無事ブロックに取り込まれたら状態を確認します。
getpeersでチャンネルが張れていること確認します。
この時点ではaliceしか残高を持っていません。feeも全てaliceが負担しています
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 getpeers
{
“peers”:[
{
“name”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700:”,
“state”:”STATE_NORMAL”,
“peerid”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″,
“connected”:true,
“our_amount”:74176000,
“our_fee”:23056000,
“their_amount”:0,
“their_fee”:0,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
# bobのpeer
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 getpeers
{
“peers”:[
{
“name”:”02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2:”,
“state”:”STATE_NORMAL”,
“peerid”:”02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2″,
“connected”:true,
“our_amount”:0,
“our_fee”:0,
“their_amount”:74176000,
“their_fee”:23056000,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
AliceからBobに送金
ではAliceからBobに送金してみます。
まずBob側でinvoice(請求書)を作成し、rhashを発行します。
from-alice-100000-1はラベルなので毎回変更する必要があります。amountの単位はミリsatoshiです。
Aliceのlightningdにこのrhashと宛先、金額を渡すことで残高が移動します。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 invoice 30000000 from-alice-30000000
{ “rhash” : “c7e14cd34b093fd8dce80d4007d17e0486eb06d708554f33fcaa750de59595a4” }
Alice側からrhashを指定して送金します。一瞬でコマンドが返ってきて送金処理が終わります。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 sendpay ‘[ { “id” : “026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700”, “msatoshi” : 30000000, “delay” : 36 } ]’ c7e14cd34b093fd8dce80d4007d17e0486eb06d708554f33fcaa750de59595a4
{ “preimage” : “fe9a9bbbbcccc229ec8a43679242b50a05635fc3ba752e1f95aa88029adb2c3b” }
ネットワーク上にtxをブロードキャストすることなく、lightningd内の残高が変わっていることが分かります。
Aliceのpeerを確認すると30000000ミリsatoshiが動き、their(Bob)のamountはfeeが引かれ18472000ミリsatoshi増えています。
{
“peers”:[
{
“name”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700:”,
“state”:”STATE_NORMAL”,
“peerid”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″,
“connected”:true,
“our_amount”:55704000,
“our_fee”:11528000,
“their_amount”:18472000,
“their_fee”:11528000,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
② 2者間で送金の逆方向
BobからAliceへ送金してみます。
Aliceがinvoiceを発行し、Bobが送金します。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 invoice 10000000 from-bob-10000000
{ “rhash” : “dff935e80c0023d8956c8c7efeeae3e2f0c1ebb7a083f048c09a67e61b17dda1” }
# Bobが送金
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 sendpay ‘[ { “id” : “02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2”, “msatoshi” : 10000000, “delay” : 36 } ]’ dff935e80c0023d8956c8c7efeeae3e2f0c1ebb7a083f048c09a67e61b17dda1
{ “preimage” : “1999c9dbf397ccadb43d803b8dffe4f29ae769f7b6cfe2d309f78a73089b45c5” }
Aliceのpeerを確認するとour_amountが10000000増え、their_amountが10000000減ったことがわかります。
2者間なので手数料を払わず送金することができました。
{
“peers”:[
{
“name”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700:”,
“state”:”STATE_NORMAL”,
“peerid”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″,
“connected”:true,
“our_amount”:65704000,
“our_fee”:11528000,
“their_amount”:8472000,
“their_fee”:11528000,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
③ 中間者を挟んだ送金
新たにCharlieのlightningdプロセスを立て、BobとCharlieの間でチャンネルを作ります。
AliceからBobを経由してCharlieに送金してみます。
Charlieのlightningdを起動
Bobへ入金し、Charlieとのチャンネルをopen。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 newaddr
{ “address” : “2N3QAJXQzEAUrSYTUmUMq17PGh2E2GE4HoY” }
# 入金
$ bitcoin-cli -testnet sendtoaddress 2N3QAJXQzEAUrSYTUmUMq17PGh2E2GE4HoY 0.001
442c61296080ce51faa062b9740a296b7bdd36c79388a563f70a316c4a80a5d1
# 入金用トランザクションを使ってBob,Charlie間でチャンネルをopen
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 connect localhost 42483 `bitcoin-cli -testnet getrawtransaction 442c61296080ce51faa062b9740a296b7bdd36c79388a563f70a316c4a80a5d1`
{ “id” : “0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871” }
amountを指定してAliceからCharlie(id: 0333…)へのrouteを確認します。
201ミリsatoshi余計に払っているのが中間者であるBob(id: 026f…)への手数料です。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 getroute 0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871 20000000 1
{
“route”:[
{
“id”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″,
“msatoshi”:20000201,
“delay”:72
},
{
“id”:”0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871″,
“msatoshi”:20000000,
“delay”:36
}
]
}
受取手がinvoiceを発行してsendpayという流れは変わりません。
2者間の時と同じように一瞬で着金します。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test3 invoice 20000000 from-alice-to-charlie-20000000
{ “rhash” : “b1d765954bc6b54019c94f8e523605c5d593d1330b1f27017d997a0ba3f3cbda” }
# Aliceが送金
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 sendpay ‘[{“id”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″, “msatoshi”:20000201,”delay”:72 },{“id”:”0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871″, “msatoshi”:20000000,”delay”:36 }]’ b1d765954bc6b54019c94f8e523605c5d593d1330b1f27017d997a0ba3f3cbda
{ “preimage” : “f9768bf3075c94e57ad39aaf92b0b183af14409c5111c73d2ebb25743c01e8ad” }
中間者Bobの残高の変化を確認します。
Alice(nameが02a..)から20000201ミリsatoshi受け取り、Charlie(nameが033..)に合計20000000ミリsatoshi送っていることが分かります。
201ミリ satoshiがBobの受け取る手数料です。
{
“peers”:[
{
“name”:”0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871:”,
“state”:”STATE_NORMAL”,
“peerid”:”0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871″,
“connected”:true,
“our_amount”:65702000,
“our_fee”:11530000,
“their_amount”:8470000,
“their_fee”:11530000,
“our_htlcs”:[
],
“their_htlcs”:[
]
},
{
“name”:”02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2:”,
“state”:”STATE_NORMAL”,
“peerid”:”02a5c54fb8ef45265f19821dc54e343b8a8f43eaad363a04b87f20943166072bb2″,
“connected”:true,
“our_amount”:28472201,
“our_fee”:11528000,
“their_amount”:45703799,
“their_fee”:11528000,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
チャンネルのclose
AliceとBobの間のチャンネルをcloseしてみました。
lightningdから最終的にブロックに書き込むtxがブロードキャストされます。
{ }
# peerの状態がSTATE_CLOSE_ONCHAIN_MUTUALに変化する
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test1 getpeers
{
“peers”:[
{
“name”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700:”,
“state”:”STATE_CLOSE_ONCHAIN_MUTUAL”,
“peerid”:”026fc8bccb7cf5ca28c56c98f60699390959076e191405d3216a5a41d2783a2700″,
“connected”:false,
“our_amount”:45703799,
“our_fee”:11528000,
“their_amount”:28472201,
“their_fee”:11528000,
“our_htlcs”:[
],
“their_htlcs”:[
]
}
]
}
ビットコイン残高の動きとブロックチェーン上のtxを確認
一連の送金を通じてAliceの持っているビットコインはこのように変化しました。
Alice用の入金用アドレスに入金(tx) | +100,000 satoshi |
open txのfee(tx) | -2,768 satoshi |
Bobに30,000 satoshi送金 | -30,000 satoshi |
Bobから10,000 satoshi入金 | +10,000 satoshi |
Charlieに20,000.201 satoshi送金 | -20,000.201satoshi |
チャンネルをcloseする(tx) | +10,000 satoshi |
合計 | + 54,938.8 satoshi |
実際にブロックチェーン上で返却されている金額は54,939 satoshiなので合計と一致しています。
openしたときのmultisigへの送金手数料はAliceが負担していますが、closeのtxの送金手数料は半額ずつ負担しています。
トランザクションの種類でいうとP2PKHで入金し、P2WSHでopenし、P2SHでcloseしています。
Bob,Charlie間のチャンネルで使ったトランザクションも載せておきます。
$ ./daemon/lightning-cli –lightning-dir ~/.lightning-test2 close 0333f7b3127bb7a97cb6c350008e243e2862d83cf5fe1d740a7621b0e8e82ae871
{ }
まとめ
コマンドとともにlightning networkを使った送金手順を紹介しました。
この規模ではpayment channelに近いですが一瞬のうちにほぼタダで送金できる点がとにかく衝撃的です。
仮想通貨による決済のファイナリティについてはここでは深入りはしませんが、送金が一瞬で終わるということは利便性を大きく向上させると思います。
受け取る側が金額を指定するのも実際のユースケースでは役立ちそうです。
次回は送金の処理をより詳細に追っていきたいと思います。
大石さんのブログや公式のドキュメントが大変参考になりました。