2022年3月2日に開催したエンジニア向け勉強会NFTプラットフォームの作り方 ー FanTopの裏側。多くの方にご参加いただいたのですが、残念ながら都合が合わなかったり、後でイベントを知ったという方もいらっしゃるのではないでしょうか。
そうした方々向けに、連載第4弾としてテキスト起こし版を作成しました。スライド資料と合わせてご覧ください。
ブロックチェーン上のデータをサービス用に管理するためのシステム作り
メディアドゥが開発・運営するNFTマーケットプレイス「FanTop」では、パブリックチェーンのデータをサービス上で管理するためのシステムを構築しました。その上で必要となる仕組みや、工夫したポイントをお話します。
登壇者紹介
濱口 賢人 @kent_hamaguchi
2012年にメディアドゥに新卒として入社しました。電子書店向けのシステムの開発と運用を経て、現在はNFTに関する業務を担当しています。
自己紹介
濱口賢人と申します。メディアドゥに入社して10年目の32歳です。4月1日で丸10年になりますので、社歴は長い方かと思います。出身は愛知県名古屋市で、趣味はゲームとプログラムとギターです。中京大学の情報理工学部でコンピュータサイエンスを学んでいました。
新卒でメディアドゥに入り、電子書籍の配信事業や音楽配信に関わってきました。今はNFTのシステム開発に携わっています。
FanTopにおけるWorkerとは
FanTopのスタンスとして、NFTはオンチェーンで単純にデータとして扱います。そして、NFTの保有権や取引履歴はFlowを徹底活用する作りになっています。ただしエンドユーザーの方から見た画面、つまりFanTopのブラウザから見た画面や最近出たスマートフォンアプリにおいては、データを使いやすいように管理、連携する仕組みが必要です。
FanTopの全体の構成はこのようになっています。
まず、オフチェーンでイベントが発生すると、Flowで具体的に何が起きるのかを紐解いていきます。
現在、FanTop上でNFTに関わる代表的な操作は2つあります。1つ目はボックスと呼ばれるアイテムをクレジットカードで購入した際に、NFTを発行する操作です。もう一つはユーザーが保有しているNFTをFanTopがマーケットプレイスに出品して、それを別のユーザーが購入した際に保有権を移動する操作です。
そのためボックスを買う瞬間や出品する瞬間、出品されているものを購入するといったイベントはオフチェーンで発生します。そういったオフチェーンで発生したイベントをWorkerがキャッチして、Flowのコントラクトに対してトランザクションを実行します。
これがFanTopはどのように動いているのかの発表であった、Workerがトランザクションを動かす部分になります。この処理では細かくステータス管理を行っています。ボックスが買われたらFanTopの画面で見られる在庫数をデクリメントしたり、ユーザー視点では購入後のボックス開封準備中、開封できました、といった具合です。
Webアプリケーションの基本的なステータス管理をオフチェーン側で行いつつ、Workerはそれをキャッチして、Flowにトランザクションを発行します。Flowはブロックチェーンなので、ブロックがどんどん積み上がっていきます。Workerはその積み上がったブロックを後追いで吸い上げていって、Mintが完了したといったトランザクションなどをキャッチしたら、それをオフチェーンに書き戻すといった処理をしています。
オフチェーンはサービスの画面に表示しやすい形でアイテムやNFTの情報を保持しています。それに対し、オンチェーンではFlowのデータ形式に従い、ブロックチェーン上にデータが記録されています。オンチェーンに記録されているデータを、オフチェーン向けに変換するのがWorkerの役割です。両方の調整をつけた上で処理する必要があり、実装の背景や内容はある程度複雑なものとなっています。
Workerはシングルトンな常駐バッチプログラムとして作られています。オフチェーンとオンチェーンをどう連携させるのが一番良いのかと考えた結果です。ブロックチェーンではブロックがシーケンシャルに積み上がっていくので、それを追いかけてイベント監視するオブザーバーもシングルトンで良いと考えました。Workerが止まってしまうとFlowのイベントがオフチェーンと連携されなくなり、NFTの取得や売買の結果が、サービスへ更新されなくなるといった問題が発生します。そのため、Workerがエラー等で落ちても、自動で起き上がる仕組みをAWSの機能で実現しています。
ステータス管理もデータが先祖返りしないようにし、Workerが再起動した際にどこまでブロックを取得していて、続きを吸い取れば良いかなどに注意しています。
Workerの仕組み
Workerは単一障害点になり得ますが、Flowのブロックが積み上がる速度や、トランザクションの開始から完了(または失敗)までの確定する時間は何十秒〜1分くらいかかります。そのため、Goのシングルトンで動いているバッチプログラムであれば、充分追いかけられます。エンドユーザーの視点からでは、クレジットカード決済するとMintがはじまり、配布準備が行われます。その間はページをリロードしたり、ブラウザを閉じたとしても同じ画面にアクセスすれば、続きの状態から見られるようなステータス管理を行っています。
そのような形でオフチェーンとオンチェーンの間を取り持っています。仮に、エンドユーザーが出品や購入といったイベントを行う際、通信が途切れないように気をつけていたらユーザーは疲れてしまいます。ユーザー視点でFanTopのUI/UXを高めながら、Flowで発生したイベントを取りこぼさないように全部オフチェーンに反映するのがWorkerの役割です。
ただ、オフチェーン用にデータを管理するのは大変です。ユーザーのマイページで取引履歴を見ると、そのユーザー視点でのトランザクション(どのNFTを獲得したか、販売したかなど)が見られます。つまりFlowのブロックをある意味、特定の項目で横断検索したような形になります。これがオフチェーンでは求められます。しかし、Flowから提供されているGo言語向けのSDKでは、データの単位がFlowイベントになります。これはトークンが発行された、デポジットされたなどの個別のイベントをシンプルに取ることしかできません。そのためGoのプログラムの中で、どのトランザクションか、どのブロックかなどを判別するためにソートをかけたり集約したりしています。
プログラムの中でデータを綺麗にしているので、オフチェーン側でこういったデータが欲しい、画面にこういう情報を出したいといった場合にも対応できます。Flowで発生したイベントを取り扱いやすいように工夫しているので、ビジネスサイドから上がってくる要望にもクイックに対応できると考えています。
2つ目の一連の状態管理が大変ということについてお伝えします。状態としては例えば、買いました・トランザクションをFlowに送りました・実行中です・戻ってきました…などとステップが細かくあります。これを管理するのがなかなか大変でした。これはWorkerというオフチェーンとオンチェーンをつなぐ心臓部があり、これによってFlowで起きたイベントをFanTopの画面でレンダリングしています。また、トランザクションの実行もWorkerへ集約することで、ユーザーの端末やバックエンドサーバーの中で通信障害やエラーがあったとしても、トランザクション完了まで行ってくれる仕組みを入れています。
質疑応答
NFTが楽しいと思うのはどのような点でしょうか?NFTの楽しさを教えてください。
ブロックチェーンやパブリックチェーンはマクロな視点で見れば、データをどういった構造にすれば効率的なのか、改ざんできないのかといった考え方の一つだと思います。ブロックチェーンはデータが前のデータにつながっていて、改ざんを行えないといった特徴があります。そうしたデータソースをいかに画面に反映するかというところが面白いです。
NFTのデータ、コントラクトのアドレスは文字列でしかありません。しかし、それを拾って画面に出すことで、画面をタップしたら見た目に楽しい表示が行われるところが楽しいです。
Workerが落ちたときの復旧について詳しく聞きたいです。
実行環境としてはAWS Fargateでタスク管理をしています。ECSで実行タスクを1つとしておけば、もしインスタンスが落ちたとしても自動的に起き上がるようになっています。これはオーソドックスな方法だと思います。ただ、Workerのバージョンを入れ替える時など、前のバージョンが動作を停止する際にどうしても重複実行が発生します。オペミスも起こるかも知れません。
その結果として、あるWorkerがブロック100〜200までを処理して、別のWorkerが150〜250を処理するといったことはどうしても発生してしまいます。そこでWorkerをシングルトンで動かし、重複実行させないように工夫しています。Workerにはバージョンを立てて、MySQLのロック処理を使ってシングルトンで動くようにしています。
オフチェーンDBにはFlowのキャッシュ・APIサーバーとWorker間のメッセージキューと処理ステータス管理・ログブロック記録という3つの役割があるという認識で正しいですか?
そうですね。キューイングはAmazon SQSがありますが、1つのイベントに対してSQSのイベントが複数発行されることがあります。それを厳密に1つにしようとすると、オンチェーンとオフチェーンの都合も鑑みて、システム設計が複雑化する可能性があります。一例としては、トランザクションがFlow側で失敗した場合には、処理キューとしては終了したけれど、Mintが完了していないといった状態です。そういった細かい制御を行おうとすると、マネージドサービスに乗るよりも、オフチェーンのデータの状態と関連させて、データベースでシンプルに状態管理した方が良いと考えました。そのため、キューの処理はMySQLで管理しています。
NFTを保有していることをオフラインで証明する方法について構想はありますか。
NFTはブロックチェーン上でデジタルアイテムを保有していることを証明する技術になりますので、これは難しい部分かと思います。今はその逆の部分に取り組んでいて、オフラインでNFTをプレゼントしますが、取得するタイミングは任意の時に即時発行する仕組みを提供しています。書店に並んでいる書籍にNFTを付ける「NFTデジタル特典」という取り組みです。これはAmazonギフト券のようなギフトコードになります。NFTデジタル特典はオフラインですが、そのギフトコードをFanTop上で入力してもらって交換ボタンを押した時にオンチェーンへつながる仕組みです。
- ブロックチェーンの選び方 ― 日本初Flowを利用したサービス開発の裏側
- NFTマーケットプレイスのアーキテクチャ設計
- FlowブロックチェーンとCadence言語の実用 ― FanTopの裏側
- ブロックチェーン上のデータを管理する仕組み