バカンス駆動開発

この前バカンスって言ったら「古っ」って言われました

日報 2018年7月9日 - LightningNetworkを動かしてみる・続

日報、githubでdiaryリポジトリ作ってそっちでやったほうが良い気がしてきた。

仕事

日中はお家で仕事してた。最近はもうずっと家。社会との断絶を感じちゃうよね。あと体の衰えもかんじちゃうよね。

アニメ

この前某勉強会で「プラネテス」がいいって教えてもらったんでちょっと前から観てました。 ぶっちぎりで面白かった。バチェラー2より面白かった。原作が漫画で4巻で完結してるんで買うかも知れない。 プライムで観れるので会員の人は是非。You copy?

LightningNetworkとか

lnd <--> bitcoind 間の通信はzeromqでやるんだけど、通信が通らない。どうもbitcoindのほうでzmqをリッスンできてない感じ。
最近のバージョンでソースコンパイルしたbitcoindならzmqがデフォルトで入ってるはずなんやけど・・。
久々にはまって疲れたからまた明日btcdの方installしてみよう・・

bitcoin.conf

rpcuser=kek
rpcpassword=kek
zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubhashblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28332
zmqpubhashtx=tcp://127.0.0.1:28332

HOST=127.0.0.1

daemon=1
server=1
txindex=1

rpcport=18332
testnet=3

rest=1
rpcallowip=0.0.0.0/0

lnd.conf

Application Options]
debuglevel=trace
debughtlc=true
maxpendingchannels=10
no-macaroons=true
noencryptwallet=1

[Bitcoin]
bitcoin.active=1
bitcoin.testnet=1
bitcoin.node=bitcoind

[Bitcoind]

; The host that your local bitcoind daemon is listening on. By default, this
; setting is assumed to be localhost with the default port for the current
; network.
; bitcoind.rpchost=localhost

; Username for RPC connections to bitcoind. By default, lnd will attempt to
; automatically obtain the credentials, so this likely won't need to be set
; (other than for a remote bitcoind instance).
bitcoind.rpcuser=kek

; Password for RPC connections to bitcoind. By default, lnd will attempt to
; automatically obtain the credentials, so this likely won't need to be set
; (other than for a remote bitcoind instance).
bitcoind.rpcpass=kek

; ZMQ socket which sends rawblock and (optionally) rawtx notifications from
; bitcoind. By default, lnd will attempt to automatically obtain this
; information, so this likely won't need to be set (other than for a remote
; bitcoind instance).
bitcoind.zmqpath=tcp://127.0.0.1:28332

日報 2018年7月8日 - LightningNetworkを動かしてみる

雑な日報を始めてみます

なんか記事にするまでもない雑多なあれこれを、だからといって放っておくと1ヶ月後に「あれ、この1ヶ月なにやってたんだっけ?」となりがちなんで雑でも記録に残すことにしました。

LightningNetwork

LightningNetworkはbitcoinのレイヤー2技術
lndはLightningNetworkの実装の一つ
これにそってローカル環境にdocker-composeでlightning networkクラスタを作ってみた github.com

lightning networkはバックエンドにbitcoinノードが必要でこのlndのチュートリアルではbtcdが採用されている。別にbitcoindでもいいみたい。
aliceとbobのlndノードを立ててchannelをつないで送金できた。
次にチュートリアルにはないけど直接channelが開いていないノード間での送信、multihop paymentと言うらしい、をやってみるがだめだった。
alice <--> bob <--> jon の状態でaliceからjonに支払いたいんだけど経路が見つからないというエラーが返ってくる

{
    "payment_error": "unable to find a path to destination",
    "payment_preimage": "",
    "payment_route": null
}

色々調べたけど解決できず。
そもそもlightningnetworkの基礎知識がないのかと思い、これを読んだ。 LND Overview and Developer Guide
まぁ基礎的なことしか書かれてなくてmultihopのルーティングがどうやっているのかは不明。 paymentしたいdestinationとのルートが存在するかどうか確認する方法がある気がするのでまた今度調べる @todo

Flareというルーティングアルゴリズムについての記事を見つけた。 Flare: Lightning Networkルーティングアルゴリズム - United Bitcoiners
まぁ何言っているかわからないのでこれもおいおい調べる @todo

ルーティングアルゴリズムの性能次第で以下のようなものも実現できます。

  • 1取引あたり0.1円未満
  • 全世界で1秒間に1000万取引以上
  • トランザクション手数料が0.000001%未満

自分はLNのマイクロペイメントに着目していたけどたしかにLNの場合はオンチェーンと違ってノードが増えれば増えるほど処理のキャパが上がるよな〜と。
オンチェーンの場合は増すのはセキュリティだけどレイヤー2になると分散の強みを得るの面白い

grep -A

このオプションは知らなかった
grep -A 1 word でwordにヒットした行とその次の1行をアウトプット
grep -10 wordでヒットした行の前後10行もアウトプット

リンク

所感

雑やな〜・・でも雑じゃないと続かないんで・・

PHPのsessionファイルの生成場所、中身、有効期限など

PHPでセッションを開始すると$_SESSIONに値を出し入れできますが実態はsessionファイルに物理的に書き込まれています。*1
中身見たことなかったのでちょっと調べました。

sessionファイルの場所

生成場所の優先順位

  1. php.iniのsession.save_path
  2. php.iniのsys_temp_dir
  3. /tmpとか

sess_v4vqefhjjllja1bqsabekihpc4みたいな感じでsess_xxxxxxxxxxxxxxという名前のファイル名で保存されます。

sessionファイルの中身

試しにこれを実行すると

<?php
session_start();
$_SESSION['hoge'] = 'hoge';
$_SESSION['huga'] = 'huga';

自分の環境だと/tmp/sess_v4vqefhjjllja1bqsabekihpc4が生成されました。中身をみると

cat /tmp/sess_v4vqefhjjllja1bqsabekihpc4

// 結果
hoge|s:4:"hoge";huga|s:4:"huga";

ぱっと見配列をserialize()したものっぽいですが微妙に違います。
session_encodeという関数を使ってエンコードしているようです。
PHP: session_encode - Manual

デフォルトのアンシリアライズの方法は PHP が内部的に実装しているものであり、 unserialize() とは違います。 シリアライズの方法は、session.serialize_handler で設定できます。

phpinfoを確認するとsession.serialize_handlerにはphpと設定されていました。これがデフォルト値です。試しにphp_serializeに変えてphpを再起動してsessionファイルを確認してみると

cat /tmp/sess_v4vqefhjjllja1bqsabekihpc4

// 結果
a:2:{s:4:"hoge";s:4:"hoge";s:4:"huga";s:4:"huga";}

とまぁおなじみのシリアライズされた文字列になりました。ハンドラがデフォルトのphpだと$_SESSIONの中で数値のインデックスや特殊文字 (| や !) を含む文字列のインデックスが使えません。

sessionファイル名とセッションID

リクエストヘッダーを見るとv4vqefhjjllja1bqsabekihpc4というセッションIDを送っています。

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:ja,en-US;q=0.8,en;q=0.6,de;q=0.4,fr;q=0.2,ko;q=0.2
Cache-Control:max-age=0
Connection:keep-alive
Cookie:PHPSESSID=v4vqefhjjllja1bqsabekihpc4 // ←!
Host:local.example.com
Upgrade-Insecure-Requests:1

クライアントから送信されたセッションIDとsessionファイルの関連付けをどうやっているのかというとそのままセッションIDに接頭辞としてsess_をつけているだけだけでした。セッションIDをそのままファイル名に使っているというのはなにやら不安な気持ちになりますね。

session_regenerate_id ()を実行するとセッションIDが新しく変わるので新しいsess_xxxxxxが生成され、クライアントに新しいセッションIDを返します。

有効期限

セッションスタート時にgcが走ります。
sessionファイルのうち生成からsession.gc_maxlifetime秒経っているファイルが対象で、session.gc_divisor分のsession.gc_probabilityの確率で削除が実行されます。

*1:デフォルトでは。

phpenvで複数バージョンのPHPを同時に利用する

1つのvagrantで複数のPHPを同時に利用できるようにします。この記事では5.6.23と7.0.0を共存させます。

CentOS6.5でapache2.4.6+PHP-FPMの構成です。

phpenv,php-buildはインストールされている前提で始めます。

起動スクリプトの用意とListenするポートの設定

php5.6.23のインストール

$ phpenv install 5.6.23

[Info]: Loaded extension plugin
[Info]: Loaded apc Plugin.
[Info]: Loaded composer Plugin.
[Info]: Loaded github Plugin.
[Info]: Loaded uprofiler Plugin.
[Info]: Loaded xdebug Plugin.
[Info]: Loaded xhprof Plugin.
[Info]: php.ini-production gets used as php.ini
[Info]: Building 5.6.23 into /home/vagrant/.phpenv/versions/5.6.23
[Downloading]: https://secure.php.net/distributions/php-5.6.23.tar.bz2
[Preparing]: /tmp/php-build/source/5.6.23
[Compiling]: /tmp/php-build/source/5.6.23
[xdebug]: Installing version 2.3.3
[xdebug]: Compiling xdebug in /tmp/php-build/source/xdebug-2.3.3
[xdebug]: Installing xdebug configuration in /home/vagrant/.phpenv/versions/5.6.23/etc/conf.d/xdebug.ini
[xdebug]: Cleaning up.
[Info]: Enabling Opcache...
[Info]: Done
[Info]: The Log File is not empty, but the Build did not fail. Maybe just warnings got logged. You can review the log in /tmp/php-build.5.6.23.20160911071038.log
[Success]: Built 5.6.23 successfully.

// 設定ファイルを作成
$ cp /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf.default /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf

サービスに追加

// 起動スクリプトを移動
sudo cp /tmp/php-build/source/5.6.23/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm-5.6.23
// 実行権限付与
sudo chmod 775 /etc/init.d/php-fpm-5.6.23
// システム起動時に自動起動するように設定
sudo chkconfig php-fpm-5.6.23 on
// 確認
sudo chkconfig --list | grep php-fpm

php-fpm-5.6.23  0:off   1:off   2:on    3:on    4:on    5:on    6:off

ポートを変更

FPMはデフォルトで9000番のポートをリッスンするようになっていますが、複数バージョンのPHPを共存させる場合はこのポート番号をずらして運用します。

vi /home/vagrant/.phpenv/versions/5.6.23/etc/php-fpm.conf

listen = 127.0.0.1:9000
↓
listen = 127.0.0.1:9001

同じことをPHP7.0.0で繰り返します。ポートは9002にします。

vi /home/vagrant/.phpenv/versions/7.0.0/etc/php-fpm.conf

listen = 127.0.0.1:9000
↓
listen = 127.0.0.1:9002

注)etc/php-fpm.confにlistenの記述がない場合は、etc/conf.d/www.confにあると思うのでそちらを変更してください。

vhostsの設定

あとはvhostsの設定でドメインごとにfcgiに投げるポート番号を対応させればOKです。

  • local.php5 → 9001番ポート
  • local.php7 → 9002番ポート
## PHP5.6.23
<VirtualHost *:80>
  ServerName local.php5
  #DocumentRoot /var/www/html/php5
  <FilesMatch \.php$>
    SetHandler application/x-httpd-php
  </FilesMatch>
  ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9001/var/www/html/php5/$1
  <Directory "/var/www/html/php5">
    AllowOverride All
    Options -Indexes +FollowSymLinks
    Require all granted
  </Directory>
</VirtualHost>

## PHP7.0.0
<VirtualHost *:80>
  ServerName local.php7
  <FilesMatch \.php$>
    SetHandler application/x-httpd-php
  </FilesMatch>
  ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9002/var/www/html/php7/$1
  <Directory "/var/www/html/php7">
    AllowOverride All
    Options -Indexes +FollowSymLinks
    Require all granted
  </Directory>
</VirtualHost>

ブラウザから見てみる

それぞれのパブリックにphpinfo()スクリプトを置いて、

http://local.php5 f:id:egapool:20160911171148p:plain

http://local.php7 f:id:egapool:20160911171756p:plain

あとがき

個人的なポイントとしては起動スクリプトにバージョン名を入れてわかりやすくしたところですかね。あと試してないですがunixソケットで通信する場合はphp-fpm.sockをphp-fpm-なんとか.confで複数つくれば良いのかなぁ。それはまた今度。

ajaxのエラー(500 internal server error)の解決方法

ajax通信処理でこの画像のように500 (Internal Server Error)と表示さる場合、js側ではなくサーバープログラムが間違っています。

f:id:egapool:20160903155605p:plain

どういうエラーなのか確かめるにはデベロッパーツールのNetworkタブを確認します。サーバーからレスポンスを受け取った以降のすべての通信内容がNetworkに表示されます。

f:id:egapool:20160903161022p:plain

エラーで返ってきた通信(ここはではajax.php)をクリックして右に出てくるパネルのPreviewタブを見るとエラー内容を確認できます。

f:id:egapool:20160903161314p:plain

500エラーで返ってきているのにPreviewタブに何も表示されない場合は、サーバー側でエラーを出力させない設定になっている可能性があります。
その場合は該当のPHP処理の先頭で

<?php
ini_set('display_errors',1);

と記述してみてください。

エラー内容を確認して原因が明らかな場合はそこを修正しておしまい。ただどこがバグの原因かわからない場合はデバッグしてく必要があります。

ひとつはprintデバッグです。printやvar_dumpを挟んでデバッグします。直後にexitかdieさせればprint内容もNetworkタブのPreviewタブで確認できます。

f:id:egapool:20160903162414p:plain

もう一つデバッガーです。ajaxリクエストもステップ実行が可能なのでそれで確認していきます。

以上、ajaxエラーの原因突き止め方法でした。

余談)google search consoleで検索ワード見てると「ajax 500 internal server error」とかでこのブログが表示されている回数が多かったのでちょっと書いてみました。