XRPL HooksのState機能を試す
XRPレジャー とは
XRPレジャーはBitcoinやEthereumなどと同じ分散型のパブリックブロックチェーンです。ビットコインの初期コントリビュータを含む3人の開発者により2012年に開発され、PoWやPoSとは異なる独自のコンセンサスアルゴリズムが用いられています。
XRPレジャーではトランザクションはプロトコルネイティブであり、開発者が個別にNFTやDEXなどを機能を構築することなく、利用することができます。
Hooks
XRPLを使ったプロダクトの開発者はNFTやDEXなどで用意された多くのパラメータなどを利用することができますが、独自のロジックを実装することは出来ませんでした。
2021年に開発が発表されたXRPレジャーにスマートコントラクト機能を実装するHooksでは、開発者が独自のロジックを実装することが可能となります。
各コントラクトをHookと呼び、その中ではトランザクションを拒否したり、別のトランザクションを送信したり、またはStateを使った状態の管理を行うことが可能です。
Hooksは2023年6月にセキュリティ監査に合格しており、今後Hooks用のサイドチェーンのリリースが予定されています。
State機能
XRPL HooksではEVMをはじめとした他のスマートコントラクトと同様にStateを保持することが可能です。
State情報はレジャー上に公開されているため、他のアカウントなどからの参照が可能となっています。
Stateは同一アカウントの同一ネームスペースのHook内で共有されるため、前述の条件であれば複数のHookからStateの操作を行うことが可能です。
ネームスペース外のHookからStateを操作するためにForeign Stateという機能がありますが、ここでは割愛します。
他のオブジェクトと同様、アカウントに設定したHookがStateを保有するためには準備金が必要となります。
Stateのサイズ
Stateはkey-value
の形式で保存され、key
は32バイト固定、value
はバリデータによるガバナンス投票で決定されます。現在稼働中のHooksテストネットでは128バイトに設定されています。
試してみる
Hooksを触ったことがない場合は、まず以下の記事を読むことをお勧めします。
以降はこの記事と同様にhook-api-examples/starter
ディレクトリ内で作業を行うこととします。
今回は、Stateの追加・削除を試すため、以下のようなHookを作成します
- 送信したXRPの額が奇数の場合、Stateを追加・更新
- 偶数の場合、Stateを削除
以下が作成したHookのコードです。
解説の都合上、100XRP以上のPaymentではロジックは走らないようにしています。
function hook(reserved: i32) {
if (Tx.TransactionType != TransactionType.Payment)
accept("Allowing non-Payment transaction.");
const amount = Tx.Amount;
if (amount.drops > 100000000) {
accept("Allowing over 100XRP Payment.");
}
const accid = Tx.Account.toString();
const xrpAmount = <u8>(amount.drops / 1000000);
let buffer = new ByteArray(1);
buffer[0] = xrpAmount;
let value_view = new ByteView(buffer, 0, buffer.length);
if (xrpAmount % 2 === 1) {
LocalState.setItem(accid, value_view);
} else {
LocalState.removeItem(accid);
}
accept();
}
パートごとに解説します。
ここではPaymentトランザクション以外のトランザクションでは以降の処理を行わずにスキップしたり、100XRP以上の送金の場合にスキップしています。
if (Tx.TransactionType != TransactionType.Payment)
accept("Allowing non-Payment transaction.");
const amount = Tx.Amount;
if (amount.drops > 100000000) {
accept("Allowing over 100XRP Payment.");
}
const accid = Tx.Account.toString;
トランザクション情報に含まれるAmountフィールドがdrop単位であるため、XRP単位に変換しています。
u8型であり0~254までの値を格納できます。
その値をByteView型のオブジェクトへ格納します。
const xrpAmount = <u8>(amount.drops / 1000000);
let buffer = new ByteArray(1);
buffer[0] = xrpAmount;
let value_view = new ByteView(buffer, 0, buffer.length);
XRPの値ごとに処理を分けます。
Hooks向けのAssemblyScriptライブラリではLocalState
を利用しState操作を行うことができます。
- LocalState.getItem(key)
- LocalState.setItem(key,value)
- LocalState.removeItem(key)
LocalState
の内部ではstateファンクションやstate_setファンクションを呼び出しています。
if (xrpAmount % 2 === 1) {
LocalState.setItem(accid, value_view);
} else {
LocalState.removeItem(accid);
}
accept();
実行結果
Stateの作成
21XRPの送金を行った結果、HookStateオブジェクトが作成されました。
keyはアカウントID(rから始まるアドレスではなくバイナリデータ)、valueは21の16進数値である15が設定されています。
Stateの更新
99XRPの送金を行った結果、HookStateオブジェクトが更新されました。
keyを表すHookStateKey
はそのまま、HookStateData
フィールドが更新されています。
別のアカウントからの送金
先ほどとは別のアカウントから送金しました。
送金元アカウントを表すHookStateKey
が異なるStateが新規に作成されました。
Stateの削除
2XRPの送金を行った結果、送金元アカウントに紐づくHookStateオブジェクトが削除されました。
まとめ
スマートコントラクトを使う上でState機能は当然無くてはならないものです。
AssemblyScriptライブラリはまだまだ開発段階であるため、粗い部分も多いですが、今後のアップデートに期待です。
XRPL Labsにより今後Hooksサイドチェーンのローンチも発表されており、このライブラリも整備されていくことでしょう。
興味を持たれた方はXRPL開発者のDiscordチャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
Discussion