Communicating with Lightning Network Daemon using gRPC

Shunta Shirai
GBEC Tech Blog
Published in
12 min readJun 23, 2019

こんにちは、HashHubの白井です。

HashHubでは日々様々なブロックチェーンプロダクトの調査・研究を行っています。その中でも僕はLightning Networkをメインにやっていて、現在絶賛Lappを開発中です。

というわけで今日も前回に同じく、Lightning Network Daemonについてご紹介したいと思います。今回はgRPCというインターフェースを使用してNodeを操作する方法を解説していきます。

Lnd(Lightning Network Daemon)を操作するインターフェースについて

Lightning Networkを組み込んだApplicationであるLappsでは、通常のアプリケーション構成(左側)と比較して以下のような構成(右側)となります。

https://medium.com/lightwork/lightning-network-development-for-modern-applications-e4dd012dac82

図にある通り、バックエンドのサーバーがLndと通信をして、bitcoinなどのブロックチェーンやそれに関連するオフチェーンの処理を行っていきます。

Lndを操作するためのインターフェースは2つ用意されており、1つ目は先程ご紹介したgRPCというもので、もう一つがWeb開発ではお馴染みのREST APIです。

以下のドキュメントにてその仕様を確認出来ます。

https://api.lightning.community/

これら2つのインターフェースのいずれかを使用して、LappsではLightning Networkと連携したアプリケーションを開発していきます。

gRPCを使ってlndを操作してみる

gRPCとは

既に様々なサービスで利用されているgRPCですが、RESTと比較すると、まだしっかりと触ったことがない人もいるのではないでしょうか。

https://www.grpc.io/docs/guides/

gRPCにはRESTと比較して以下のようなメリットがあります。

  • デフォルトでパラメーターに対する型付けが入っている
  • 双方向ストリーミングなどのHTTP/2を用いた効率的なネットワークリソースの活用が可能
  • protoファイルを定義するだけでクライアント・サーバーの実装を様々な言語で自動生成出来る
  • バイナリ形式のシリアライズフォーマットであるprotocol buffersで通信を行うためJSONやXMLと比較して通信速度が早い

RESTはたしかに多くのWeb開発者にとって馴染みが深い設計ですが、lndを使用して開発する時は、基本的にgRPCを採用して開発されることをおすすめします。

lndのgRPCインターフェースには双方向通信のためのAPIなど、REST API よりも使用できる機能が多く用意されています。REST APIはgRPCはproxyとして用意されているだけでおまけ的な意味合いが強いです。

gRPCクライアントを作成する

ここからは実際にgRPCをインストールして、lndを操作してみます。

lndに関しては既にインストールを完了している前提で話を進めていきます。lndのインストールがまだの方はこちらをご確認ください。https://github.com/lightningnetwork/lnd/blob/master/docs/INSTALL.md

今回はrubyで試してみます。まずは適当なディレクトリを作ってそこで作業を進めていきましょう。

# ディレクトリの作成を行い作業ディレクトリに移動する
$ mkdir ln-grpc
$ cd ln-grpc
# Gemfileの雛形を作成
$ bundle initg

Gemfileに必要なGemを記述。

----Gemfile----# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem 'grpc'
gem 'grpc-tools'
---------------

Gemをインストール。

$ bundle install --path vendor/bundleFetching gem metadata from https://rubygems.org/.........
Resolving dependencies...
Using bundler 1.17.2
Fetching google-protobuf 3.8.0 (universal-darwin)
Installing google-protobuf 3.8.0 (universal-darwin)
Fetching googleapis-common-protos-types 1.0.4
Installing googleapis-common-protos-types 1.0.4
Fetching grpc 1.21.0 (universal-darwin)
Installing grpc 1.21.0 (universal-darwin)
Fetching grpc-tools 1.21.0
Installing grpc-tools 1.21.0
Bundle complete! 2 Gemfile dependencies, 5 gems now installed.
Bundled gems are installed into `./vendor/bundle`

gRPCのソースコードを生成するために必要なGoogleAPIをgithubからクローンします。

$ git clone https://github.com/googleapis/googleapis.gitCloning into 'googleapis'...
remote: Enumerating objects: 116, done.
remote: Counting objects: 100% (116/116), done.
remote: Compressing objects: 100% (82/82), done.
remote: Total 123042 (delta 53), reused 90 (delta 31), pack-reused 122926
Receiving objects: 100% (123042/123042), 134.65 MiB | 14.57 MiB/s, done.
Resolving deltas: 100% (111143/111143), done.

gRPCの定義ファイルをダウンロードして、それをコンパイルします。

$ curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto$ bundle exec grpc_tools_ruby_protoc --proto_path googleapis:. --ruby_out=. --grpc_out=. rpc.proto

以下の2つのファイルが生成されるはずです。

  • rpc_pb.rb
  • rpc_services_pb.rb

gRPCクライアントを使ってlndを操作してみる

--no-macaroonsオプションを設定しlocalhost:10009でlndを起動しておく

  • walletの残高を取得するコードの例
# ファイルを作成し、以下のコードを記述する---- get_wallet_balance.rb ----#!/usr/bin/env ruby$:.unshift(File.dirname(__FILE__))
require "bundler/setup"
require 'grpc'
require 'rpc_services_pb'
# Due to updated ECDSA generated tls.cert we need to let gprc know that
# we need to use that cipher suite otherwise there will be a handhsake
# error when we communicate with the lnd rpc server.
ENV['GRPC_SSL_CIPHER_SUITES'] = "HIGH+ECDSA"
certificate = File.read(File.expand_path("~/Library/Application Support/Lnd/tls.cert"))
credentials = GRPC::Core::ChannelCredentials.new(certificate)
stub = Lnrpc::Lightning::Stub.new('127.0.0.1:10009', credentials)
response = stub.wallet_balance(Lnrpc::WalletBalanceRequest.new())
puts "Total balance: #{response.total_balance}"
-------------------------------

コードを実行し、結果を取得。

$ ruby get_wallet_balance.rbTotal balance: 2952553
  • Invoiceの状態をストリーミングで受け取る。
# ファイルを作成し、以下のコードを記述する---- subscribe_invoice.rb ----#!/usr/bin/env ruby$:.unshift(File.dirname(__FILE__))require "bundler/setup"
require 'grpc'
require 'rpc_services_pb'
ENV['GRPC_SSL_CIPHER_SUITES'] = "HIGH+ECDSA"certificate = File.read(File.expand_path("~/Library/Application Support/Lnd/tls.cert"))
credentials = GRPC::Core::ChannelCredentials.new(certificate)
stub = Lnrpc::Lightning::Stub.new('127.0.0.1:10009', credentials)
stub.subscribe_invoices(Lnrpc::InvoiceSubscription.new) do |invoice|
puts invoice.inspect
end
------------------------------

コードを実行してストリーミング

$ ruby subscribe_invoice.rb# invoiceを発行したり支払いが行われると結果をストリーミング通信で受け取ることが出来る

lncliコマンドを使ってinvoiceを作成。

$ lncli addinvoice --amt=590
{
"r_hash": <R_HASH>,
"pay_req": <PAY_REQ>
}

別のノード(先程invoiceを作成したノードとチャネルは開設済み)から支払いを行う。

$ lncli sendpayment --pay_req=<PAY_REQ># subscribe_invoice.rbを実行しているコンソールで支払いを確認できる

まとめ

lndのリポジトリにある以下のドキュメントには、各言語でのgRPCの使用方法や応用が記載されています。https://github.com/lightningnetwork/lnd/tree/master/docs/grpc

これらのインターフェースの使い方さえ理解してしまえば、lappsを作ることはそんなに難しいことではありません。

皆さんもぜひ試してみてください!

お知らせ

■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。

HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo

■ブロックチェーンエンジニア集中講座開講中!
HashHubではブロックチェーンエンジニアを育成するための短期集中講座を開講しています。お申込み、詳細は下記のページをご覧ください。

ブロックチェーンエンジニア集中講座:https://www.blockchain-edu.jp/

--

--