🪝

JS Hooksの第一歩

2024/08/05に公開

XRPL Hooks

XRPL Hooksは、分散型のL1ブロックチェーンXRP LedgerのXRP Ledgerプロトコルで利用可能なスマートコントラクト機能です。Hooks機能は現時点ではXRPLと同じXRPLプロトコルベースのネットワークであるXahau Networkでのみ利用可能です。

https://zenn.dev/tequ/articles/xrpl-hooks-starter

XRP LedgerメインネットへのHooks機能統合へも取り組まれており、Hooks機能はXRPLのスマートコントラクト機能として利用可能となることが期待されています。

JS Hooks

これまでHooksはWASMベースで記述されており、ほとんどがCで記述されていました。しかし、C言語は非常に効率的である一方で、多くの開発者にとっては学習コストが高い言語であるため、開発者がHooksを利用する際には学習コストが高いという問題がありました。

しかし、Hooks機能の次の一歩として、JavaScriptエンジンQuickJSを利用しJavaScript/TypeScriptでHooksを記述可能にする機能の開発が進められています。

これはAssemblyScriptではなく、JavaScript/TypeScriptの標準的な構文を利用することが可能であり、Hooksの開発をより簡単にすることが期待されています。

現在はXahau NetworkのJSHookテストネットで利用可能です。

https://jshooks.xahau-test.net/

試してみる

hooks-toolkit-cliを利用することで、簡単にJS Hooksを試してみることができます。

https://www.npmjs.com/package/@transia/hooks-toolkit

準備

CLIツールをインストールします。

npm i -g @transia/hooks-toolkit-cli

インストールしたCLIツールのinitコマンドを使ってプロジェクトを作成します。

jsは利用言語の指定、jshooks-testはプロジェクト名です。

jsの箇所をcとすることで既存のC言語ベースでHooksプロジェクトを作成することも可能です。

hooks-toolkit-cli init js jshooks-test

プロジェクトのディレクトリへ移動します。

cd jshooks-test

依存関係をインストールします

npm i

ここまでの作業が完了しているとcontractsディレクトリにbase.tsというファイルが存在していると思います。
このファイルがHookのエントリーポイントとなります。

import { SUCCESS } from "jshooks-api";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Hook = (arg: number) => {
  trace("Base.c: Called.", 0, false);
  return accept("base: Finished.", SUCCESS);
};

export { Hook };

Hook APIについて

JSHooksを含むHooks機能ではHook APIを利用し、ネットワークの情報を取得したり、Stateを追加/更新/削除、Hook内からトランザクションを送信したりすることが可能です。

Hook APIドキュメント (執筆時点でJSHooks向けのドキュメントはまだ存在しませんが、C言語向けのドキュメントを参考にすることができます。)
https://xrpl-hooks.readme.io/reference

JSHooksのHook APIの型情報はこちらで確認することができます。
https://github.com/Transia-RnD/jshooks-api/blob/main/src/types/global.d.ts

Hook開発

contracts/base.tsファイルを編集し、Hookのロジックを記述します。

今回はシンプルなHookとして、Hookが呼び出されるたびにカウントアップするHookを作成します。

import { assert, encodeString, fallback, SUCCESS } from 'jshooks-api'

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Hook = (arg: number) => {
  trace("Counter: Called.", 0)
  
  const key = encodeString('COUNT')
  const value = fallback(state(key))

  let count: number
  if (value === undefined)
    count = 0
  else
    count = value[0]

  if (count === 0xFF)
    count = 0
  
  trace("Counter: prev", count);
  count++
  trace("Counter: next", count);

  assert(state_set([count], key))

  accept(`Counter: Finished.: ${count}`, SUCCESS)
}

export { Hook }

コードを見ていきましょう

ログの出力

  trace("Counter: Called.", 0);

trace()はHookAPIであり、サーバ上にログを出力します。第一引数にはログメッセージ、第二引数には任意の値を指定します。

Stateの取得

  const key = encodeString('COUNT')
  const value = fallback(state(key))

stateはHookAPIであり引数で指定したキーに対応するStateを取得します。

encodeStringはjshooks-apiライブラリで提供されているヘルパー関数であり、文字列をバイト列にエンコードします。
fallbackも同じくヘルパー関数であり、引数のデータが存在する場合はそのデータを返し、存在しない場合はundefinedを返します。 (引数の結果が-5(DOESNT_EXIST)以外のエラーコードの場合はrollback処理を行い、Hook処理を終了します。)

つまりCOUNTを持つState情報を取得し、valueに格納している処理になります。

Counter処理

  let count: number
  if (value === undefined)
    count = 0
  else
    count = value[0]

  if (count === 0xFF)
    count = 0

  trace("Counter: prev", count);
  count++
  trace("Counter: next", count);

JavaScriptによる基本的な処理です。Stateが存在しなかった場合は0を、存在した場合はStateの値を取得します。
Stateの値が0xFFの場合は0にリセットし、その後カウンターをインクリメントします。

Stateの更新

  assert(state_set([count], key))

  accept(`Counter: Finished.: ${count}`, SUCCESS)

state_setはHookAPIであり、引数で指定した値を指定したキーに対応するStateにセットします。
acceptはHookAPIであり、Hook処理を正常終了します。
assertはjshooks-apiライブラリで提供されているヘルパー関数であり、引数の結果が成功の場合はその値を返し、失敗の場合はrollback処理を行い、Hook処理を終了します。

つまり、更新したカウンターの値をCOUNTというキーでStateにセットし、Hook処理を正常終了する処理になります。

Hookのビルド

次のコマンドでHookをビルドします。

npm run build

実行後buildディレクトリにbase.bcが生成されます。これがHookの実態となるバイナリファイルです。

テストネットでのHookのデプロイ & 実行

次のコマンドでHookをデプロイおよびHookの呼び出しを行います。

npm run deploy

テストネットを利用しているため、10秒程度時間がかかります。

処理が終了すると、次のようなHookの結果が表示されCounterが動作していることがわかると思います。

Counter: Finished.: 1

続けて何度か実行するとCounterがインクリメントされていくことも確認できます。

まとめ

JSHooksはXRP LedgerのHooks機能をJavaScript/TypeScriptで利用可能にすることで、より多くの開発者がHooksを利用しやすくすることを目指しています。

現時点では、JSHooks関連のドキュメントは十分とは言えませんが、Hooks機能の最先端を試してみて、Hooks開発に興味を持つきっかけになればと思います。

XRPL JapanのDiscordサーバがありますので、こちらもぜひご参加ください!
技術的な質問などあれば開発者チャンネルにてお答えします!
https://discord.gg/invite/xrpljapan

私のX/Twitterアカウントはこちら!

Discussion