[LN#005]Establish Channel (前半)

相手ノードとのネゴシエーションが終わり、initメッセージの交換が終わると、BOLTメッセージが交換できるようになる。

通常は、ノード間に開設したチャネルを使って送受金を行うため、開設するための「Channel Establish」について説明していく。

まず、ノードのどちらかが出資者(funder)になり、このチャネルでやりとりする総額を決定する。現在のBOLT仕様では、送受金はこの額の範囲内でしか行えない。

送金する場合は送金額を自分に割り当てられた額から減らして相手の割当額に加えるし、着金の場合はその逆になる。
それを繰り返し、チャネルを閉鎖したくなったときに、最後に残った配分をブロックチェーンに展開する。

下の図の青い部分をブロックチェーンではない改装で行うため、2nd Layer技術の一種となっている。
大きなしくみはこれだけである。
ただ、これにdecentralizationやtrustless、秘匿性などを組み合わせていったため、仕様が複雑になっている。

image

Channel Establishは大きく2つに分かれる(BOLTでは前半・後半の呼び名はなく、ここでの説明のために分けている)。

  • funding transaction展開前(前半)
  • funding transaction展開後(後半)

funding transaction“というのは、上の図でいう橙色に当たる。
funderが出資したトランザクションで、その出力先はAさんとBさんのMultiSigになっている。
チャネルの双方が出資し合うように思ってしまうが、BOLT仕様では片方しか出資しない。

このトランザクションをブロックチェーンに展開し、相手が指定したブロック時間だけ経過すると、funding transactionとして有効と見なすことになっている。
今回は、前半だけ解説する。

image

まず、funder(シーケンス図の左)が open_channel メッセージを送信する。
メッセージに問題が無ければ、fundee(シーケンス図の右)が accept_channel メッセージを送信する。

どちらもパラメータが多いが、ここで出資するための情報や条件がほぼ表されている。
主なパラメータを以下に示す(主に、と書いたが、無視できるパラメータは無い)。

MultiSigのための公開鍵 : funding_pubkey
前章に出てきた、鍵生成のためのパラメータ : xxx_basepoint
出資額 : open_channel.funding_satoshis
出資額のうち、相手に渡す額 : open_channel.push_msat
funding transaction展開後、トランザクションが安定したと見なす最短ブロック時間 : accept_channel.minimum_depth

Bitcoinの額は、最小単位がsatoshiである。
しかし、BOLTでの最小単位はmilli-satoshi(msat)で、1000分の1 satoshiである。
ここでは、push_msatがmsatになる。

push_msatは、単に配分として相手に渡すという仕様があるだけで、それを渡すための条件はBOLTで決められていない。
もしpush_msatに値がある状態でチャネルを開設し、そのまま取引をせずにチャネルを閉鎖しても、相手にはpush_msatをsatoshiに変換した額が渡されてしまうので、扱いについては注意が必要である。

accept_channelをチェックして問題が無ければ、 funding_createdメッセージを送信する。
この時点で、チャネルを閉鎖した際、funderとfundeeにいくらずつ配分すべきかのトランザクションを決定することができる。

これはfunding transactionの出力となるトランザクションで、BOLTでは “commitment transaction”と呼ぶ。
以降、commitment transactionでfunderとfundeeの配分を変化させていくことで送受金処理を行っていく。

BOLTではトランザクションの構成を細かく決めることで、トランザクション自体の情報を交換せず、ブロックチェーンに展開する際の署名だけを渡すことが多い(funding transactionが2-of-2 MultiSigのため、その出力であるcommitment transactionを展開するためにはお互いが署名する必要がある)。

ブロックチェーンに見える部分だけの署名関係を簡易図にすると、以下のようになる(txはトランザクションの略)。
commitment transaction(commit_tx)の送金先は、実際はもう少し複雑であるが、基本的にはこうなる。

image

funding_createdメッセージでは、funderが初回のcommitment transactionに署名して、相手に渡す。
また、込みいっていることに、commitment transactionの構成はAさんとBさんで異なる。

これは、funderとfundeeで異なる訳ではなく、トランザクションの項目に”local”と”remote”があり、自分が作るトランザクションの場合は「local=自分」「remote=相手」になり、相手が作るトランザクションの場合は「local=相手」「remote=自分」になるためである。

トランザクションの展開には手数料(fee)も必要になるが、手数料はトランザクションを展開する人の額から差し引くことになっているため、額についてもどちらが展開するかによって変わってくることになる。

それを踏まえて図を修正すると、以下のようになる。

image

そして、funding_createdで送信する署名は、相手が展開するcommitment transactionに対する署名である。

よって、commitment transactionは自分用と相手用の両方を作り、メッセージで送信する場合は相手のcommitment transactionに対しての署名を送信し、メッセージで受信した署名は自分のcommitment transactionでチェックすることになる。

funding_signedを受信して問題が無かった場合、funding_signedメッセージを送信する。
このメッセージも署名を含んでいるが、funding_createdと同様に「相手の持つcommitment transaction」に行った署名になる。

ここまでメッセージを交換すると、funding transactionを展開してから相手が不在になったとしても、自分に取り戻すcommitment transactionを展開することができる状況になったので、funding transactionをブロックチェーンに公開する。

ここまでがEstablish Channelの前半である。

[LN#004]鍵

これからノード間で送金を行うための準備を行う。

送金するためには「チャネル」と呼ぶ関係を作る。
チャネルができた後は、チャネルについた識別子(channel_id)をBOLTメッセージに載せて通信をしていく。
チャネルを開設する処理を「Channel Establishment」と呼んでいる。

https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#channel-establishment

Channel Establishのシーケンスを以下に示す。

image

Channel Establishにて、on-chainからoff-chainに制御を移す。
移す際に、FunderとFundeeのMultiSig(2-of-2)に送金を行う。

その2-of-2の鍵や、不正を行わないようBitcoinのトランザクションにスクリプトを作るための鍵などがあり、それらをEstablish中に交換する。
鍵を直接交換するのでは無く、鍵を生成するための情報を交換し、各自で計算することになる。
計算については、以下を参照のこと。
https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#keys

また、鍵は固定ではなく、2-of-2トランザクションの出力内容を更新するたびに新しく作り替え、古い鍵情報は廃棄(revoke)する。
送金を行った後で古い出力内容をon-chainに載せられてしまうと、Bitcoinとしてはon-chainに見える送金情報しか確認できないため、結果として行った送金が無かったことになってしまうためである。
ただ、廃棄したことを約束事だけにしてしまわず、トランザクションのスクリプトと、BOLTメッセージのルールを組み合わせることで、古い出力内容をon-chainに展開すると、展開した方が損をする、というしくみになっている。

鍵(公開鍵)は、以下の種類がある(2017/11/27現在)。

  • localkey
  • remotekey
  • local_delayedkey
  • remote_delayedkey
  • local_revocationkey
  • remote_revocationkey
  • local_htlckey
  • remote_htlckey

localとremoteがあり、お互いが作成できるだけの情報を交換する。
これらの鍵を使って、それぞれが2-of-2トランザクションからの出力(commitment transaction)を作成できるようになっている。

このように、鍵については慎重に考えられているが、ここでは、以下を認識しておけば良いだろう。

  • 鍵を直接交換しないで交換した情報から生成する
  • 最初の情報交換は、Channel Establish時に行う
  • 2-of-2トランザクションからの出力内容(commitment transaction)が変わるたびに、鍵を作り直す
  • 古い鍵を使ったcommitment transactionを使うと損する設計になっている
参照

https://github.com/nayutaco/ptarmigan/blob/development/ucoin/src/ln/ln_derkey.c

[LN#003]init

前回、ノード間のネゴシエーションを行った。

ネゴシエーション後、最初に送信するBOLTメッセージは”init”である。

https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#the-init-message

image

描画ツールの都合上、initがシーケンスのようにやりとりしているようになってしまったが、実際はどちらが先に送信しても良い。

ただし、initを受信するまでは次のBOLTメッセージを送信することはできない。

initメッセージはglobalとlocalのfeatureをパラメータとして持つ。
featureの内容は、BOLT#9に記載されている。
https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md

featureのデータは最短長になるように送信しなくてはならない。
例えば、現時点ではgolbalfeaturesの定義が無いので「0x00」を送信したくなるが、立てるビットがない場合には送信する必要がないため、ここではgflenを0にして、パラメータ自体を送信しないようにする。
あるいは、奇数ビットについては受信側で無視して良いことになっているため、そういうデータなら送信してもよい。

チャネル接続後、ネットワークが切断されて再接続する場合は、initメッセージのあとに”channel_reestablish”を送信する。
再接続については、説明を省略する。
https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#message-retransmission

参照

https://github.com/nayutaco/ptarmigan/blob/development/ucoin/src/ln/ln_msg_setupctl.c

[LN#002] Noise Protocol

BOLTは、ノード間でメッセージ交換する。

まず、相手ノードとのネゴシエーションを行い、成功したらその相手とBOLTのメッセージを符号化して通信する。
BOLT#8では、ネゴシエーションの方法と、その後のメッセージ符号化/復号化について説明している。
このBOLT#8だけは、他の章からほぼ独立している。


https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md

ネゴシエーションや符号化の仕方は、Noise Protocolという方式を用いている。
Noise Protocol自体はいくつかパラメータがあり、そのうちBOLTで使用するものだけ#8に記載されている。
シーケンスを以下の図に示す。

 

image

 

ここでは、AがBに対して接続を要求するようになっている。
相手ノードとはIPアドレスなどでTCP接続を行った後、相手をnode_id(Bitcoinの公開鍵と同じ計算で求めた33バイトのデータ)で指定してネゴシエーションを行う。
1.5往復して相手のノードに間違いが無ければ、ネゴシエーションが完了する。


それ以降は、ネゴシエーション時に交換した鍵情報で、BOLTのメッセージを符号化/復号化を行う。
メッセージ構造は、以下に記載されている。

https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#lightning-message-specification

 

大きく「メッセージ長」と「メッセージ本体」に分かれる。
メッセージ長はChaChaPoly-1305で符号化+MAC付加する(2+16byte)。
メッセージ本体も同様にChaChaPoly-1305で符号化+MAC付加する(メッセージ長+16byte)。
その両者を結合して、1つのメッセージとして相手に送信する。
受信はその逆の動作を行って復号化する。

 

符号化/復号化の鍵はネゴシエーション時のものを使い続けるのではなく、1000回符号化/復号化するたびにrotation処理を行い、鍵を変更する。
1回の送信で2回の符号化を行うため、500回のメッセージ送信でrotation処理を行うことになる。
https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#lightning-message-key-rotation

 

参照

https://github.com/nayutaco/ptarmigan/blob/development/ucoin/src/ln/ln_enc_auth.c

[LN#001] どこから読むか

現在(2017/11/14)のところ、BOLTは0~11章まである(うち、6章は欠番)。

image

 

このうち、どこから読み始めるのがよいかという質問をされることがあるが、その回答は難しい。


まず、BOLT#0は導入部で用語が多少載っているため、先に目を通すとよいだろう。
テーマソングがあるなど、ふざけたところがあるように見えるかもしれないが、そういった要素はここ以外見当たらない。

 

内容についてはBOLT#1以降になるが、プロトコルの階層順で行くと、BOLT#8を最初に読むのがよいだろう。
BOLT#8は他の章からほぼ独立していて、BOLTでの通信を開始する前のネゴシエーションと、通信を開始してからの符号化処理について書かれている。
他の章は、この章の内容が実現されている前提になっている。
逆に言えば、実装をしないのであれば、BOLT#8はあまり気にしなくてよい。

 

BOLT#1、#2および#7は、P2P通信プロトコルについて記載されている。
BOLT#1,#7で使用するパラメータの一部をBOLT#9で、BOLT#2で使用するパラメータの一部をBOLT#4で詳細に説明している。
BOLT#3は、1st Layer、すなわちBitcoinのブロックチェーンで使用するトランザクションとBOLT#2で交換したメッセージの関係や、スクリプトで使用する鍵の導出について記載されている。
BOLT#5は、トランザクションをon-chain、すなわちBitcoinのブロックチェーンでどのように扱うべきか示している。

 

BOLT#10はノードの情報を得る手段について、BOLT#11は請求書(invoice)についてである。


このように、章単独で読み進められるものではない。
それでもあえてどこからか読み進めるとすれば、BOLT#2がよいか。
内容は分からないにしても、シーケンスが図になっているので、イメージはつかみやすいと思う。

 

ただ、このブログでは、通信を確立するところから順に解説していく。


なお、弊社ではオリジナルノード実装のptarmiganを開発している。
BOLTの標準実装を進めているc-lightningのノードと混在させての送受金テストも動作している(commit id : ebdecebb1a89f7dcd8daa53c57ec58af32f7c40d)。

image

[LN#000] "Basis of Lightning Technology"(BOLT)について

はじめまして、Nayutaのuenoです。

 

BitcoinのLightning Network仕様の1つにBOLTがあります。
これを書いている時点では、まだv1.0になるかならないか、という状況で、変更もしばしば行われています。

弊社ではBOLT実装を行っており、GitHubにて公開しています。
BOLTを読んだだけではわかりづらい箇所が多々ありますが、その内部で何が行われているかを、何回かに分けて解説していきます。

Bitcoinプログラミングの入り口

今回はBitcoin AdventCalendarの記事の一つとなります。

Bitcoin Advent Calendar 2014 – Qiita

 

注意:以下の実験を真似する場合は必ずtestnet環境で行ってください。本物のbitcoinネットワークで行った場合、何か間違いがあれば、最悪持っているbitcoinを全部失います。

この記事に従って損失が出た場合、筆者は一切責任を負いません。

 

BitcoinやBlockchainのアルゴリズムや応用が分かった所で、Blockchainを利用したプログラミングへ進んでいきます。何事も作ってみないと本質は分からないというのが信条です。Ethereumのコードを読むということも考えましたが、まずは情報も一杯あってコードも枯れているBitcoinから初めてみることにします。

f:id:kurinkurin12:20140731231645p:plain

Bitcoinは上の図にあるように世界中に存在するマイニングノードがこれまでの全ての取引を記録したBlockchainと呼ばれるデータを保持しています。このマイニングを行うプログラムはWalletも兼ねており、Satoshi Nakamotoの論文を元に開発されました。

もちろんオープンソースでGithubで公開されています。

https://github.com/bitcoin/bitcoin

bitcoin-qtという名前のソフトウェアです。bitcoindという名前のコマンドラインで起動するデーモンプログラムもあります。

 

また、bitcoinにはSPV(simplified payment verification)と呼ばれる、マイニングを行わないノードも存在します。 スマホ等でよく使用されているbitcoin walletはこちらのSPVノードです。

SPVノードもオープンソース実装がたくさんあります。今回は以下のコードを使用します。

schildbach/bitcoin-wallet · GitHub

 

今回は、この二種類のノードをソースからコンパイルしてbitcoinのやりとりを行います。この環境が作れれば、後はソースコードを読んで、改造し、自分のbitcoinアプリケーションの開発ができるようになるはずです。

 

まずはbitcoin-qtをインストールしてみます。以下の作業は全て、Ubuntu14.04LTS上で行っています。

現在(2014.12.7)の最新バージョンはv0.9.3のようなので、そちらを使います。

まずは、Githubからclone !

git clone https://github.com/bitcoin/bitcoin.git

 

git branch -r でリモートのブランチをチェック

kurimoto@kurimoto-ubuntu:~/Develop/Bitcoin/bitcoin-qt/bitcoin$ git branch -r
origin/0.6.3
origin/0.7.2
origin/0.8.6
origin/0.9.3
origin/HEAD -> origin/master
origin/freenode-verf
origin/master

0.9.3をローカルに再現します。

git checkout -b My0.9.3 origin/0.9.3

doc/build-unixに従って、必要なライブラリをインストール

sudo apt-get install build-essential
sudo apt-get install libtool autotools-dev autoconf
sudo apt-get install libssl-dev

sudo apt-get install libboost-all-dev

sudo add-apt-repository ppa:bitcoin/bitcoin (libdb4.8インストールのため)
sudo apt-get update

sudo apt-get install libdb4.8-dev
sudo apt-get install libdb4.8++-dev

sudo apt-get install libminiupnpc-dev

sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler

sudo apt-get install libqrencode-dev

ライブラリを準備できたらビルド開始

./autogen.sh

./configure

make

コンパイルが始まります。

sudo make install

インストール終了

 

コンパイルが通って、起動させたいところですが、ここで以下の事項に対する知識が必要です。

■bitcoin関連の開発において、以下の3つの実行環境でテストが行われます。

a. main or “production” network

b. test network(testnet)

c. regression test mode

aは所謂bitcoinネットワークです。実際に価値のあるbitcoinの送金等が行われているネットワークです。こちらはプログラムを完全に理解した人以外使用してはいけません。バグがあって、大きな額のbitcoinを知らない人に送金してしまったら、二度と戻ってきません。

bは上記のような開発時の難しさを避けるためにインターネット上に作られているtestnetです。ここでのbitcoinは価値を持ちません。通常はこちらを使いましょう。 -testnetで起動することでこちらに接続します。

cはインターネット上のマイニングネットワークには繋げずに、自分で起動したbitcoindとプライベートなネットワークを作って実験する方法です。今回の記事では使用しません。

 

コマンドライン実行時に -testnet とオプションをつければtestnetで動作させることができますが、ここではbitcoin.confというコンフィグレーションファイルを使って設定する方法を取ります。

以下のページにtestnet用のbitcoin.confサンプルがありますので、これを変更して、~/.bitcoin/のディレクトリに置きます。

insight-api/bitcoin-testnet.conf at master · bitpay/insight-api · GitHub

この状態で起動すると、通常はオレンジのbitcoinロゴが緑のロゴとなって開始します。緑色はtestnetにつないでいることを示しています。

ブロックチェインの同期が始まります。結構な時間がかかります。ネット上にaddnode=blockexplorer.com を加えると書いてあったので、bitcoin.confに加えるとやや早くなりました。

 

マイニングするフルノードはソースからビルドして稼働することができました。次にAndroid上のSPVノードをソースからビルドして動作させます。

git clone https://github.com/schildbach/bitcoin-wallet.git

でソースをローカルに持ってきます。

mvn clean install でビルドが始まります。

無事にビルドが終わると wallet/target/wallet-4.08-test.apk

ができあがります。テストネット用のwalletです。

 

Android SDKをインストールすると使えるようになる、adbを使用してマニュアルインストールします(Androidは開発者オプションと身元不明のアプリのインストールの許可をオンにしておきます)。

adb install wallet-4.08-test.apk

これでUSBコードを通してAndroid端末にbitcoin SPV node walletがインストールされました。

Testnet3と表示されているアプリケーションアイコンをタップすると起動します。

f:id:kurinkurin12:20141207190029p:plain

 

testnet上のbitcoinは実験用としてしか価値がありませんので、以下のtestnet faucetで簡単に手に入れることができます。

TP’s TestNet Faucet

AndroidアプリのQRコードをタップした時に出てくるwallet のアドレスを上記HPで入力し、captchaの値を入力してsendボタンを押すと無事にAndroid walletにtestnet上のbitcoinが入金されました。

f:id:kurinkurin12:20141207190507p:plain

bitcoin-qtの方に戻り、受信ボタンを押して、Request paymentボタンを押すと、受信用QRコードが出ます。

f:id:kurinkurin12:20141207212620p:plain

Androidアプリからこのコードをスキャンして送金してみます。

送金するとblockchain netowrk上にトランザクションが広がります。まだマイニングによって承認されていません。アプリ側で未承認状態にあることが確認できます。

暫く待つと一つ目の承認がblockchain network上で行われ、アプリ上の表示記号が変わります。

それと同時にBitcoin-Qtの方で受金します。

f:id:kurinkurin12:20141207213857p:plain

こんな感じで無事bitcoinを受け取ることができました。

 

以上で、マイニングフルノードとSPVモバイルwalletをソースからコンパイルしてbitcoinのやり取りに成功しました。

 

あとは、ソースコードを解読するなり改造するなりしてbitcoinアプリケーションの開発が可能になります。

 

Let’s hack !!!

 

K.Kurimoto