この記事はversion bison(0.2.0.2) のものです。その他のバージョンでは正しく動きません
This article is for versin bison (0.2.0.2). Configuration is different in later versions of bison.
2019.7.1 ver 0.5.0.1(elephant)以降は下記Githubリポジトリへ。(セットアップは雑ですが)
https://github.com/mijinc0/catapult-server-build
2019.2.15 ver 0.3.0.1 (cow)でハーベスティング廻りの設定方法が変更になったので下記参照してください。
https://github.com/mijinc0/try_to_start_catapult_cow
2018.11.08 BisonFinalized (pub) version-0.2.0.2 に伴い記事を一部修正しています
NemesisBlock生成時に使うcatapult.tools.nemgen
の引数、オプションを変えました。
概要
Dockerのbridgeネットワークを作り、その中に図で示すようなネットワークを作ることを目標とする。
catapultがビルドされた状態から始めるためのイメージは 44uk さんのものを基にしたものを使わせていただいています。
[Github : 44uk/catapult-server-docker]
https://github.com/44uk/catapult-server-docker
上記のDockerファイルの 98-113
行を消したものを使いました。(ビルド直後の状態にしたかったので)
なお、構成としては tech-bureau/catapult-service-bootstrap
と同じで、こっちのほうが断然使い勝手が良いので、ネットワークが出来た状態から何かしたい場合にはそちらを使うのをおすすめする。
[Github : tech-bureau/catapult-service-bootstrap]
https://github.com/tech-bureau/catapult-service-bootstrap
また、今回はエラー吐かせながらやったために無駄に長い。ビルドした状態からノードを立ち上げたいだけであれば、 planet★箒星 さんの記事を読んで進めるのをおすすめする。
[nem catapult.server 実行]
https://hackmd.io/s/BkpxBlsRz
[Qiitaの方にも色々書いてくれてます]
https://qiita.com/planethouki
1.新規ネットワーク生成
まず、今回使う為のネットワークを作る。
$ sudo docker network create my_catapult_network
確認
$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
1337cecfc3a4 bridge bridge local
65f46a9eacca host host local
9fae70d430b5 my_catapult_network bridge local
2f1080053878 none null local
Driver bridge
のネットワークが出来た。ここに各コンテナを所属させていく。
2.ノード用コンテナの生成
peerノードもAPIノードも元は同じなので、コンテナを先に全て作ってしまう。
$ sudo docker run -i -t --net=my_catapult_network --name cat-peer-1 test-catapult /bin/bash
$ sudo docker run -i -t --net=my_catapult_network --name cat-peer-2 test-catapult /bin/bash
$ sudo docker run -i -t --net=my_catapult_network --name cat-api test-catapult /bin/bash
全てのノードが新規に作成したネットワークに参加していることを確認します。
$ sudo docker network inspect my_catapult_network
[
{
"Name": "my_catapult_network",
<省略>
"Containers": {
"0d611f1d43cd094ddd2f56c60fb86856bfdd2a548473e54cf473ed3480fa4c2c": {
"Name": "cat-api",
"EndpointID": "6cd7db2469bb4774bcb018879680cc20e63d85d055702aa3214d5f7235210b8d",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/16",
"IPv6Address": ""
},
"2f935d0a6388b1d4aab58f9b1269f22c7d1eaa8596b3ac343531734474ce594c": {
"Name": "cat-peer-2",
"EndpointID": "e637218fba42f4e3a6fe3346ccf0443b52098b4e74a2af9612d32c75b59e3850",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
},
"54a75d8123dc3450b615b550af3d431007735adc696a7eccd8c0fdddc1f5e8ab": {
"Name": "cat-peer-1",
"EndpointID": "215a21c2d98e5abebd4a23223ea02731d716e932978323ace9069b153761e19d",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
},
<省略>
ノード用のコンテナが生成されてアドレスが割り振られました。
3.KeyPair/Addressの生成
色々なところで使うことになるので、先に秘密鍵、公開鍵、アドレスのセットを用意しておく。
とりあえず、peer-1用のコンテナに入り、最初の場所を確認しましょう。
peer1:~/_build$ pwd
/tmp/catapult-server/_build
鍵ペアとアドレスのランダム生成は_build/bin
ディレクトリ内にあるcatapult.tools.address
を実行するだけで済む。
peer1:~/_build$ ./bin/catapult.tools.address -g 10 -n mijin-test
Address Tool
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
Address Tool Initializing Logging...
loading configuration from "../resources/config-logging.properties"
--- generating 10 keys ---
private key: 116FE8C4901885065C19B49AB8FA901E907141D380F572F027DA470BD82A2C14
public key: 5096DB3B7D25F49F0D3D1DE73E4C39B7FD556ABA4B1E4D39332C3BC99B97C06D
address (mijin-test): SDZIX4TG7CYGTFPZZOMVMVMOLNUKULIQCLCSBBLB
private key: 70D1774C675DFF45819F4A913742D9E567D4024CD5A3455D279E49792DFCE5E4
public key: F59240141852736BC2A23832833EB2114CE037B0066217E09207DDFEA0E08478
address (mijin-test): SA3DUQXABBXTNFH5SNPHUQM64TQNWIFEG4ZZRUYJ
private key: ADA44598D1809AEC7ECE07FCA45EB3F5128AC8C5E0C9172E53E875888C447984
public key: A62C50240CF8905D759CEF941CB9D2C3F2F00C5D2E6CF72A612B54C7AAAB7E26
address (mijin-test): SBJLWLE7ZKMBJC7K76KS24WYC26JVTLUWM27USNS
private key: 2D8C4D365D6C347B533FEDE8AC6D256F839879D5EFB123251B49F61149216908
public key: AFDCFE113E7820C97C5715DE95F0C43F810643CEFBCB979C78E5F863DBC5372F
address (mijin-test): SBDVJLQWMGJFAKJ56PJAQCRJI3CHK5XYVLN2YHLC
private key: E383335EE7BB765DBE453FE509735D1D5C45C64E0E3950AD1156728203146476
public key: 09AD9530E6B611E609679ABC544C6E5B76F5E0B3A1C956F2E95988B72DD624A5
address (mijin-test): SCSVJOFEQMEPWRPBZ6CTLS7UQKD53TQHYKJS7IBY
private key: E04D404AF24AF83FBAF354A99BF628B3794F6372226C7EC95CC14F4423A7ECE1
public key: 0245B4DDC15136611E4AA2BAC7DE8F826A38A9D448E0D3C7F07BD2DBE614CA8C
address (mijin-test): SB3M5DT2GAKQL4JHNQBWCCGA3B5DYZVKX6FSIJVT
private key: 0D0A06A4EDC28E12683DAD3994404CAD162F6BEE1399511ED57A5F1BB0681C53
public key: D47F30791EDDBDE77CCE413159FFE8E99146383CBE3CD7A450871939DB751B69
address (mijin-test): SACVFLZDUFWGF5XF5GRU4SAE7RJFRTLHPC36ZEZE
private key: E2DA6A70F76D72744D8A93C5A38EA85DC56A889488DC6C8464AB392E812EF5BC
public key: 77825D19F50D389FDD67E78443CF9354F5CA88C2C40A87664918D3C28673013A
address (mijin-test): SCHRC7P5XLH6QJJZDYD4TB77FVXDG63PW7YDPQOV
private key: 53CE6D6D001665FFCC1B56261F757A2BC034F905C0E5958D0D40104A1D20FD08
public key: 550BEC4CFA7159E986CDB5684025D79FF030B93EBDC290F89FAC61152C5ECAE2
address (mijin-test): SBVL2ODBQBI5B6ILHICUWKKW22KELQDP576DFJFA
private key: DF7A6F65FECDF059D1828AC031B67DD81FC49F52FF6AEB8DE9856008BD7CEF7D
public key: FADD0425ED62B3792983D225AEDF2F3F8565353B93E64B336BFC9443583423E6
address (mijin-test): SDHZLOWIKOS563XMF6XGOKDHHBPQGXH7KRCI2BD6
これらは度々使うので何処かに控えておく。
4.peerノードの設定
ここからはpeerノードの設定をしながら起動していく。
4-1.config読み込み
とりあえず何も考えずに_build/bin
ディレクトリ内にあるcatapult.server
を実行してみる。catapult.server
はサーバーの実行コマンド。
peer1:~/_build$ cd bin
peer1:~/bin$ ./catapult.server
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
loading resources from "../resources"
[2018-10-23 04:42:14.700000] [0x00007f6942870740] [fatal] aborting load due to missing configuration file: "../resources/config-network.properties"
unhandled exception while loading configuration!
/tmp/catapult-server/src/catapult/config/ConfigurationFileLoader.h(38): Throw in function TConfiguration catapult::config::LoadConfiguration(const boost::filesystem::path&, TConfigurationLoader) [with TConfigurationLoader = catapult::config::LoadIniConfiguration(const boost::filesystem::path&) [with TConfiguration = catapult::model::BlockChainConfiguration]::<lambda(const auto:2&)>; TConfiguration = catapult::model::BlockChainConfiguration]
Dynamic exception type: boost::exception_detail::clone_impl<catapult::catapult_error<std::runtime_error> >
std::exception::what: aborting load due to missing configuration file
早速エラーが出た。エラーログを読んでみる。文字を追っていくと、なんだか良くわからないけど、最初にloading resources from "../resources"
が見える。つまり、_build/resources
から何かを読み込もうとしている。そして、LoadConfiguration
の実行でエラーを吐いているpath
という文字も見える。一番最後にはaborting load due to missing configuration file
とある。ここでやっと、どうやら_build/resources
の中を読み込んだけどconfigファイルを見つけられなかったようだと分かる。
試しに中身を見てみると、configファイルらしきものがない。
peer1:~/bin$ ls ../resources
CMakeFiles CTestTestfile.cmake Makefile cmake_install.cmake
ということで、resourcesの中身を_build
の上にあるresources
ディレクトリから全部引っ張ってくる。
peer1:~/bin$ cp ../../resources/* ../resources
peer1:~/bin$ ls ../resources
CMakeFiles Makefile config-harvesting.properties config-network.properties config-task.properties peers-api.json
CMakeLists.txt cmake_install.cmake config-logging.properties config-node.properties config-timesync.properties peers-p2p.json
CTestTestfile.cmake config-database.properties config-messaging.properties config-pt.properties config-user.properties
これで良いはず。もう一回catapult.server
を実行してみる。
peer1:~/bin$ ./catapult.server
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
loading resources from "../resources"
loading configuration from "../resources/config-network.properties"
loading configuration from "../resources/config-user.properties"
loading configuration from "../resources/config-logging.properties"
loading configuration from "../resources/config-node.properties"
2018-10-23 05:06:23.481354 0x00007fae5cdcc740: <warning> (io::FileLock.cpp@74) LockOpen failed: 2
2018-10-23 05:06:23.481450 0x00007fae5cdcc740: <fatal> (server::ServerMain.cpp@91) could not acquire instance lock "../data/file.lock"
loading configuration from "../resources/config-network.properties"
が見える。どうやら読み込んでくれたようだ。別のエラー吐いてるけどな。
[ configの読み込み場所について ]
configファイルの読み込場所は、何も設定しなければ../resources
を探しに行く。なので、実はbin
ディレクトリに入らず、_build
ディレクトリ上で./bin/catapult.server
を実行すると、_build
ディレクトリの上のディレクトリにある/tmp/catapult-server/resources
を読み込みに行くので、エラーを吐かない。もし任意のパスにあるresourcesディレクトリからconfigファイルを読ませたい場合は、
catapult.server
に実行時引数としてパスを渡してやれば良い。
例えば、/home/resources
の中にconfigファイルが詰まっているとするなら、~/bin$ ./catapult.server /home
としてやれば良い。一度適当なパスで
catapult.server
を実行してみれば分かると思う。
では、次のエラーを読んでみる。
4-2.ファイルロック
4-1
に戻ってエラーを見てみる。
2018-10-23 05:06:23.481354 0x00007fae5cdcc740: <warning> (io::FileLock.cpp@74) LockOpen failed: 2
2018-10-23 05:06:23.481450 0x00007fae5cdcc740: <fatal> (server::ServerMain.cpp@91) could not acquire instance lock "../data/file.lock"
could not acquire instance lock "../data/file.lock"
とある。インスタンス(サーバー)を起動しようと思ったけどlockが取れませんでしたということらしい。
とりあえずdata
ディレクトリがない。作らないといけない。file.lock
は多分起動時に生成されるやつだろう。
peer1:~/bin$ mkdir ../data
これで再びcatapult.server
実行してみる。
peer1:~/bin$ ./catapult.server
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
loading resources from "../resources"
loading configuration from "../resources/config-network.properties"
loading configuration from "../resources/config-user.properties"
loading configuration from "../resources/config-logging.properties"
loading configuration from "../resources/config-node.properties"
2018-10-23 05:32:17.255633 0x00007f91b6fb6740: <info> (server::ServerMain.cpp@61) booting local node with public key 43EEB17F0BAB10DD51AB70983C25200A1742D31B3B7B54C38C34D7B827B26EED
<省略>
なんか動いた。またすぐエラー吐いて止まったけど。data
ディレクトリを作るだけでよかったみたい。
4-3.Nemesisブロックの生成
ログを見てみると、スレッドプール作ったり、extensionの読み込みをしたり、pluginの読み込みをしていることが分かる。ここは正常に動いているようだが、その次で止まった。エラーログを見てみる。
2018-10-23 05:32:17.604834 0x00007f91b6fb6740: <error> (io::RawFile.cpp@193) couldn't open the file ../data/00000/00001.dat (invalid)
ということで、先程作ったdata
ディレクトリに00000/00001.dat
が無いよということらしい。
ここで、何も分からなければ詰むかも知れないが、この手のファイルはブロックデータが入るファイルだ。NIS1やビットコインコアとかでもそうだったはず。
なので、Nemesisブロックを生成しないといけない。NemesisブロックはBitcoinで言うところのGenesisブロックで、ブロックチェーンの中で一番最初に生成されるブロック。
この生成にはbin
ディレクトリ内にあるcatapult.tools.nemgen
を使う。これにNemesisブロック生成用のconfigファイルを渡してあげればその設定に沿ってNemesisブロックデータを生成してくれる。configファイルは/tmp/catapult-server/tools/nemgen/resources/mijin-test.properties
のを拝借する。
まずは、mijin-test.properties
をコピーする。(resources
ディレクトリに入れる)
peer1:~/bin$ cp /tmp/catapult-server/tools/nemgen/resources/mijin-test.properties ../resources
では、mijin-test.properties
の中身をいくつか抜粋してみてみる。
[nemesis]
[nemesis]
networkIdentifier = mijin-test
nemesisGenerationHash = 57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D6
nemesisSignerPrivateKey = C06B2CC5D7B66900B2493CF68BE10B7AA8690D973B7F0B65D0DAE4F7AA464716
Nemesisブロックの情報を指定する。Nemesisブロックといっても、扱いとしてはあくまでブロックなので、Nemesisブロックに続くブロックと同様GenerationHash
と署名者の署名
が必要になる。それを指定している。これらは後に触るconfig-network.properties
に影響してくる。とりあえず、最初に生成した鍵ペアのものに書き換える。
[nemesis]
networkIdentifier = mijin-test
nemesisGenerationHash = 57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D6
nemesisSignerPrivateKey = 116FE8C4901885065C19B49AB8FA901E907141D380F572F027DA470BD82A2C14
これでNemesisブロックの署名者の秘密鍵が変わりました。この秘密鍵に対する公開鍵はこのcatapultネットワークに参加する全てのノードに共有されないといけないので、控えをなくさないでください。NemesisBlockのGenerationHashは何でも良いけどこれもネットワーク全体で共有されるもの。こっちは書き換えていない。
[output]
[output]
cppFile = ../tests/test/core/mocks/MockMemoryBasedStorage_data.h
binDirectory = ../seed/mijin-test
catapult.tools.nemgen
ので生成されるファイルの出力先を指定する。
cppFile |
---|
test時に使うMockMemoryBasedStorage_data.h を生成先。 空欄であれば生成しない。 |
binDirectory |
---|
nemesisブロックのバイナリファイルの生成先する。 |
cppFile
は私が見た限りだと、テストに使うモックストレージの為のNemesisブロックデータを含むヘッダファイルを生成する模様(テスト時に使う擬似ストレージをメモリ上に作るためのもの)。なので今回は空欄で構わないはず。結果、cppFile
のパスを消して下記のようになります。
[output]
cppFile =
binDirectory = ../seed/mijin-test
ということは、bin
ディレクトリ上でcatapult.tools.nemgen
を実行すると、Nemesisブロックが記録されたバイナリファイルが/tmp/catapult-server/_build/seed/mijin-test
に生成されるということになるはずなので、ディレクトリを生成しておきます。
peer1:~/bin$ mkdir -p ../seed/mijin-test
初期分配アドレス
[output]
以降は、初期分配モザイクとそのアドレスになっている。nem:xem
とeur:euro
をNemesisブロックで生成していることが分かる。xemがないと困るので、初期分配アドレスのいくつかを、事前に生成したアドレスに書き換えておく。
config-network.properties
ブロックチェーンの設定はconfig-network.properties
の書き換えで行う。この設定は、NemesisBlockを生成する時に変更をかける必要がある、
中身を見たら、一番最初の[network]
にNemesisProperties(mijin-test.properties)と似た項目があることが分かる。違いは、privateKeyがpublicKeyになっていることだ。このpublicKeyを、NemesisブロックのprivateKeyに対応するものに変えてあげる。
peer1:~/bin$ vi ../resources/config-network.properties
[network]
identifier = mijin-test
publicKey = B4F12E7C9F6946091E2CB8B6D3A12B50D17CCBBF646386EA27CE2946A7423DCF
generationHash = 57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D6
これが
[network]
identifier = mijin-test
publicKey = 5096DB3B7D25F49F0D3D1DE73E4C39B7FD556ABA4B1E4D39332C3BC99B97C06D
generationHash = 57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D6
こうなる。
これでNemesisブロック生成の準備が出来たので、catapult.tools.nemgen
を実行する。
peer1:~/bin$ ./catapult.tools.nemgen -r .. -p ../resources/mijin-test.properties
[catapult.tools.nemgen のオプション]
-r
: config(.properties)ファイルが詰まったresourcesディレクトリのパス(デフォルトは..
)
-p
: NemesisPropertiesFile(今回だとmijin-test.propertiesファイル)のパスその他のオプションは
-h
のヘルプを参照
ここで、エラーログが吐き出されるはずです。hashes.dat has invalid size (0)
だそう。 そもそもそんなファイル作ってないけどな。 とりあえず中身を見てみます。
peer1:~/bin$ ls ../seed/mijin-test
00000
00000
というディレクトリが生成されている。
peer1:~/bin$ ls ../seed/mijin-test/00000
00001.dat hashes.dat
00001.dat
とhashes.dat
が生成されている。
peer1:~/bin$ xxd ../seed/mijin-test/00000/00001.dat
00000000: 7d10 0000 6229 8db4 bbcb df40 e1e9 0902 }...b).....@....
00000010: 4e1f d91f 37d3 bd97 5136 4548 10ad 61a1 N...7...Q6EH..a.
00000020: 65e6 2a7b 6e58 548a c095 89d8 c672 b97f e.*{nXT......r..
00000030: cf89 6018 a98b 63cd 7732 5d2d a8c0 5918 ..`...c.w2]-..Y.
00000040: 2222 8107 5096 db3b 7d25 f49f 0d3d 1de7 ""..P..;}%...=..
00000050: 3e4c 39b7 fd55 6aba 4b1e 4d39 332c 3bc9 >L9..Uj.K.M93,;.
<省略>
Nemesisブロックのデータは作られている模様(ちゃんと読んでないけど)。
peer1:~/bin$ xxd ../seed/mijin-test/00000/hashes.dat
空のファイル。 まぁ俺作ってないしな
で、調べてみたところ、どうも00000
に入るhashes.dat
は64byte分のデータが中に書かれていないと読み込み時にエラーを吐くらしい。とりあえず64byte分のデータを入れてみる。
peer1:~/bin$ echo -n 0000000000000000000000000000000000000000000000000000000000000000 > ../seed/mijin-test/00000/hashes.dat
これでもう一度catapult.tools.nemgen
をする。
peer1:~/bin$ ./catapult.tools.nemgen ../resources/mijin-test.properties
Nemesis Block Generator Tool
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
Nemesis Block Generator Tool Initializing Logging...
loading configuration from "../resources/config-logging.properties"
2018-10-24 00:30:39.738714 0x00007f4b597cc740: <info> (nemgen::main.cpp@60) loading nemesis configuration from "../resources/mijin-test.properties"
2018-10-24 00:30:39.745981 0x00007f4b597cc740: <info> (nemgen::main.cpp@352) creating binary storage seed in ../seed/mijin-test
2018-10-24 00:30:39.746229 0x00007f4b597cc740: <info> (nemgen::main.cpp@343) nemesis block hash: 9050E352BB5BF321522A7067B78C87C3C3CD5C7C7FBC1C96FAE82F6D73974452
生成できた。hashes.dat
の中身を見てみる。
peer1:~/bin$ xxd ../seed/mijin-test/00000/hashes.dat
00000000: 3030 3030 3030 3030 3030 3030 3030 3030 0000000000000000
00000010: 3030 3030 3030 3030 3030 3030 3030 3030 0000000000000000
00000020: 9050 e352 bb5b f321 522a 7067 b78c 87c3 .P.R.[.!R*pg....
00000030: c3cd 5c7c 7fbc 1c96 fae8 2f6d 7397 4452 ..\|....../ms.DR
後半32byteがNemesisBlockHash
に置き換わっていることがわかったが、コレで正解なのかは現時点では分からない。
とりあえずseed
ディレクトリ内に出来たNemesisブロックのデータをdata
ディレクトリ内に移動する。
peer1:~/bin$ cp ../seed/mijin-test/00000/* ../data/00000
peer1:~/bin$ ls ../data/00000。
00001.dat hashes.dat
これでNemesisブロックを生成できた。ふたたびcatapult.server
を実行してみる。
peer1:~/bin$ ./catapult.server
Copyright (c) Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
catapult version: 0.1.0.2 dc1be9f [master]
loading resources from "../resources"
loading configuration from "../resources/config-network.properties"
loading configuration from "../resources/config-user.properties"
<省略>
動いた。エラーを吐いているが、packet
やsocket
の文字を見れば分かるとおり、今はまだ通信の設定を何もしていないからエラーを吐いたのだと分かる。停止はCtr-c
でインタラプト送ってやれば止まる。
ここから、やっとノードの設定に入る。
4-4.peer1ノードの設定
4-4-1.config-node.properties
resources
ディレクトリ内にあるconfig-node.properties
をいじる。
まずは[node]
を見てみる。
peer1:~/bin$ cat ../resources/config-node.properties
[node]
port = 7900
apiPort = 7901
shouldAllowAddressReuse = false
shouldUseSingleThreadPool = false
shouldUseCacheDatabaseStorage = false
port
,apiPort
はこのままで良いので別に触らなくて良いだろう。
次に[localnode]
を見てみる。
[localnode]
host =
friendlyName =
version = 0
roles = Peer
最後のroles
でpeerノードなのか、apiノードなのか、役割を切り替えられる。peer1
はpeerノードにしたいのでこれもこのままで良いだろう。friendlyName
だけ指定しておく。
[localnode]
host =
friendlyName = Peer1
version = 0
roles = Peer
これでOK。
4-4-2.config-user.properties
次に、config-user.properties
をいじる。まずは中身を見てみる。
peer1:~/bin$ cat ../resources/config-user.properties
[account]
# keys should look like 3485d98efd7eb07adafcfd1a157d89de2796a95e780813c0258af3f5f84ed8cb
bootKey = DF7A6F65FECDF059D1828AC031B67DD81FC49F52FF6AEB8DE9856008BD7CEF7D
[storage]
dataDirectory = ../data
pluginsDirectory = .
bootKey
とは、このノードに結びつく公開鍵に対する秘密鍵だ。全てのノード(正確にはそのインスタンス)は自分自身の公開鍵を持つ。ノードはその公開鍵でお互いを認識する。また、今回は使わないがcatapultノードにはSecurityMode
というモードが存在し、このモードがonになっているとき、ノードは通信するパケットに署名して、確かに自分が送ったものだと証明できる。また、相手から送られてきたパケットに署名がない、相手の公開鍵で署名が検証できないときにはそのパケットを受け付けないという設定が出来る。
このbootKey
に対応する公開鍵は、ノードが他のノードに接続する時に交換し合う。(チャレンジを送って、署名・検証をし合う)
ちなみに、SecurityMode
のON,OFFはconfig-node.properties
で行う。outgoingSecurityMode
とincomingSecurityModes
の項目を変える。
とにかく、bootKey
を事前に作った使ってないアドレスの秘密鍵に変える。
4-4-3.peers-p2p.json
ノードが最初にネットワークにつながるとき、そもそも何処に繋げばよいのかノードは知らない。知るわけがない。一度ネットワークにつながれば、お互いが知っているノードのIPアドレスを交換し合うことで接続候補ノードを増やしていけるが、最初だけは教えてあげないといけない。それはpeers-p2p.json
に記載してあげることで教えてあげられる。
peer1:~/bin$ cat ../resources/peers-p2p.json
{
"_info": "this file contains a list of all trusted peers and can be shared",
"knownPeers": [
{
"publicKey": "0000000000000000000000000000000000000000000000000000000000000000",
"endpoint": {
"host": "127.0.0.1",
"port": 7900
},
"metadata": {
"name": "peernode",
"roles": "Peer"
}
}
]
}
ここで、前項でも言ったが相手のノードを公開鍵でもって認識するので(IPアドレスもだけど)、あいての公開鍵を知る必要がある。これがわからないと接続時のチャレンジが失敗して接続が切られる。peer2
で使う予定の秘密鍵に対する公開鍵をセットしておく。また、IPアドレスはDockerコンテナに割り当てられたアドレスを入れておく。
peer1:~/bin$ cat ../resources/peers-p2p.json
{
"_info": "this file contains a list of all trusted peers and can be shared",
"knownPeers": [
{
"publicKey": "550BEC4CFA7159E986CDB5684025D79FF030B93EBDC290F89FAC61152C5ECAE2",
"endpoint": {
"host": "172.20.0.3",
"port": 7900
},
"metadata": {
"name": "peernode",
"roles": "Peer"
}
}
]
}
ちなみに、peers-api.json
というjsonファイルもあるが、こっちはAPIノード用のようで、peer
ノードはコレを読み込まない。api
ノードの設定の時に使う。
4-4-4.config-harvesting.properties
peer1
には、ハーベスティングもさせたいので、設定をしておく。当然、xemが必要になるので、Nemesisブロックで初期分配を割り当てたアドレスの秘密鍵を使う。
peer1:~/bin$ cat ../resources/config-harvesting.properties
[harvesting]
# keys should look like 3485d98efd7eb07adafcfd1a157d89de2796a95e780813c0258af3f5f84ed8cb
harvestKey =
isAutoHarvestingEnabled = false
maxUnlockedAccounts = 5
これが
peer1:~/bin$ cat ../resources/config-harvesting.properties
[harvesting]
# keys should look like 3485d98efd7eb07adafcfd1a157d89de2796a95e780813c0258af3f5f84ed8cb
harvestKey = 70D1774C675DFF45819F4A913742D9E567D4024CD5A3455D279E49792DFCE5E4
isAutoHarvestingEnabled = true
maxUnlockedAccounts = 5
こうなる。
これで、やっとpeer1
の設定が終わった。次はpeer2
だ。
4-5.peer2ノードの設定
peer2
もpeerノードなので、peer1
のときとやることは変わらない。bootKey
をpeer1
で設定したものに合わせることなど、秘密鍵、公開鍵の設定、peer1
のOPアドレス、公開鍵を教えてあげることが異なるところだ。やり方は全く同じ。Nemesisブロックのデータはpeer1
のものを送ってあげれば楽だし、ハーベスティングの設定はしなくて良い。
ざっと設定を載せます。
config-node.properties
[localnode]
host =
friendlyName = Peer2
version = 0
roles = Peer
config-user.properties
[account]
# keys should look like 3485d98efd7eb07adafcfd1a157d89de2796a95e780813c0258af3f5f84ed8cb
bootKey = 53CE6D6D001665FFCC1B56261F757A2BC034F905C0E5958D0D40104A1D20FD08
[storage]
dataDirectory = ../data
pluginsDirectory = .
peers-p2p.json
{
"_info": "this file contains a list of all trusted peers and can be shared",
"knownPeers": [
{
"publicKey": "FADD0425ED62B3792983D225AEDF2F3F8565353B93E64B336BFC9443583423E6",
"endpoint": {
"host": "172.20.0.2",
"port": 7900
},
"metadata": {
"name": "peernode",
"roles": "Peer"
}
}
]
}
data
ディレクトリの中身、上記で変更した以外のresources
ディレクトリの中にある.properties
ファイルの中身はpeer1
とおなじ。
では、ここでpeer1
とpeer2
をそれぞれ動かしてみましょう。接続ができ、暫く待って、peer1
がハーベスティングに成功して、それをpeer2
が受け取れば成功です。ネットワークを作ることが出来ました。ハーベスティングの成功時には明らかにログの出力が変わってharvesting
の文字が出るので分かるでしょう。
Successfully harvested block at 3 with signer F59240141852736BC2A23832833EB2114CE037B0066217E09207DDFEA0E08478
こんなログが出ます。
失敗する人は、Dockerコンテナに割り当てられたIPアドレス、ポート、相手の公開鍵が相手のbookKeyに対応しているかを確認しましょう。
ここで、一回hashes.dat
の中身を見てみる。ブロックが一つ進んだが、どうなるだろうか。
peer1:~/bin$ xxd ../data/00000/hashes.dat
00000000: 3030 3030 3030 3030 3030 3030 3030 3030 0000000000000000
00000010: 3030 3030 3030 3030 3030 3030 3030 3030 0000000000000000
00000020: 9050 e352 bb5b f321 522a 7067 b78c 87c3 .P.R.[.!R*pg....
00000030: c3cd 5c7c 7fbc 1c96 fae8 2f6d 7397 4452 ..\|....../ms.DR
00000040: b2a8 9493 7a2a eb63 8291 b412 4136 f8c0 ....z*.c....A6..
00000050: 5ce8 899d 297f 67a2 dd55 8ff2 60d7 8438 \...).g..U..`..8
新しいブロックのhashが追加されている。結局一番最初の32byteは何なんだろうか。
4-6.APIノードの設定
最後にAPIノード。Nemesisブロックのデータはpeer2
と同じ状態にする。
で、こうなる。
config-user.properties
[account]
# keys should look like 3485d98efd7eb07adafcfd1a157d89de2796a95e780813c0258af3f5f84ed8cb
bootKey = E2DA6A70F76D72744D8A93C5A38EA85DC56A889488DC6C8464AB392E812EF5BC
[storage]
dataDirectory = ../data
pluginsDirectory = .
次に、api
ノードが最初の状態で知っているノードの情報はpeers-api.json
に書く。peer
ノードの情報を追記する。
peers-api.json
{
"_info": "this file contains a list of api peers",
"knownPeers": [
{
"publicKey": "FADD0425ED62B3792983D225AEDF2F3F8565353B93E64B336BFC9443583423E6",
"endpoint": {
"host": "172.20.0.2",
"port": 7900
},
"metadata": {
"name": "peernode1",
"roles": "Peer"
}
},
{
"publicKey": "550BEC4CFA7159E986CDB5684025D79FF030B93EBDC290F89FAC61152C5ECAE2",
"endpoint": {
"host": "172.20.0.3",
"port": 7900
},
"metadata": {
"name": "peernode2",
"roles": "Peer"
}
}
]
}
これでapi
ノードが立ち上がった時に、peer
ノードに接続をしに行くようになる。
config-node.properties
については、役割をpeer
からapi
に変えてやる必要がある。
まずは[localnode]
の設定。roles
をApi
にしてやる。ついでにfriendlyName
も付ける。
[localnode]
host =
friendlyName = Api
version = 0
roles = Api
次に[extensions]
を変える。# api extensions
にあるものを全てtrue
に、# p2p extensions
にあるものを全てfalse
にする。
[extensions]
# api extensions
# (in order for precomputation to work in all cases when enabled, `addressextraction` must be registered first
# because it precomputes addresses of rolled-back transactions)
extension.addressextraction = true
extension.mongo = true
extension.partialtransaction = true
extension.zeromq = true
# p2p extensions
extension.eventsource = false
extension.harvesting = false
extension.syncsource = false
これで設定はOK。
次に、MongoDB
を入れる。# api extensions
でtrue
にしたものの中に、mongo
がある。APIノードにはmongoDBが必要。
api:~/bin$ apt install mongodb
api:~/bin$ service mongodb start
これで完了。動けばOK、もし、何かしらのエラーを吐いてその中に[connection timeout calling ismaster on '127.0.0.1:27017']
があれば、mongoDBとの接続がうまくいってないせいで動いてないのだと思われる。
mongoDB廻りは各自調べてね。(私がやった時はsystemctlが使えなかった)
なお、一度ランタイムエラーで止まってしまうと、/tmp/catapult-server/_build/data
の中にfile.lock
が残ってしまって次回起動時に起動しなくなる。サーバーを起動する前にfile.lock
を消そう。(エラーを見ればfile.lockが取れなかったから起動できないと出るはず)
5.restサーバーの準備
httpで通信するためにcatapult_rest
サーバーをapi
ノードの動いているコンテナに仕込んで動かします。
rest(api):/$ cd /tmp
// nodejs入れる(バージョンは8 or 9)
rest:/tmp$ git clone https://github.com/creationix/nvm.git /tmp/.nvm
rest:/tmp$ source /tmp/.nvm/nvm.sh
rest:/nvm$ nvm install v8.12.0
rest:/nvm$ nvm use v8.12.0
rest:/nvm$ node -v
v8.12.0
rest:/nvm$ cd /tmp
// yarnを使えるようにする
rest:/tmp$ apt install apt-transport-https
rest:/tmp$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
rest:/tmp$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
rest:/tmp$ apt-get update && apt-get install --no-install-recommends yarn
rest:/tmp$ yarn -v
1.10.1
// restサーバーを入れる
rest:/tmp$ git clone https://github.com/nemtech/catapult-rest.git
rest:/tmp$ cd catapult-rest
rest:/catapult-rest$ ./yarn_setup.sh
rest:/catapult-rest$ cd rest
rest:/rest$ yarn build
正直Nodejs廻りは良く分からない。バージョン8か9のnodejs,yarnが入っていてビルドできればOKだと思う。
restサーバーの設定を行います。api
ノードと通信をするので、api
ノードのIPアドレス、bootKeyに対する公開鍵をセットしてください。下記のようになります。
/home/catapult-rest/rest/resources/rest.json
{
"network": {
"name": "mijinTest",
"description": "catapult development network"
},
"port": 3000,
"crossDomainHttpMethods": ["GET", "POST", "PUT", "OPTIONS"],
"clientPrivateKey": "0D0A06A4EDC28E12683DAD3994404CAD162F6BEE1399511ED57A5F1BB0681C53",
"extensions": ["aggregate", "lock", "multisig", "namespace", "transfer"],
"db": {
"url": "mongodb://172.20.0.4:27017/",
"name": "catapult",
"pageSizeMin": 10,
"pageSizeMax": 100,
"pageSizeStep": 25,
"maxConnectionAttempts": 5,
"baseRetryDelay": 500
},
"apiNode": {
"host": "172.20.0.4",
"port": 7901,
"publicKey": "77825D19F50D389FDD67E78443CF9354F5CA88C2C40A87664918D3C28673013A",
"timeout": 1000
}
<省略>
要するに、restサーバーも一つのノードとして振る舞うので、自身のbootKeyにあたるものと、通信相手の公開鍵を知っておく必要があるということだと思います。
実行は下記の通り。実際にはapiノードも動かさないといけないので、どちらかをバックグラウンドで実行することになる。
rest:/rest$ cd _build
rest:_build$ node index.js
これでrestサーバの準備もOK。後はクライアントを作るだけ。
5.クライアント
ここできたらクライアントになるコンテナを生成して通信を試みます。
host$ sudo docker run -i -t --net=my_catapult_network --name cat-client ubuntu /bin/bash
全てのサーバを起動し、Restサーバに向けてリクエストを送ってみます。
client:/$ curl http://172.20.0.4:3000/block/3
{"meta":{"hash":"C814FEDF49AA2E53E6BCB3190D790B573FF74AAE25C5FF7A8FAC89D02B58EF0F","generationHash":"175B7A8463765189464108B3140936258AAA3D38EE095A2539F91F1ED19C4E7B","totalFee":[0,0],"numTransactions":0},"block":{"signature":"C95F18C42C6F1D5121E26E0211D808B7DB0E11737DAB2123F777BB231BABEF1EB3D54987FC2C5CCD5D09634744CFF27C63E42FCF8DB301FB13FD8345EDCDF40F","signer":"F59240141852736BC2A23832833EB2114CE037B0066217E09207DDFEA0E08478","version":36867,"type":33091,"height":[3,0],"timestamp":[3584828787,18],"difficulty":[3913347072,22118],"previousBlockHash":"B2A894937A2AEB638291B4124136F8C05CE8899D297F67A2DD558FF260D78438","blockTransactionsHash":"0000000000000000000000000000000000000000000000000000000000000000"}}
はい。無事ハーベスディングされたブロックが取れました。
さいごに / よく分かってないところ
- apiノードを止めてもrestサーバは動くので独立している。mongoDBからデータを取っているから問題なく動くとして、apiノードと通信し合う必要性は?(webソケットの為?)
- 結局、hahses.datを作るときの最初の64byteのデータに何を入れるのが正解なのか。
- apiノードがmongoDBにブロック情報を貯めているのであれば、ファイルストレージ(datファイル)の方は不要では...?(mongoDBに何を貯めているのかも分からない)
きれいにまとめてどっかに書く。間違っているところがあればご指摘下さい。
これでオレオレネットワーク作れるね!