Hookのトランザクションを読む
Hooksとは
HooksはXRP Ledgerへスマートコントラクト機能を追加するための機能です。
執筆時点ではXRPLのサイドチェーンであるXahau Networkでのみ利用可能ですが、将来的にはXRPL本体でも利用可能になる可能性があります。
Hooksの特徴の1つとして、Hook(コントラクト)専用のコントラクトアカウントが作成されるのではなく、既存のアカウントにHookを追加できる点が挙げられます。
アカウントからのトランザクションの送信や着信に対して、ロジックが実行されるようになります。
また、アカウントのマスターキー(秘密鍵)等を無効化し、ブラックホール化することで、実施的に他チェーンでいうところのコントラクトアカウントとして運用も可能です。
この記事ではHooksを利用したトランザクションの読み方を解説します。
今回はHooksの内部のロジックについては触れません。
コード
Hooksに関連するトランザクションは大きく2つに分けられます。
-
- Hookを呼び出すトランザクション
-
- 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
}
※ 一部のフィールドを省略しています。
いくつかのフィールドが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内で作成されアカウントの署名が行われないためSequence
やSigningPubKey
などのフィールドは特別な値(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
}
※ 一部のフィールドを省略しています。
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チャンネルへ是非お越しください!
日本語チャンネルもありますので、英語ができなくても大丈夫です!
また、XRPL JapanのDiscordサーバもありますので、こちらもぜひご参加ください!
私のX/Twitterアカウントはこちら!
Discussion