次世代nemのインフラサーバーであるコードネームCatapultがgithubにて公開され、ビルドをしてみたり、動かすための設定をいじったりと、全国のnemberは試行錯誤を重ねて楽しんでいました。
nemtech/catapult-server: Catapult server
そんな中、mijinを開発するテックビューロ社による、docker-compose up
で数分まてばCatapult環境が立ち上がるブートストラップが公開されました。
tech-bureau/catapult-service-bootstrap: Starter project to get developers up and running with a running Catapult Service
公式(?)なお手本ということで、ノード立ち上げまでどんなことが行われているのかを読み解いてみました。
なお、今後のアップデートによって内容が食い違っていく可能性があることをご了承ください。
docker-composeの構成
catapult-service-bootstrap/docker-compose.yml at master · tech-bureau/catapult-service-bootstrap
docker-composeには複数のサービスが定義されていますが、おおまかに分けると以下のことが行われます。
- 初期アドレス、サーバ設定ファイル群の生成
- 初期ブロックの生成
- サーバの立ち上げ
ほとんどが初期設定によるファイル生成ですが、どんな設定をすればいいのかの参考になります。
以下、docker-compose
で実行されるサービスで起こることを順に整理します。
なおdocker-compose #{サービス名}
で一つづつ実行しながら様子を確認してみました。
初期アドレス、サーバ設定ファイル群の生成
generate-raw-addresses
まず最初に実行されるサービスです。
これは初期配布用やノードの設定に使われるアドレスを生成し、build/generated-address/raw-address.txt
として保存しています。
Catapultにはcatapult.tools.address
というアドレスを生成するコマンドが同梱されています。
catapult-service-bootstrap/generate-raw-addresses-if-needed at master · tech-bureau/catapult-service-bootstrap
このシェルスクリプト経由で実行されています。
あとで設定に組み込まれるアドレスはここに保存されたものが使われるので、キーペアはここで確認できます。
store-addresses
先に生成されたraw-addresses.txt
から、後に生成するノード設定のテンプレートへ流し込むために整形されたアドレス定義を生成します。
catapult-service-bootstrap/addresses.rb at master · tech-bureau/catapult-service-bootstrap
このrubyスクリプトによって整形済みのファイルがbuild/generated-addresses/addresses.yml
として保存されます。
catapult-service-bootstrap/addresses.rb at master · tech-bureau/catapult-service-bootstrap
このあたりの定義によって、以下のセクションごとにそれぞれで使われるアドレスとして振り分けられます。
- peer_nodes
- api_nodes
- rest_gateways
- nemesis_addresses_harvesting
- nemesis_generation_hash
- nemesis_signer_private_key
- nemesis_addresses
generate-configs
CatapultのノードやAPIサーバ用の設定である*.propertiesや*.jsonファイルをそれぞれ生成します。
ここで、直前に生成されたbuild/generated-addresses/addresses.yml
が使用されます。
ruby/bin/generate-and-write-configurations.rb
このスクリプトがruby/catapult-templates
以下のファイルをテンプレートとしてアドレスを流し込み、build/catapult-config
へ各ノードの設定ファイルを、/build/nemesis
へ初期ブロック生成の設定ファイルが保存されます。
初期ブロックの生成
ノードはPeerサーバ
2つとAPIサーバ
1つの3つ分の初期化が行われます。
- peer-node-0-nemgen
- peer-node-1-nemgen
- api-node-0-nemgen
peer-node-0-nemgen
dockerfiles/nemgen/userconfig/nemgen.sh
が実行され、直前で生成されたbuild/nemesis/block-properties-file.properties
を使い、初期ブロックを生成してdata/peer-node-0/00000
のように保存します。
catapult-service-bootstrap/nemgen.sh at master · tech-bureau/catapult-service-bootstrap
他のサーバも初期ブロックの保存ディレクトリが異なるだけで、同様の処理がおこなわれます。
init-db
data/mongo
にMongoDBの初期DBファイルを生成して保存します。
static-config/mongo
以下を使ってコレクションやスキーマの設定等を行い、data/mongo
にDBファイルが保存されます。
サーバの立ち上げ
ここまでで、ノード、API、DBサーバの初期設定が終わったので、いよいよサーバの立ち上げをしてみます。
db
まず先にdocker-compose up -d db
でmongoDBを立ち上げておきます。
docker-compose logs -f db
でログを表示して動作しているかを確認できます。
peer-node-0
Peerノード
を立ち上げてみます。docker-compose up -d peer-node-0
。
同様にdocker-compose logs -f peer-node-0
でログを表示してみます。
peer-node-0_1 | 2018-05-26 06:43:57.685252 0x00007fb024ae8700: <error> (ionet::PacketSocket.cpp@456) failed when resolving address 'peer-node-1': Host not found (authoritative) (cancelled? false)
このようなpeer-node-1
への接続でタイムアウトしたというエラーが確認できました。
これはcatapult-config/peer-node-0/userconfig/resources/peers.p2p.json
に定義されているknownPeers
にかかれているpeer-node-1
が立ち上がっていないからです。
このファイルにて、他のPeerサーバ
を既知のサーバとして定義するようです。
peer-node-1
では一度ログ表示を抜けて、docker-compose up -d peer-node-1
でもう一つのノードを立ち上げてみます。
もう一度docker-compose logs -f peer-node-0
でログを確認すると、先程のエラーがでなくなっています。
docker-compose logs -f peer-node-1
でもう一台のノードのログを見てもエラーはでていません。
peer-node-0_1 | 2018-05-26 06:59:28.796465 0x00007fb025aea700: <debug> (src::NetworkHeightService.cpp@45) network chain height increased from 92 to 93
しばらく様子を見ていると、このようなブロック高が上がっていくログが確認できます。
またdata/peer-node-0/00000/*
にブロックごとのファイルが生成されているのも確認できます。
api-node-0
Peerノード
が立ち上がり、通信も始まってブロック生成が進んでいるので、その情報を取得するためにAPIノード
をdocker-compose up -d api-node-0
で立ち上げてみます。
これでノードは立ち上がりますが、APIに問い合わせを行うにはAPI RESTサーバ経由で行うため、Catapult RESTサーバ
も立ち上げます。
rest-gateway
docker-compose up -d rest-gateway
でサーバを立ち上げます。
ポートが3000:3000
でマッピングされているので、localhost:3000
でアクセスできます。
http://localhost:3000/block/1 で初期ブロックの情報が取得できるはずです。
{"meta":{"hash":"D2C9D14D39C4568D9D75E6AB7B143F8C655C145822CA49BEF45D3D630BDDC288","generationHash":"AA0F8D3D9D5E7C6610DC3EE7055E3BA4EE0D8AA9C2DB497C46601B1AC94CC54A","totalFee":[0,0],"numTransactions":25,"merkleTree":["OBuL94fOt46Udsq/PH+dmkL8QiEIi40MeZoq8PZ2dN4=","4cWF2igNFzQDiFTf3XjRFpuoWXiZTnHFVZt5VyC80h4=","tZFQpYOnXfS9vI8dv/7cZ6i4Ba5tToDlvZzSR7THWHw=","pTSRSTCRqAKzAaQ5Ckli693yKux/CjXO9H6B3FjKWPw=","rk3KArNr6HEVhH21dKKMgxcqiBHXzrMeXam2xdutwPI=","BRff7PJgm+td7ItGBHp3n8/1JDPPzCzCTdLT3Q5+oRI=","sPZNdyRW70L0yup5xXJIois+AiJKX12XDx0nubJYkFk=","997muKVVL/d7FBXw8RJb3JnlvEtfYfQupmcHEBahu9E=","4dj7rBkx4Ovf84CrlDlsS450ZiiH5lQpLff4Dbf1Ncc=","VNB2Ac6BXIboulluP59kcggNkhFoIuYuIfRwzBeHxKw=","TtYMSOkBUI8F2C4agrIm+eTCDQQxR8SFBf0VhnI3SM0=","Hv1HzVdX73+ovJJXidmcUX6fjeYd7z17OddoUZ8mzCU=","CUXz9nakZs+7G7amEZr0pBiQV/nmTgiMnnAYuWvexrI=","VGL3PKA+zjlW0IaQpKX9V58D7sIQ6kn8thLU3+coxx8=","+yITEMK/YRoFOjQO1+86jF3kDU6xkFyk3LKmIHNWgKU=","V291O3JcLFbvQm+8UyZSrSgQ8u6oiNRtJm89KdPZfIo=","SkJVhIY+2VMIGtffLWAbSoJPKYFaD6VxrRSsyHyQBT0=","NTHU0GDUgkC/egeztPLPuPcj1LhMce5VeIUoWeIJ9lk=","d1lsh9Lcp9i1IB6pbnym51SpCSrWKPFUr73aFXGFBDo=","chrpJrTa7rQSMPpy+MJ3xLC9UOkGndx926/vBXrO0ig=","3Lk9R2z9Y8tYqq9ThcHXUvHTgmj0mqfDDhQ9qDvikBE=","HEokpIyjCQ9w40CGj/71n9xFNu0g/MJ+/5uL06HV5Q8=","fkeVhjGF9xA+jYAyk8T3btklNZ4tE1mWAu1wrbwU/ow=","Z5a3zLpvqztwAut3niBg1msbTAOQJYzEB3GQR0rrVFs=","Sz/8PppR+n4wsxHEXN0A711Je3C5bTe+mZtdbCx5uDU=","Sz/8PppR+n4wsxHEXN0A711Je3C5bTe+mZtdbCx5uDU=","CGem9XU3w92hxfMpaMdQDQHnudspAf1M6EtqhgdKVtQ=","XzoNdGrGPolxg7/AoYez4HMin825OcNiI1hjtDNXLwg=","f0suZxEsZDIfPcdufMwqpebSCBIcOyzuYuBjYvomun8=","Bpq8IQcM2kzXzgbKud+SE1InfpCOyeM9wHC29TozSFY=","IFVanFxIkdp6A4OD9HEtDpBSdy/VXIWYEsM5GoPUYok=","bUQMSbSaoEPsh5vtAVTHjLwCHHqu4KD21GNSViZTDsE=","/VsaOM9Z+RmSynfPeUp5/kQFFxGi9MkxcO91aqkNTpg=","vPKamiarY55ytNaZEoUKS8PrVsUS4RhrUFp65/un9so=","b6jlNCQRQmOF2+8YwOL/OCfwnsugBqv7ovZ5e8zWpyk=","7qW6QR//B7sHBzs3vAzoeRcrWtZAQWfBVEC2jwKLzcI=","QliJlD42cy2WgSpLd4gslvwgHezhFLKtiRLfrxPc/qc=","JjzWCjAdEVpexhdGb29nK+08fk0tRUyzDpMV7Ij5j1s=","qUdfpbxjStVqpY2e/J+sJwN7kDjl6pr4e6dbMDWgBhQ=","qUdfpbxjStVqpY2e/J+sJwN7kDjl6pr4e6dbMDWgBhQ=","yOQy6nWN6NDFSiPmrPXpytzQWhbxLjODTITeNs1U3zE=","RLdXP9MefX58wUwtVJaXwddfastzNCgsfFXiV0a+pvs=","ef/4Tsnm0IIFagWGL+dw5dXQ3+EDqa0YDxKtMxtNbfU=","9S0HcHOeSbzkejEa2lUaAz1/3hshb1EKZ2wqUa66rms=","or3ekl67vX2JMHyetigbMyUn2BUKG+zD0GdhkIMGkXg=","SCpHwM/Kzzz1vhSy019lDuJRlGwWjcaWs89jVF3Mx9Y=","geyf5O/FYsnAoJwKbrFXTtJ5iIFBkOF3mhrxUwdilAU=","geyf5O/FYsnAoJwKbrFXTtJ5iIFBkOF3mhrxUwdilAU=","S+U4C/ad+betMBaPPETc1RZS4He8J61tBfXjvoP9V6o=","ITHxpUzwRqvJrZjycVrmzGgW0/L/1Mp3hK1QX3yIrpA=","Kfu2NlCFKkG1i2i1vpKuCwWFECzcVHo/1WAZa4IZUmY=","Sc3eVT+gitnT37+2uLhqOoy7wLi4yFEVXSRAdhXLlv4=","8V1d2f2t1Ijj2BYJR8SvBlz2VEYPYas7k7r2BkjnBOo=","j/xajoh8JrZgqienrEGl8dejxz5yM16MpZRdlwnoiqc=","8j2VoUs2QB9ThUm+a2T0Fcv4H/l2SQ0dtvlV59SdYaQ="]},"block":{"signature":"2D489C6D5850B81CA0CFECA379BBD9C1F17E57ECB9654154ED1DA7463E18D250A4D82E4E650A9AE06E9C272E9551D67DF2D57C861927425714B098DC8B6B1402","signer":"8B34A6575D5A5E1C8E6D33BB57B1FBA2936EB602A78E7AA1741AAA2A3D756C62","version":36867,"type":32835,"height":[1,0],"timestamp":[0,0],"difficulty":[276447232,23283],"previousBlockHash":"0000000000000000000000000000000000000000000000000000000000000000","blockTransactionsHash":"F23D95A14B36401F538549BE6B64F415CBF81FF976490D1DB6F955E7D49D61A4"}}
もう数十ブロック程度は生成されているでしょうから、適当に番号を進めてみればそのブロックも取得できます。
これでAPIに対してリクエストが投げられる状態になったので、nem2-cliなりnem2-sdkを使って動作確認や開発を行うことができそうです。
日本語README
日本語READMEも公開されたので、使い方についてはこちらのほうが読みやすいでしょう。
catapult-service-bootstrap/README.ja.md at master · tech-bureau/catapult-service-bootstrap
コメント
上記の動作がdocker-compose up
をするだけでサーバの立ち上がりまで勝手に進みます。
初期ファイルの生成が終わってしまえば、必要に応じてbuild/catapult-config/
以下の*.propertiesファイルを変更して設定を変えてみるなどできます。
もし完全に初期化したい場合は./clean-all
を叩けばここまでに生成されたデータは削除されます。
日本語READMEにも記述があるので参照してみてください。
浅い考察
catapult-serverにはPeer
とAPI
のロールがあり、API
ロールのサーバに対してリクエストを送ります。
Catapultがパブリックnemとして可動するまではまだ相当の時間がかかると思われるので、その頃までには何かしら解決するのかもですが、わざわざAPIノードを整備するためのインセンティブが気になります。
ネットワークを維持するだけならPeerロールとして、nemネットワークに必要なポートの開放等、外部とは最小限の接続にすることでセキュアな構築ができますが、APIロールはそれに加えてRestサーバとの接続にも気を使う必要が出てくるのではないでしょうか。
このあたりもどのようになっていくのか、気になるところです。