FlowのAccess Nodeを構築してみよう(前編)

Takashi Tahara (田原 崇)
29 min readSep 5, 2023

--

※※※※※Advertisement|広告※※※※※

書籍、SvelteとGraphQLでブロックチェーンゲームを作る!が好評発売中です。(URLは以下)

※※※※最新フレームワークでBlockchainアプリ開発ならこの一冊!※※※

Flow Blockchainはデジタルアセットの保管に強みのあるパブリックブロックチェーンです。

通常、ブロックチェーンといえば、Bitcoinのように各ノードがUTXOを計算しながら保持し、その結果として帳簿ができるものを想像されると思いますが、Flow Blockchainは実際にデジタルアセットを保持するストレージが各アカウントごとに430MBが用意されています。

Flow Blockchainの代表的なソフトウェアであるNBA TopShotがブームになった時からGoogle GCPがサポートに回っていた為、豊富なストレージが最初から用意されています。

この記事では実際にAccess Nodeを構築する流れについて解説していきたいと思います。Access Nodeは実際にトランザクションを発行する事ができますので、暗号資産取引所、アナリティクスなどの、Public Access Nodeに対するRateLimitを気にする事なく、頻繁にブロックチェーンとアクセスする必要がある場合などに、Access Node構築が必要となるユースケースがあります。

手順としては

1. ノードIDを発行するスクリプトをダウンロード

2. ノードIDを発行し、それをEpochが終了する前に100FLOWと一緒にステーキング

3. Access Nodeが登録されるスロットは5つしか無いので、1週間に5つまでしかAccess Nodeは追加されません。そのため、ノードIDがスロットに登録されたかを確認します。ノードIDがスロットに登録されていない場合は100FLOWが返却されますが、そのまま次の週のスロット用にステーキングを続ける事もできます。

4. ノードIDがスロットに登録されればあとはノードを動かすだけです。Access NodeのDockerイメージをダウンロードします。

5. Dockerをdocker runで走らせればAccess Nodeとして起動できます。直接Execution Nodeなどにトランザクションを発行する事ができるようになります。

これらの流れの詳細はFlow Blockchain公式が提供しているYoutube(https://www.youtube.com/watch?v=Crm22VzDoZk 2:30ごろから詳しく説明されています。)かまたは、https://developers.flow.com/で知る事ができます。

または、flow developersサイトのAsk AIで以下のように”How to run an Access Node?”と打ち込むとAIが要約を教えてくれたりもします。

出力された内容を上から順にDeepLで翻訳していきますと、以下のようになりました。

How to run an Access Node?
To run a Permissionless Access Node on Flow, you need to follow these steps:

1. Generate the node identity: This includes private and public keys, node ID,
etc.

アクセスノードの実行方法
Flow上でパーミッションレスのアクセスノードを実行するには、以下の手順に従う必要があります:

1. ノードIDを生成する: これには、秘密鍵と公開鍵、ノードIDなどが含まれます。

2. Stake the node: You need to stake the node with 100 FLOW by the end of the 
staking phase of the current epoch. You can do this by providing the node
information generated in step 1. You can register the node on chain by staking
the node via Flow Port. If you are not familiar with Flow Port, you can follow
this guide. If you are staking via a custody provider or would like to directly
submit a staking transaction instead, follow this guide. Fund your Flow account
with at least 100.01 FLOW tokens, which covers the required stake plus the
storage deposit. On Flow port, choose Stake and Delegate -> Start Staking or
Stake Again and then choose Access node as the option. On the next screen,
provide the node details of your node. Those node details (Node ID, Network
Address, Networking Key and Staking Key) can be found in the file:
./bootstrap/public-root-information/node-info.pub.<node-id>.json.

2. ノードをステーキングする: 現在のエポックのステーキング・フェーズが終了するまでに、100FLOWでノードをステーキングする必要があります。これは、ステップ1で生成されたノード情報を提供することで実行できる。Flow Port経由でノードをステーキングすることで、ノードをチェーンに登録できます。Flow Portに詳しくない場合は、このガイドに従ってください。カストディプロバイダー経由でステーキングを行っている場合、または代わりにステーキング取引を直接送信したい場合は、このガイドに従ってください。

Flowアカウントに少なくとも100.01 FLOWトークンを入金します。Flowポートで、ステーキングと委任 -> ステーキング開始または再度ステーキングを選択し、オプションとしてアクセスノードを選択します。次の画面で、自分のノードの詳細を入力します。これらのノードの詳細(ノードID、ネットワークアドレス、ネットワーキング・キー、ステーキング・キー)は、./bootstrap/public-root-information/node-info.pub.<node-id>.jsonというファイルに記載されています。

3. Verify if your node ID was selected: You can verify if your node ID was
selected by the on-chain random selection process on Wednesday at around
20:00 UTC when the next epoch starts.

3. 自分のノードIDが選択されたかどうかを確認する: 次のエポックが始まる水曜日の20:00 UTC(日本時間で朝5時)頃に、自分のノードIDがオンチェーンランダム選択プロセスで選択されたかどうかを確認できます。

4. Start your node: If your node ID was selected, you can provision and start
running the node. If your node wasn't selected, your tokens will have been
refunded to your unstaked bucket in the staking smart contract. When the next
epoch begins, you can try committing tokens again in a future epoch to get a
new spot. The access node can be run as a docker container with the following
command by replacing nodeid with your node ID and adjusting the other
parameters as per your setup.

4. ノードを起動します: あなたのノードIDが選択された場合、ノードのプロビジョニングと実行を開始できます。あなたのノードが選択されなかった場合、あなたのトークンはステーキングスマートコントラクトの未ステーキングバケットに払い戻されます。次のエポックが始まったら、将来のエポックで再度トークンをコミットして、新しいスポットを獲得することができます。アクセスノードは、nodeidをあなたのノードIDに置き換え、他のパラメータをセットアップに従って調整することで、以下のコマンドでdockerコンテナとして実行できます。

docker run --rm \
-v $PWD/bootstrap:/bootstrap:ro \
-v $PWD/data:/data:rw \
--name flow-go \
--network host \
gcr.io/flow-container-registry/access:v0.29.8 \
--nodeid=[Insert you NODE ID here] \
--bootstrapdir=/bootstrap \
--datadir=/data/protocol \
--secretsdir=/data/secrets \
--rpc-addr=0.0.0.0:9000 \
--http-addr=0.0.0.0:8000 \
--rest-addr=0.0.0.0:80 \
--rpc-metrics-enabled=true \
--bind 0.0.0.0:3569 \
--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \
--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \
--dynamic-startup-epoch-phase=EpochPhaseStaking \
--loglevel=error
If you want to run multiple access nodes, you will have to run through these
steps for each node.
For more detailed information, you can refer to the [Flow documentation]
(https://developers.flow.com/concepts/nodes/node-operation


Answer based on the following sources:

複数のアクセスノードを実行する場合は、各ノードに対してこれらの手順を実行する必要があります。
より詳細な情報については、Flow documentationを参照してください。

以下のソースに基づいて回答:

port.onflow.org/ developers.flow.com/concepts developers.flow.com/concepts developers.flow.com/concepts

実際にFlow Blockchain公式が用意したYoutubeやドキュメントを見るよりAsk AIに聞いた方がわかりやすいですね。。

実際にAccessノードを走らせるdocker runの部分は以下サイトを見ながら実行した方が理解が早まると思います。

docker run

新しいコンテナでコマンドを 実行します。

$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

オプション
--add-host ホスト-IP マッピングのカスタム設定を追加します。(ホスト名:ip)
--attach , -a STDIN、STDOUT、STDERR にアタッチします。
--blkio-weight ブロック I/O。(相対的な重みづけ)、10 から 1000、0 は無効化。(デフォルトは 0)
--blkio-weight-device ブロック I/O 重みづけ。(相対的なデバイス重みづけ)
--cap-add Linux ケーパビリティーを追加します。
--cap-drop Linux ケーパビリティーを削除します。
--cgroup-parent 任意に指定するコンテナーの親 cgroup。
--cgroupns cgroup 名前空間(host|private)。 'host': Dockerホストのcgroup名前空間内でコンテナーを起動。 'private': プライベートなcgroup名前空間内でコンテナーを起動。 '': デーモンのdefault-cgroupns-modeオプションによって 設定されるcgroup名前空間を利用(デフォルト)。
--cidfile コンテナー ID をファイルに書き出します。
--cpu-count CPU カウント。(Windows のみ)
--cpu-percent CPU パーセント。(Windows のみ)
--cpu-period CPU の CFS(Completely Fair Scheduler)間隔を制限します。
--cpu-quota CPU の CFS(Completely Fair Scheduler)クォータを制限します。
--cpu-rt-period CPU へのリアルタイムアクセス時間をマイクロ秒で制限します。
--cpu-rt-runtime CPU へのリアルタイムアクセスランタイムをマイクロ秒で制限します。
--cpu-shares , -c CPU 配分。(相対的な重みづけ)
--cpus CPU 数。
--cpuset-cpus 利用を許容する CPU 数。(0-3、0,1)
--cpuset-mems 利用を許容するメモリ数。(0-3、0,1)
--detach , -d コンテナーをバックグラウンド実行し、コンテナー ID を出力します。
--detach-keys コンテナーデタッチ時のキーシーケンスをオーバーライドします。
--device ホストのデバイスをコンテナーに追加します。
--device-cgroup-rule cgroup がアクセス可能なデバイスリストにルールを追加します。
--device-read-bps デバイスからの読み込み割合(秒あたりのバイト数)を制限します。
--device-read-iops デバイスからの読み込み割合(秒あたりの I/O)を制限します。
--device-write-bps デバイスへの書き込み割合(秒あたりのバイト数)を制限します。
--device-write-iops デバイスへの書き込み割合(秒あたりの I/O)を制限します。
--disable-content-trust true イメージの検証を省略します。
--dns カスタム DNS サーバーを設定します。
--dns-opt DNS オプションを設定します。
--dns-option DNS オプションを設定します。
--dns-search カスタム DNS 検索ドメインを設定します。
--domainname コンテナーの NIS ドメイン名。
--entrypoint イメージのデフォルト ENTRYPOINT をオーバーライドします。
--env , -e 環境変数を設定します。
--env-file 環境変数ファイルを読み込みます。
--expose ポートまたはポート範囲を公開します。
--gpus コンテナーに追加する GPU デバイスを指定します。('all' により全 GPU)
--group-add 新たに参加するグループを追加します。
--health-cmd ヘルスチェックを実行するコマンド。
--health-interval ヘルスチェックの実行間隔。(ms|s|m|h) (デフォルトは 0s)
--health-retries 不健康(unhealthy)であると報告するのに必要な連続失敗回数。
--health-start-period ヘルスチェックのリトライを数え始める前の、コンテナー初期化を行う開始時間。(ms|s|m|h) (デフォルトは 0s)
--health-timeout 1 つのチェック処理実行に許容する最大時間。(ms|s|m|h) (デフォルトは 0s)
--help Print usage
--hostname , -h Container host name
--init コンテナー内部にて、シグナル送信と子プロセス管理を行う初期化処理を実行します。
--interactive , -i アタッチされていなくても STDIN は開放し続けます。
--io-maxbandwidth システムデバイスの I/O 帯域幅の上限。(Windows のみ)
--io-maxiops システムデバイスの IOps の上限。(Windows のみ)
--ip IPv4 アドレス。(たとえば 172.30.100.104)
--ip6 IPv6 アドレス。(たとえば 2001:db8::33)
--ipc 利用する IPC モード。
--isolation コンテナーの分離技術(isolation technology)方式。
--kernel-memory カーネルメモリ上限。
--label , -l コンテナーに対してメタデータを設定します。
--label-file 行ごとにラベルが記述されたファイルを読み込みます。
--link 別コンテナーへのリンクを追加します。
--link-local-ip コンテナーの IPv4/IPv6 によるリンクローカルアドレス。
--log-driver コンテナーにおけるログドライバー。
--log-opt ログドライバーオプション。
--mac-address コンテナーの MAC アドレス。(たとえば 92:d0:c6:0a:29:33)
--memory , -m メモリ上限。
--memory-reservation メモリのソフトリミット。
--memory-swap メモリとスワップの総量を制限します。'-1' 設定時はスワップ無制限。
--memory-swappiness -1 コンテナーのスワップ割合を調整します。(0 から 100)
--mount ファイルシステムマウントをコンテナーにアタッチします。
--name コンテナーに名前を割り当てます。
--net コンテナーをネットワークに接続します。
--net-alias ネットワーク範囲内のエイリアスをコンテナーに追加します。
--network コンテナーをネットワークに接続します。
--network-alias ネットワーク範囲内のエイリアスをコンテナーに追加します。
--no-healthcheck コンテナー固有の HEALTHCHECK を無効にします。
--oom-kill-disable OOM キラーを無効にします。
--oom-score-adj ホストの OOM に対する優先順位を設定します。(-1000 から 1000)
--pid 利用する PID 名前空間。
--pids-limit コンテナーの PID 制限を調整します。(-1 により無制限)
--platform サーバーがマルチプラットフォームに対応している場合に、プラットフォームを指定します。
--privileged コンテナーに拡張権限を付与します。
--publish , -p ホストに対してコンテナーのポートを公開します。
--publish-all , -P 公開されたポートをランダムポートとして公開します。
--pull missing イメージ生成前にプルを行います("always"|"missing"|"never")。
--read-only コンテナーのルートファイルシステムを読み込み専用としてマウントします。
--restart no コンテナー終了時に適用する再起動ポリシー。
--rm 終了時に中間コンテナーを自動的に削除します。
--runtime このコンテナー向けに利用するランタイム。
--security-opt セキュリティオプション。
--shm-size /dev/shm のサイズ。
--sig-proxy true 受信シグナルをすべてプロセスにプロキシーします。
--stop-signal SIGTERM コンテナーを停止するシグナル。
--stop-timeout コンテナー停止時の中断時間(秒単位)。
--storage-opt コンテナーにおけるストレージドライバーのオプション。
--sysctl sysctl オプション。
--tmpfs tmpfs ディレクトリのマウント。
--tty , -t 擬似 TTY を割り当てます。
--ulimit ulimit オプション。
--user , -u ユーザー名または UID。(記述書式t: <name|uid>[:<group|gid>])
--userns User namespace to use
--uts 利用する UTS 名前空間。
--volume , -v ボリュームをバインドマウントします。
--volume-driver 任意に指定するボリュームドライバー。
--volumes-from 指定されたコンテナーからボリュームをマウントいます。
--workdir , -w コンテナー内部のワーキングディレクトリ。

このようにdocker runコマンドはdockerコマンドの中でもダントツでオプションが多いので、Access Node起動もオプションが多いのは納得ですね。

Access Node起動時に何を指定しているかというと、上記サイトを参考に解釈すると、

docker run --rm \                  (終了時に中間コンテナーを自動的に削除)
-v $PWD/bootstrap:/bootstrap:ro \ (ボリュームをコンテナにマウントする)
-v $PWD/data:/data:rw \                       (ボリュームをコンテナにマウントする)
--name flow-go \ (コンテナに名前を割り当て)
--network host \ (コンテナを(hostモードで)ネットワークに接続)

gcr.io/flow-container-registry/access:v0.29.8 \
--nodeid=[Insert you NODE ID here] \ (以下は全てdocker公式には存在しないオプション)
--bootstrapdir=/bootstrap \
--datadir=/data/protocol \
--secretsdir=/data/secrets \
--rpc-addr=0.0.0.0:9000 \
--http-addr=0.0.0.0:8000 \
--rest-addr=0.0.0.0:80 \
--rpc-metrics-enabled=true \
--bind 0.0.0.0:3569 \
--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \
--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \
--dynamic-startup-epoch-phase=EpochPhaseStaking \
--loglevel=error

— nodeid以下のオプションは全て公式のdocker runマニュアルに載っていなかったので —network host以降は別の1セットのコマンドだと考えられます。

docker runはimageをコンテナとして起動させるのでimageに対してオプションをつけて起動させているようです。(docker image: gcr.io/flow-container-registry/access:v0.29.8)

gcr.ioとあるので、Google Cloud RegistryにDocker Imageが登録されていると分かります。

Access NodeはGolangで作られているのでGolang Appのoptionとして — nodeidなどのオプション(flag)がついているようです。

Golangで作ったDocker Imageってflagをつけてdocker run出来るんですね。 Pythonでも出来るのでしょうか?知りませんでした。

この場所で — dynamic-startup-access-address flagが正しいかチェックしてありました。

ただ、Golang Appをgcr.ioにpushするにはDockerfileを作成してdocker buildする必要があると思うのですが、GithubのどこにもAccess NodeのDockerfileが無いのですよね。。

ただ、先ほどのdocker公式のコマンド例を見ると、

$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

となっているので、IMAGEの前にoptionsを置く必要があり、

gcr.io/flow-container-registry/access:v0.29.8

以降はdocker runのOPTIONSでは無い、と考えられます。見た感じ、COMMANDでもARGでも無いように見えますが。。

しかもCOMMANDは[COMMAND]となっているので1つしか指定できません。

ということは — nodeidなどはCOMMANDやARGではない、という事になりますね。

やはりdocker run するGolang AppのImageにはflagをつけて実行する事ができる、と考えるべきでしょうか?

“docker run gcr”のキーワードでしばらくGoogleで探してみたところ、GCPのjettyイメージが同じようなコマンドでdocker runされていました。

コマンドはこれです。

docker run gcr.io/google-appengine/jetty --list-config

確かにimageの後にflagをつけてdocker runしていますね。言語はJavaとGoでした。サーブレットコンテナらしいです

更に探したところ、Stack Overflowにやり方が載っていました。

DockerfileのENTRYPOINTに [“python”]などと指定しておくと、docker run IMAGE — vのようにImageの後にFlagをつけてdocker run出来るのだそうです。

ほうほう、そうなのですね。という事は — nodeidなどのoptionはaccess:v0.29.8イメージのENTRYPOINTに対するFlagだったのですね。なるほど。GithubにDockerfileが見つかりませんでしたが、やはりどこかにあるようです。

Golangの場合は以下のようにするそうです。

ENTRYPOINT ["./app"]
CMD ["-flag_name=value"]

Dockerfileにこう記述することで、

docker run -it --rm myapp -flag_name=value

のようにしてFlagをつけてdocker run出来るようです。おぉー。

これはこちらに書かれてありました。最初検索して見つからなかったのはoptionsで検索していたからでした。Flagで検索するとヒットするようになりました。

これでdocker runの謎は解けましたね。良かった..

docker run --rm \                  (終了時に中間コンテナーを自動的に削除)
-v $PWD/bootstrap:/bootstrap:ro \ (ボリュームをコンテナにマウントする)
-v $PWD/data:/data:rw \                       (ボリュームをコンテナにマウントする)
--name flow-go \ (コンテナに名前を割り当て)
--network host \ (コンテナを(hostモードで)ネットワークに接続)
gcr.io/flow-container-registry/access:v0.29.8 \
--nodeid=[Insert you NODE ID here] \ (以下は全てaccess:v0.29.8のENTRYPOINTに対するFlag)
--bootstrapdir=/bootstrap \
--datadir=/data/protocol \
--secretsdir=/data/secrets \
--rpc-addr=0.0.0.0:9000 \
--http-addr=0.0.0.0:8000 \
--rest-addr=0.0.0.0:80 \
--rpc-metrics-enabled=true \
--bind 0.0.0.0:3569 \
--dynamic-startup-access-address=secure.mainnet.nodes.onflow.org:9001 \
--dynamic-startup-access-publickey=28a0d9edd0de3f15866dfe4aea1560c4504fe313fc6ca3f63a63e4f98d0e295144692a58ebe7f7894349198613f65b2d960abf99ec2625e247b1c78ba5bf2eae \
--dynamic-startup-epoch-phase=EpochPhaseStaking \
--loglevel=error

なかなか見ない形なので焦りましたよ…

長くなりましたので前編と後編に分けたいと思います。🙇‍♂️

ブロックチェーンゲーム制作に欠かせないリファレンス本が出版されています。

変数の型、Struct、配列、リソースなど全てのオブジェクトのメソッドを網羅しています。GraphQLを使用してブロックチェーンとの通信をするdApp開発の内容を収録しています。

このリファレンスを用いて開発されたブロックチェーンゲームはこちら(*•̀ᴗ•́*)و ̑̑

このゲーム、なんと全てのロジックがブロックチェーン上で動いているんです。

対戦カードゲームですが、全部スマートコントラクトを介して処理されているんですよ。

スマートコントラクトの全長は2450行にも及びます。

※ゲーム自体のソースコードはこちら -> https://github.com/temt-ceo/CODE-of-flow

Flutterアプリ内でブロックチェーンのウォレットを呼び出す方法や、iPhone/Androidアプリ内からトランザクションを発行する手段サーバーサイドからトランザクションを発行する方法などをまとめています。

Jacob君の許可を頂いて、Jacob君の動画のエッセンスを詰め込んだリファレンス本がなんとたったの3,000円(税抜)

--

--

Takashi Tahara (田原 崇)

Programmer, Blockchain engineer, AI Engineer, and Front-end Engineer ( I have several certifications of Cisco, IBM, AWS, Google Cloud, C++, Go, Rust and more.)