見出し画像

テクニカルノート:Sei LabsのエンジニアがIBCインデックスの不一致を発見

この記事は、Seiのブログ「Technical Note: Sei Labs Engineers Discover IBC Indexing Discrepancy」(2023年11月22日付)の日本語訳です。もし記事内に不自然が表現を感じられる場合、併せて原文を確認することをお勧めします。本記事では、"Sei"はプロジェクト及びブロックチェーンの名前を指し、"SEI"はSeiにおけるトークンを指します。


今後の技術ブログ記事、製品ニュース、開発者向けイニシアチブに関するお知らせをご希望の方は、開発者向けメーリングリストにご登録ください。

Inter-Blockchain Communication(IBC)プロトコルは、独立したブロックチェーン間の安全でシームレスな通信を促進し、トークンやデータの相互転送を可能にするために設計された画期的なフレームワークです。IBCは複雑で難しい技術です。

過去数ヶ月の間に、Sei Labsのエンジニアリングチームは、いくつかのサードパーティーのサービス上で、Seiブロックチェーン上のOSMOトークンの総流入量と総流出量の間に不一致があることを確認しました。Sei Labsチームが行った調査と根本原因分析により、この問題の原因と思われるものが特定されました。この不一致は、これらのサードパーティ・サービスがどのようにインデックスを作成し、データを解釈しているかに起因しています。不一致は、これらのサードパーティサービスがデータをインデックスし、解釈する方法によるものです。

この投稿では、この問題がどのように発見され、調査され、2つの潜在的な解決策が提示されたかを詳しく説明します。

NB Flipside Cryptoのチームは、調査後にこの問題を知らされました。彼らの協力とサポートに感謝しています。

発見

この問題は当初、ローンチの2日目からOSMOの総流入額が総流出額を下回っているように見えるFlipsideのレポートによって明らかになりました。トークンは取引されるために投入されなければならず、したがって総流入量は総流出量と等しいか、それ以上でなければなりません。このようなことが起こり得るのは、SeiとOsmosis双方のIBCロジックにバグがある場合です。

Sei Labsのエンジニアリング・チームがMintscanでチェックしたところ、同じような、しかし明確な結果が出ました。相違点は以下の通りでした:

  • Mintscan: ローンチ以来、さらに4,917,796のOSMOの流出がありました。

  • Flipside: ローンチ以来、さらに3,219,878のOSMOの流出がありました。

これらのずれの原因を特定するため、Sei LabsのエンジニアはSeiメインネットのローンチ後数日間のデータを再インデックス化しました。その結果、流入と流出の合計が一致していることが確認されました:

(Net_Inflow_18520000_to_19300000 - Net_Outflow_18520000_to_19300000) + Bank Supply of IBC Uosmo on height 18520000 = total supply of uosmo at height 19300000.

In this equation: Net_Inflow_18520000_to_19300000 = 289607886926903
Net_Outflow_18520000_to_19300000 = 288034713858306 
Bank Supply of IBC Uosmo on height 18520000 = 20685000 
Bank supply of uosmo at height 19300000 = 1573193753597

調査

Sei Labsのエンジニアは、2つの異なるサードパーティーのデータプロバイダーで、流入と流出の合計がずれているように見える問題を発見し、根本原因の分析を行いました。

オンチェーンの合計が期待通りに正しく一致していることを確認した後、サードパーティサービスがIBCデータをどのようにインデックス化しているかに注目しました。Flipsideは自社のデータモデルをGitHubでオープンソース化しており、これは手始めとして良い場所でした。

Flipsideのデータモデルは、ブロックチェーン上の'ibc_transfer'イベントを観測することでIBCの流出量を計算し、'write_acknowledgement'msgと'packet_data'属性を観測することでIBCの流入量を計算しました。

IBC転送の成功例を見てみましょう:

図1:チェーンAからチェーンBへのネイティブトークン(例:Seiのusei)のIBC転送
  1. チェーンA(ソースチェーン)でのパケット生成:

    1. チェーンAのユーザがチェーンBへのトークン転送を開始します。

    2. このアクションにより、トークン転送を示すIBCパケットがチェーンA 上に作成されます。チェーンAのトークンはIBCエスクローアカウントに保管され、二重使用されることはありません。例えば、osmo<>seiチャネルのエスクローアカウントはaxelar<>seiチャネルのものとは異なります。

    3. トランザクション#1:チェーンAで送金を開始するための1トランザクションを実行します。

  2. パケットをチェーンBに中継:

    1. チェーンA上の新しいパケットを検知したリレイヤーがチェーンBにトランザクションを送信し、パケットデータを中継します。

    2. トランザクション#2: チェーンBでパケットを受信するための1トランザクションを実行します。

  3. チェーンB(宛先チェーン)でパケット処理:

    1. チェーンBはパケットを処理し、チェーンB上で意図した受信者に相当するトークンをミントし、確認応答を生成します。

  4. 確認応答をチェーンAに中継:

    1. リレイヤーがチェーンB上の確認応答に気づき、この確認応答を中継するためにチェーンAにトランザクションを送信します。

    2. トランザクション#3:チェーンAで確認応答を処理するための1トランザクションを実行します。

では、すべてのibc_transferメッセージが記録され、すべてのトランザクションが上記のように進めば、合計が一致するということでしょうか?理論的にはそうです。

実際には、タイムアウトという問題があります。IBCの転送にはタイムアウトパラメーターがあり、ブロック高、タイムスタンプ、場合によってはその両方が指定されます。この時間またはブロック高が過ぎると、IBCパケットはタイムアウトとみなされます。

図2:タイムアウトによるチェーンAからチェーンBへのIBC転送の失敗

リレイヤーがタイムアウトしたIBCパケットをチェーンBのIBCモジュールに中継しようとすると、そのモジュールはタイムアウトエラーを返します。リレイヤーはチェーンAの送信モジュールにパケットがタイムアウトしたことを通知します(TimeoutPacketを使用)。転送されるはずだったトークンは転送イニシエーターに送り返され、IBC転送は失敗しました。

IBC転送トランザクションのライフサイクルをご覧になり、タイミングアウトによって転送が失敗することがあることをお分かりいただけたと思います。Sei Labsのエンジニアリングチームは、Seiブロックチェーンのローンチ後の数日間のトランザクションデータを振り返りました。確かに、IBCのアウトバウンド転送がタイムアウトするケースが頻繁にありました。

サードパーティのデータインデクサーは、その転送がその後タイムアウトした場合でも、IBCの流出のためにすべての ibc_transfer イベントをカウントしていました。したがって、これらのデータプロバイダーが計算したIBCの総流出量は、成功したIBC移送だけでなく、タイムアウトしたものも含んでいます。こうして、IBCの流出量が流入量を上回りました。

提案した解決策

Sei Labs エンジニアリングチームは、IBC転送イベントを処理して流入/流出の数量を得る代わりに、IBCモジュールアカウントから流入または流出した非ネイティブトークンの合計額をカウントすることを提案しています。

彼らは、このアプローチで金額を解析するために、以下のコードスニペットを提供しました。

// IBC Transactions: Check tx event for event type 'transfer' between ibc-transfer module account and sei account
// Example: {"type":"transfer","attributes":
// [{"key":"recipient","value":"sei1z3g0ccd0gpe6m4afjjmtxka269yyrymhwwvf3x"},
//   {"key":"sender","value":"sei1yl6hdjhmkf37639730gffanpzndzdpmhrn8l3z"}, 
// {"key":"amount","value":"7898600ibc/2CC0B1B7A981ACC748547..."}]}
func ParseBridgeTx(txResponse *sdktypes.TxResponse, chainId string, msgTypes []string) ([]types.RawBridgeTx, error) {

	// txResponse here is the result the same as `seid q txs --events`
	for _, log := range txResponse.Logs {
		for _, event := range log.Events {
...
			if event.Type != transferEventType {
				continue
			}
...
			amountCoins, err := sdktypes.ParseCoinsNormalized(amount)
			for _, amountCoin := range amountCoins {

				// Case: IBC Transfer Bridge In or IBC Timeout Refund
				if sender == IBCTransferModuleAccount {
					bridgeUserAddress = recipient
					bridgeAddress = sender
					bridgeTxType = IBCTransferBridgeInType
				}

				// Case: IBC Transfer Bridge Out
				if recipient == IBCTransferModuleAccount {
					bridgeUserAddress = sender
					bridgeAddress = recipient
					bridgeTxType = IBCTransferBridgeOutType
				}
...
			}
		}
	}

ソースチェーン上のネイティブトークンの流入量と流出量のインデックスは、非ネイティブトークンのインデックスと同じアプローチで機能します。ここでの唯一のわずかな違いは、IBCモジュールアカウントからの送信情報をカウントするのではなく、チャネル特定のIBCエスクローアカウントからカウントすることです。

まとめ

本レポートを通じて、私たちはInter-Blockchain Communication(IBC)プロトコルの複雑なニュアンスと、その複雑なインフローとアウトフローのインデックス作成処理を解明してきました。

Flipsideのダッシュボードで観察された不一致で明らかなように、インデックス作成における不具合は、コミュニティ内の誤解を招きかねません。IBCを使用する際には、特にネットワークが混雑している時や、パケットタイムアウトのような予期せぬシナリオに遭遇した時など、細心の注意が必要であることを関係者全員が認識することが不可欠です。

Sei Labsエンジニアリングチームは、忍耐と信頼に対するコミュニティメンバーとステークホルダーの皆様に感謝の意を表したいと思います。当チームは、当チェーン上のすべてのIBC取引の透明性、正確性、および効率性を確保するために十分な設備を整え、全力を尽くしています。私たちは、信頼を育み、IBCエコシステムの完全性を維持するための献身に揺るぎはありません。

今後の技術ブログ記事、製品ニュース、開発者向けイニシアチブに関する通知をご希望の方は、以下のフォームを使用して開発者向けメーリングリストにご登録ください。

この記事が気に入ったらサポートをしてみませんか?