🪝

Hookのトランザクションを読む

2023/11/28に公開

Hooksとは

HooksはXRP Ledgerへスマートコントラクト機能を追加するための機能です。

https://hooks.xrpl.org

執筆時点ではXRPLのサイドチェーンであるXahau Networkでのみ利用可能ですが、将来的にはXRPL本体でも利用可能になる可能性があります。

https://xahau.network

Hooksの特徴の1つとして、Hook(コントラクト)専用のコントラクトアカウントが作成されるのではなく、既存のアカウントにHookを追加できる点が挙げられます。

アカウントからのトランザクションの送信や着信に対して、ロジックが実行されるようになります。

また、アカウントのマスターキー(秘密鍵)等を無効化し、ブラックホール化することで、実施的に他チェーンでいうところのコントラクトアカウントとして運用も可能です。

この記事ではHooksを利用したトランザクションの読み方を解説します。

今回はHooksの内部のロジックについては触れません。

コード

Hooksに関連するトランザクションは大きく2つに分けられます。

    1. Hookを呼び出すトランザクション
    1. Hookの中から作成されるトランザクション

「1. Hookを呼び出すトランザクション」はこれまでと同じように任意のトランザクションを利用し、送信元アカウントや送信先アカウントがHookを実行することになります。

「2. Hookの中から作成されるトランザクション」はHookの中で作成されるトランザクションです。ユーザが直接作成できず、Hookのロジック内のみで作成されます。

1. Hookを呼び出すトランザクション

ユーザによって作成されHookを呼び出したトランザクションは次のような情報を持ちます。基本的な情報はHookを呼び出さなかった場合と同じです。

{
    "Account": "rJeoxs1fZW78sMeamwJ27CVcXZNpQZR3t",
    "Destination": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
    "Fee": "100000",
    "HookParameters": [
        {
            "HookParameter": {
                "HookParameterName": "4C",
                "HookParameterValue": "01"
            }
        },
        {
            "HookParameter": {
                "HookParameterName": "54",
                "HookParameterValue": "4800"
            }
        },
        {
            "HookParameter": {
                "HookParameterName": "56",
                "HookParameterValue": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77"
            }
        }
    ],
    "LastLedgerSequence": 8501168,
    "NetworkID": 21338,
    "Sequence": 6869599,
    "SigningPubKey": "03048847C30C92A1FF1E85B19468F6A3960090C06A2DB6E9464185F632E7F22DD5",
    "SourceTag": 42697468,
    "TransactionType": "Invoke",
    "TxnSignature": "30440220543F534D447B5EBED2D602172601665060C3CE72B3FA667394FE255A539EF7BB02201CBB4BCC9BC2C60B740B3B39B1E440D35A154DC2B013CC2667DAEB1B46462E43",
    "ctid": "C081B7AC0000535A",
    "date": 753888941,
    "hash": "15D6F4C4155B2F758906E1A75093A752BB11023E7A380DEF517CF4114698F68D",
    "inLedger": 8501164,
    "ledger_index": 8501164,
    "meta": {
        "AffectedNodes": [
            {
                "ModifiedNode": {
                    "FinalFields": {
                        "Flags": 0,
                        "Owner": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
                        "RootIndex": "8F3A8E8C89C6E7726BA3D4D6336783B6B14781E4B2DC19868721D1753F899A35"
                    },
                    "LedgerEntryType": "DirectoryNode",
                    "LedgerIndex": "0B01EB6FE5486993AC031694CD5685B79A0E361A3C9214065C51A1B1EEAC1A6D"
                }
            },
            ...
        ],
        "HookExecutions": [
            {
                "HookExecution": {
                    "HookAccount": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
                    "HookEmitCount": 1,
                    "HookExecutionIndex": 0,
                    "HookHash": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77",
                    "HookInstructionCount": "2e9",
                    "HookResult": 3,
                    "HookReturnCode": "1d6",
                    "HookReturnString": "476F7665726E616E63653A205375636365737366756C6C7920656D6974746564204C3120766F74652E00",
                    "HookStateChangeCount": 4
                }
            }
        ],
        "TransactionIndex": 0,
        "TransactionResult": "tesSUCCESS"
    },
    "validated": true
}

※ 一部のフィールドを省略しています。
https://test.xahauexplorer.com/explorer/15D6F4C4155B2F758906E1A75093A752BB11023E7A380DEF517CF4114698F68D

いくつかのフィールドがHooks向けに存在しています。

HookParameters

Hookに情報を渡すことができるフィールドです。このフィールドを利用しHook内で条件分岐したり、情報をStateへ保存することが可能になります。

    "HookParameters": [
        {
            "HookParameter": {
                "HookParameterName": "4C",
                "HookParameterValue": "01"
            }
        },
        {
            "HookParameter": {
                "HookParameterName": "54",
                "HookParameterValue": "4800"
            }
        },
        {
            "HookParameter": {
                "HookParameterName": "56",
                "HookParameterValue": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77"
            }
        }
    ],

HookParameterNameはそれぞれ最大32バイト、HookParameterValueはそれぞれ最大128バイトまでのデータを設定することができます。

HookParametersフィールドのデータ量に応じて必要となるトランザクション手数料も増加します。

16進数値のみが利用可能ですが、Hooksのロジック内では自由に扱うことができます。

meta.HookExecutions

トランザクションがネットワークに取り込まれ成功した場合に自動で挿入されるフィールドです。
そのトランザクションで実行したHookに関する情報が格納されています。

        "HookExecutions": [
            {
                "HookExecution": {
                    "HookAccount": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
                    "HookEmitCount": 1,
                    "HookExecutionIndex": 0,
                    "HookHash": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77",
                    "HookInstructionCount": "2e9",
                    "HookResult": 3,
                    "HookReturnCode": "1d6",
                    "HookReturnString": "476F7665726E616E63653A205375636365737366756C6C7920656D6974746564204C3120766F74652E00",
                    "HookStateChangeCount": 4
                }
            }
        ],

今回の例ではHookExecutionは1つですが、トランザクションで2つ以上のHookを呼び出した場合は、その数分のHookExecutionが格納されます。

HookHashが呼び出したHookのハッシュ値を表します。最も利用するであろうフィールドはHookReturnStringです。Hookの処理に成功した場合、ロジック内から返された文字列が16進数値で格納され、どのような結果で成功したかなどを確認できます。

2. Hookの中から作成されるトランザクション

Hook内で作成されたトランザクションも大きくは他のトランザクションと同様です。
Hook内で作成されアカウントの署名が行われないためSequenceSigningPubKeyなどのフィールドは特別な値(0や"")が設定されています。

{
    "Account": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
    "Destination": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
    "EmitDetails": {
        "EmitBurden": "1",
        "EmitGeneration": 1,
        "EmitHookHash": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77",
        "EmitNonce": "D8C06A0518AF8D2926CEFE7DB12EA28155B3C26A32CF2D6E4CE734AC1F8EAE89",
        "EmitParentTxnID": "2FA146568CA9A08C955269061F91AF7068DD8F0B8A598AA5B1D8F743EA64779C"
    },
    "Fee": "9613",
    "FirstLedgerSequence": 8501164,
    "Flags": 2147483648,
    "HookParameters": [
        {
            "HookParameter": {
                "HookParameterName": "54",
                "HookParameterValue": "4800"
            }
        },
        {
            "HookParameter": {
                "HookParameterName": "56",
                "HookParameterValue": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77"
            }
        }
    ],
    "LastLedgerSequence": 8501168,
    "Sequence": 0,
    "SigningPubKey": "",
    "TransactionType": "Invoke",
    "ctid": "C081B7AC0001535A",
    "date": 753888941,
    "hash": "9042A99824A4996A753C323DEB788DAEA7E0AC9BB5F40314438D2E4569374464",
    "inLedger": 8501164,
    "ledger_index": 8501164,
    "meta": {
        "AffectedNodes": [
            {
                "ModifiedNode": {
                    "FinalFields": {
                        "Account": "rGsa7f4arJ8JE9ok9LCht6jCu5xBKUKVMq",
                        "AccountIndex": "4",
                        "Balance": "19907777840",
                        "Flags": 65536,
                        "HookNamespaces": [
                            "0000000000000000000000000000000000000000000000000000000000000000"
                        ],
                        "HookStateCount": 58,
                        "OwnerCount": 59,
                        "RegularKey": "rUQkAeEyGcN3XmyWQUzt5khxJF5cgxSuet",
                        "Sequence": 6869562
                    },
                    "LedgerEntryType": "AccountRoot",
                    "LedgerIndex": "B261E79ED0041BA6DC968F61675BEEFA144206C1807D5AE6F3545F1413ECE20D",
                    "PreviousFields": {
                        "Balance": "19907787453"
                    }
                }
            },
            ...
        ],
        "HookExecutions": [
            {
                "HookExecution": {
                    "HookAccount": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
                    "HookEmitCount": 0,
                    "HookExecutionIndex": 0,
                    "HookHash": "78CA3F5BD3D4F7B32A6BEBB3844380A9345C9BA496EFEB30314BDDF405D7B4B3",
                    "HookInstructionCount": "155",
                    "HookResult": 3,
                    "HookReturnCode": "13b",
                    "HookReturnString": "476F7665726E616E63653A20596F757220766F746520697320616C7265616479206361737420746869732077617920666F72207468697320746F7069632E00",
                    "HookStateChangeCount": 2
                }
            }
        ],
        "TransactionIndex": 1,
        "TransactionResult": "tesSUCCESS"
    },
    "validated": true
}

※ 一部のフィールドを省略しています。
https://test.xahauexplorer.com/explorer/9042A99824A4996A753C323DEB788DAEA7E0AC9BB5F40314438D2E4569374464

EmitDetails

このトランザクションの作成元となったトランザクションやHookの情報が格納されています。

    "EmitDetails": {
        "EmitBurden": "1",
        "EmitGeneration": 1,
        "EmitHookHash": "5EDF6439C47C423EAC99C1061EE2A0CE6A24A58C8E8A66E4B3AF91D76772DC77",
        "EmitNonce": "D8C06A0518AF8D2926CEFE7DB12EA28155B3C26A32CF2D6E4CE734AC1F8EAE89",
        "EmitParentTxnID": "2FA146568CA9A08C955269061F91AF7068DD8F0B8A598AA5B1D8F743EA64779C"
    },

EmitGenerationは作成元のHookによって作成されたトランザクション数、EmitHookHashは作成元のHookのハッシュ値、EmitParentTxnIDは作成元のトランザクションのIDを表します。

その他

HookParameters: Hook内部から他アカウントのHookを呼び出すことも可能であるため、HookParametersを利用できます。
meta.HookExecutions: Hook内部から他アカウントのHookを呼び出すことも可能であるため、同じようにmeta.HookExecutionsを利用ができます。

まとめ

Hookに渡すパラメータや実行結果、他のトランザクションとの関連性など、Hooksのトランザクションには他のトランザクションにはない情報が含まれています。

これらの情報を理解し、Hooksを利用したトランザクションを読むことで、より深くHooksのロジックを理解できるようになるでしょう。

興味を持たれた方はXRP Ledger開発者のDiscordチャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
https://xrpldevs.org

また、XRPL JapanのDiscordサーバもありますので、こちらもぜひご参加ください!
https://discord.gg/invite/xrpljapan

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

Discussion