XRP LEDGERのトランザクションのファイナリティ
XRP LEDGERのトランザクションのファイナリティについて理解しましょう!
初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
ERCについてひたすらまとめたり、スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
https://twitter.com/cardene777
https://chaldene.net/
https://qiita.com/cardene
https://zenn.dev/heku
https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58
https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
また、これからも情報を見逃したくないという方はぜひ以下の購読ボタンを教えてください。
更新があった時、登録しているメールアドレス宛に通知が飛ぶようになります。
今回はXRP LEDGERについての第7回の記事になります。
第1回~第6回の記事は以下になります。
https://cardene.substack.com/p/xrp-ledger-introduction
https://cardene.substack.com/p/xrp-ledger-usecase
https://cardene.substack.com/p/xrp-ledger-concept-network
https://cardene.substack.com/p/xrp-ledger-consensus
https://cardene.substack.com/p/xrp-ledger-ledger
https://cardene.substack.com/p/xrp-ledger-transaction
XRP LEDGERのコンセプトの1つである「トランザクションの確定」についてまとめていきます。
この記事は以下の公式ドキュメントを参考にまとめていきます。
https://xrpl.org/docs/concepts/
トランザクションのファイナリティ
XRP Ledgerにおいて、トランザクションの最終的な結果は、そのトランザクションがコンセンサスプロセスによって承認され、検証済みレジャーに含まれるまで確定しません。
トランザクションの結果が最終的なものかどうかは、結果コードによって判断できます。
結果コード
tesSUCCESS検証済みレジャーに含まれる場合は確定。
すべての
tecコード検証済みレジャーに含まれる場合は確定。
すべての
temコード確定(トランザクションが有効になるようにプロトコルが変更される場合を除く)。
tefPAST_SEQ検証済みレジャーに同じシーケンス番号の別のトランザクションが含まれている場合は確定。
tefMAX_LEDGER検証済みレジャーにトランザクションの
LastLedgerSequenceフィールドよりも大きいレジャーインデックスがあり、検証済みレジャーにそのトランザクションが含まれていない場合は確定。
未確定の結果が変更される理由
XRP Ledgerでは、トランザクションの最終結果は暫定的な結果と異なる場合があります。
理由は以下の通りです。
トランザクションが延期されたり、検証済みレジャーに取り込まれない場合がある。
関連するトランザクションの適用順序により、暫定的に成功したトランザクションが失敗したり、その逆もあり得る。
XRP Ledgerに対してテストを行う時は、同じデータに影響する複数のアカウントがある場合、トランザクション間のレジャーが閉じられるまで待つ必要があります。
スタンドアロンモードのサーバでは、レジャーを手動で閉じる必要があります。
トランザクションの結果の確認
XRP Ledgerでは、トランザクションが成功したかどうか、何を実行したか、失敗した場合の理由を把握することが重要です。
XRP Ledgerは共有システムであり、すべてのデータが公開された形で正確に記録され、新しいレジャーバージョンで安全に更新されます。
誰でも任意のトランザクションの結果を確認し、トランザクションメタデータによってその実行内容を確認できます。
トランザクションの結果を調査するために以下の条件が必要です。
調べるトランザクションを特定できる(トランザクションの識別用ハッシュなど)。
信頼できる情報と必要な履歴を提供する
rippledサーバにアクセスできる。
最近送信したトランザクションの結果を確認する場合は、トランザクションの送信時に使用したサーバがネットワークと同期されていれば十分です。
古いトランザクションの結果については、全履歴を記録するサーバを使用する必要があります。
トランザクションステータスの取得
トランザクションが成功したか失敗したかを確認するには、以下の2つの確認が必要です。
トランザクションが検証済みレジャーに記録されているか。
記録されていた場合、結果としてレジャーの状態はどのように変化したのか。
検証済みレジャーにトランザクションが記録されているかを確認するには、txメソッド、account_txメソッドなどを使用し、"validated": trueを検索します。
結果に
"validated": trueがない場合、結果は一時的である可能性があります。結果にトランザクションが含まれていない、または
txnNotFoundエラーが返される場合、サーバに保存されているレジャーにはそのトランザクションはありません。
ただし、このことだけでトランザクションの失敗を判断できない場合があります。
以下は、成功したトランザクションの例です。
rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpnというアドレスが、シーケンス番号376を使用してAccountSetトランザクションを送信したことを示しています。
トランザクションの識別用ハッシュは017DED8F5E20F0335C6F56E3D5EE7EF5F7E83FB81D2904072E665EEA69402567で、その結果はtesSUCCESSです。
トランザクションは、検証済みのレジャーバージョン46447423に記録されファイナリティに達しています。
トランザクションが検証済みレジャーに記録されていない場合、共有XRP Ledgerの状態に影響しません。
トランザクションが検証済みレジャーに記録されている場合、トランザクションメタデータにはレジャーの状態に対して行われたすべての変更が含まれます。TransactionResultフィールドには、結果を要約したトランザクション結果コードが含まれます。
tesSUCCESSは、トランザクションがだいたい成功したことを示します。tecクラスコードは、トランザクションが失敗したことを示します。
結果コードはトランザクションの結果の要約にすぎません。
トランザクションの実行内容を詳しく理解するには、残りのメタデータを確認する必要があります。
メタデータの解釈
XRP Ledgerのトランザクションメタデータは、トランザクションがレジャーに適用された方法を正確に示します。
主要なフィールドは以下の通りです。
AffectedNodesこのトランザクションで作成、削除、または修正されたレジャーオブジェクトのリストと、個々のオブジェクトに対する具体的な変更内容。
DeliveredAmount廃止予定。
delivered_amountで置き換えられます。
TransactionIndexトランザクションが記録されているレジャーでのトランザクションの位置。
TransactionResultトランザクションが成功したか、どのような理由で失敗したかを示す結果コード。
delivered_amountDestinationアカウントが実際に受取った通貨額。
ほとんどのメタデータはAffectedNodes配列に含まれており、トランザクションのタイプによって探す対象が異なります。
ほぼすべてのトランザクションが、送金元のAccountRootオブジェクトを変更してXRPトランザクションコストを消却し、アカウントのシーケンス番号を増やします。
以下は、AccountSetトランザクションの例です。
上記のトランザクションによって行われた唯一の変更は、送金元のAccountRootオブジェクトの更新です。
Sequence値は376から377に増加。XRPの
Balanceは396015176から396015164に減少(12 dropがトランザクションコストとして消却)。AccountTxnIDが変更され、このトランザクションが最新のトランザクションとなったことを反映。PreviousTxnIDとPreviousTxnLgrSeqが、このアカウントに影響を及ぼした以前のトランザクション(E710CADE7FE9C26C51E8630138322D80926BE91E46D69BF2F36E6E4598D6D0CF)を示す。
メタデータには明示的に示されませんが、トランザクションがレジャーオブジェクトを変更すると、そのオブジェクトのPreviousTxnIDとPreviousTxnLgrSeqフィールドが現在のトランザクションの情報で更新されます。
XRPが送信または受信される場合、送金元の残高の変動額はトランザクションコストと合算され、Balanceフィールドの金額は1回で変更されます。
トランザクションを記録する
ほぼすべてのトランザクションにより、以下のような変更が行われます。
シーケンスとトランザクションコストの変更
送金元のシーケンス番号を増やし、トランザクションコストの支払いに使用するXRPを消却するために、疑似トランザクションを除くすべてのトランザクションが送金元のAccountRootオブジェクトに変更を加えます。
アカウントのスレッド化
オブジェクトを作成する一部のトランザクションでは、目的の受取人または宛先のアカウントのAccountRootオブジェクトも変更し、そのアカウントに関連する要素が変更されたことを示します。
この「タグ付け」手法では、オブジェクトのPreviousTxnIDとPreviousTxnLgrSeqフィールドのみを変更し、これらのフィールドに指定されたトランザクションの「スレッド」を追跡することで、アカウントのトランザクション履歴を効率よく検索できます。
ディレクトリーの更新
レジャーオブジェクトを作成または削除するトランザクションは、多くの場合DirectoryNodeオブジェクトを変更して、どのオブジェクトが存在しているかを追跡します。
また、アカウントの所有者準備金に反映されるオブジェクトが追加されると、所有者のAccountRootオブジェクトのOwnerCountが増加し、オブジェクトを削除するとOwnerCountが減少します。
アカウントのOwnerCountを増やす例。
多くのトランザクションのタイプで、DirectoryNodeオブジェクトが作成または変更されます。
これらのオブジェクトは、アカウントが所有するすべてのオブジェクトや、同じ為替レートで通貨を交換するすべてのオファーを追跡するためのトランザクション記録に使用されます。
トランザクションがレジャーに新しいオブジェクトを作成した場合、既存のDirectoryNodeオブジェクトにエントリを追加するか、別のDirectoryNodeオブジェクトを追加してディレクトリーの別のページを表す必要があります。トランザクションがレジャーからオブジェクトを削除した場合、不要となった1つ以上のDirectoryNodeオブジェクトを削除する必要があります。
新しいオファーディレクトリーを表すCreatedNodeの例。
トランザクションメタデータを処理する時に探すその他の項目は、トランザクションのタイプによって異なります。
支払い
XRP Ledgerにおける支払いには、XRP間の直接トランザクション、クロスカレンシー支払い、トークンでの直接トランザクションがあります。
XRP以外の支払いはpartial paymentが可能です。
デフォルトのケースでは、XRP LedgerのPaymentトランザクションの
Amountフィールドに、為替レートと送金手数料を差し引いた実際の送金額が指定されます。「Partial Payment」フラグ(tfPartialPayment)を使うと、送金額を増額する代わりに受取金額を減額して、支払を正常に実行できます。Partial Paymentは、追加コストなしで支払を返金したい場合に便利です。https://xrpl.org/ja/docs/concepts/payment-types/partial-payments/
トークンでの支払いは、トラストラインを表すRippleStateオブジェクトの残高変更として記録されます。1回の支払いで複数のトラストラインとオーダーブックを経由する長いパスをたどることがあり、このプロセスをRipplingと呼びます。
トラストラインとは、XRP Ledgerにおけるトークンを保持するための仕組みを指します。トラストラインは、XRP Ledgerのルールである「不要なトークンを他者に保有させることはできない」という原則を強制するものです。
クロスカレンシー支払いでは、オファーの一部または全額を消費して通貨間の変更が行われます。トラストラインの設定により、送金元と受取人での金額が異なる場合があります。
また、トークンの精度の範囲外で丸められることにより、少額のトークンが作成または消却される可能性があります。
クロスカレンシー支払いのメタデータは、パスの長さに応じて非常に長くなることがあります。
オファー
XRP Ledgerにおけるオファーの作成と変更は以下のようにまとめられます。
XRP Ledgerの分散型取引所では、通貨の取引注文は「オファー」と呼ばれます。オファーはXRPとトークンの取引、またはトークン間の取引(同一通貨コードだが発行者が異なるトークンを含む)を行うことができます。
https://xrpl.org/ja/docs/concepts/tokens/decentralized-exchange/offers/
OfferCreateトランザクションでは、成立額やフラグによって、レジャーにオファーオブジェクトが作成される場合と作成されない場合がある。LedgerEntryTypeがOfferのModifiedNodeは、成立し一部が消費されたオファーを示す。LedgerEntryTypeがOfferのDeletedNodeは、すべて消費された成立オファー、期限切れになったオファー、資金化されないオファー、またはキャンセルされたオファーを示す。
オファーの発行者とオファーの利用可能性を追跡するために
DirectoryNodeオブジェクトが作成、削除、変更される。OfferCancelトランザクションが実際にオファーを削除したことを確認するには、LedgerEntryTypeがOfferのDeletedNodeを探す。OfferCreateトランザクションがタイプRippleStateのCreatedNodeを示す場合、オファーがトラストラインを作成したことを示す。
Escrow
XRP Ledgerにおけるエスクローの作成と終了は以下のようにまとめられます。
成功した
EscrowCreateトランザクションは、レジャーにEscrowオブジェクトを作成し、送金元から同額のXRPを引き出す。成功した
EscrowFinishトランザクションは、受取人のXRP残高を増加させ、Escrowオブジェクトを削除し、エスクロー作成者の所有者数を減らす。成功した
EscrowCancelトランザクションは、XRPをエスクローの最初の作成者に返却する点を除き、EscrowFinishと類似している。EscrowFinishは、エスクローの条件を満たす場合にのみ成功し、EscrowCancelはEscrowオブジェクトの期限が前のレジャーの閉鎖時刻よりも前である場合にのみ成功する。
上記のコード例では、自身宛てのエスクローが正常に終了したため、アカウントr9UUEX...の残高が10億XRP増加し、所有者の数が1減少している。
Payment Channel
Payment Channelの作成時には、LedgerEntryTypeがPayChannelのCreatedNodeを探します。
また、送金元の残高の減少を示す、LedgerEntryTypeがAccountRootのModifiedNodeも探す必要があります。
fixPayChanRecipientOwnerDir Amendmentが有効な場合は、メタデータは宛先のアカウントの所有者ディレクトリーを変更して、新しく作成されるPayment Channelをリストで示す必要もあります。
Payment Channelの閉鎖を要求する方法は、Payment Channelの不変のCancelAfter時刻以外にもいくつかあります。
トランザクションでChannelの閉鎖をスケジュールする場合は、そのChannel用にLedgerEntryTypeがPayChannelのModifiedNodeエントリがあり、FinalFieldsのExpirationフィールドには閉鎖時刻が新たに追加されています。
上記のコード例は、送金元がクレームを清算せずにChannelを閉鎖するよう要求した場合にPayChannelに対して行われる変更を示しています。
TrustSetトランザクション
TrustSetトランザクションは、RippleStateオブジェクトとして表されるトラストラインを作成、変更、または削除します。
1つのRippleStateオブジェクトには、関与する両当事者の制限やRipplingの設定などが含まれます。
トラストラインの作成と変更によって送金元の所有者準備金と所有者ディレクトリーの調整も行われます。
「Rippling」とは同一通貨のトラストラインを有する複数の接続当事者間での非可分なネット決済のプロセスを指しています。Ripplingはトークンの基幹的なプロセスです。Ripplingを利用すれば、同一イシュアーを信頼するユーザは、そのイシュアーを受動的な仲介機関として発行済み残高を相互に送金できるようになります。Ripplingは、受動的かつ双方向の通貨取引オーダーのようなもので、制限がなく、通貨コードが同一でイシュアーが異なる2つの通貨間の為替レートは1:1です。
https://xrpl.org/ja/docs/concepts/tokens/fungible-tokens/rippling/
以下のコード例は、rf1BiG... が rsA2Lp... によって発行されたUSDを最大110 USDまで保持するという新しいトラストラインを示しています。
その他のトランザクション
その他のほとんどのトランザクションは、特定のタイプのレジャーエントリを作成し、送金元の所有者準備金と所有者ディレクトリーの調整を行います。
AccountSetトランザクションは、送金元の既存のAccountRootオブジェクトを変更し、指定されたとおりに設定とフラグを変更する。
AccountRootは、単一のアカウント、その設定、およびXRP残高を記述します。
DepositPreauthトランザクションは、特定の送金元のDepositPreauthオブジェクトを追加または削除する。
DepositPreauthオブジェクトはアカウント間の事前承認を追跡します。DepositPreauthトランザクションによりこれらのオブジェクトが作成されます。https://xrpl.org/ja/docs/references/protocol/ledger-data/ledger-entry-types/depositpreauth/
SetRegularKeyトランザクションは、送金元のAccountRootオブジェクトを変更し、指定されたとおりにRegularKeyフィールドを変更する。SignerListSetトランザクションは、SignerListオブジェクトを追加、削除、または置換する。
SignerListオブジェクトタイプは、個別アカウントの代わりにグループとしてトランザクション署名をすることが承認されている署名者のリストです。SignerListSetトランザクションを使用して、SignerListを作成、置き換え、または削除できます。https://xrpl.org/ja/docs/references/protocol/ledger-data/ledger-entry-types/signerlist/
疑似トランザクションにもメタデータがあるが、通常のトランザクションのすべてのルールに従うとは限らない。
疑似トランザクションは実在のアカウントに関連付けられていないため、レジャーのAccountRootオブジェクトを変更してシーケンス番号を増やしたりXRPを消却したりしない。
EnableAmendment疑似トランザクションは、Amendmentレジャーオブジェクトを変更して、有効なAmendment、過半数の支持を得ている保留中のAmendment、および保留中の期間を追跡する。
Amendmentsオブジェクトタイプには、現在アクティブなAmendmentのリストが含まれています。各レジャーバージョンには最大で1つのAmendmentsオブジェクトが含まれています。https://xrpl.org/ja/docs/references/protocol/ledger-data/ledger-entry-types/amendments/
Amendmentは、トランザクション処理における新機能またはその他の変更を表します。
https://xrpl.org/ja/docs/concepts/networks-and-servers/amendments/
SetFee疑似トランザクションは、FeeSettingsレジャーオブジェクトを変更して、トランザクションコストおよび必要準備金のベースレベルを変更する。
FeeSettingsオブジェク トタイプには、現在の基本トランザクションコストと、手数料投票により決定する準備金の額が含まれています。各レジャーバージョンには最大で1つのFeeSettingsオブジェクトが含まれています。https://xrpl.org/ja/docs/references/protocol/ledger-data/ledger-entry-types/feesettings/
トランザクション展性
XRP Ledgerでは、署名付きトランザクションの機能性は変更できないが、場合によっては第三者がトランザクションの署名と識別用ハッシュを変更できる可能性があります。
この展性のあるトランザクションを送信した脆弱なソフトウェアは、トランザクションの状況を把握できなくなる可能性があり、最悪の場合、不正使用者がこの点を悪用して資金を盗むことが可能です。
XRP Ledgerのメインネット上では、マルチ署名トランザクションのみが、必要以上の署名がある場合や承認された署名者が必要以上の追加署名を提供する場合に変更可能です。
2014年以前は、デフォルトの署名アルゴリズムの特性により、単一署名トランザクションを不正に変更することができたが、2020年7月にRequireFullyCanonicalSig Amendmentが有効になるまでは、この変更可能なトランザクションを作成・提出することが可能でした。
展性とは、署名後のトランザクションを、署名に使用されたキーを使用せずに変更できる性質のことを指します。
つまり、トランザクションに署名した後でも、その署名を無効にすることなく、トランザクションの内容を変更できてしまう可能性があるということです。
この性質を悪用すると、トランザクションの送信者が意図しない形でトランザクションが変更され、送信者が気づかないうちに不正な取引が行われてしまう可能性があります。
したがって、暗号通貨のシステムでは、展性を防ぐための対策が重要になります。
背景
XRP Ledgerでは、トランザクションを実行するためには、いくつかの条件を満たす必要があります。
まず、署名自体を除くトランザクションのすべてのフィールドに署名がなされている必要があります。
次に、署名に使用されるキーペアが、そのアカウントの代理としてトランザクションを送信することを承認されている必要があります。
最後に、署名が正規であり、トランザクションの指示に一致している必要があります。
secp256k1曲線を使用したECDSA署名では、2つの有効な値のうち小さい方を使用することが求められます。
2020年に有効になったRequireFullyCanonicalSig Amendmentでは、すべてのトランザクションは完全正規な署名のみを使用しなければならないと定められました。
マルチシグトランザクションでは、署名の削除、追加、置換により展性の問題が生じる可能性があります。
これを防ぐためには、いくつかの適切な運用セキュリティ対策を導入する必要があります。
具体的には以下の項目が挙げられます。
必要な数以上の署名を収集しないこと
トランザクション作成当事者を任命するか署名者が事前に定義された順序で署名すること
不要な署名者を追加しないこと
異なるハッシュや想定外の署名セットを使用して実行される可能性に備えること
アカウントから送信されたトランザクションとシーケンス番号を監視すること
tfFullyCanonicalSigフラグが有効であることを確認すること
これらの対策を講じることで、マルチシグトランザクションにおける展性の問題を防ぐことができます。
展性のあるトランザクションを使用した悪用
XRP Ledgerとのインターフェイスに使用するソフトウェアから展性のあるトランザクションが送信されると、不正使用者がソフトウェアをだましてトランザクションの最終結果を確認できなくし、同額の支払いを複数回送金させることが可能になります。
脆弱なシステムを悪用するプロセスは以下のような順で進みます。
脆弱なシステムが、
tfFullyCanonicalSigを有効にせずにトランザクションを生成し署名する。システムは脆弱なトランザクションの識別用ハッシュを確認し、そのハッシュをXRP Ledgerネットワークに送信し、検証済みレジャーバージョンにそのハッシュが記録されるのを監視し始める。
不正使用者は、トランザクションが確定する前にそのトランザクションがネットワークを通じて伝搬することを確認する。
不正使用者が脆弱なトランザクションの代替署名を計算する。
不正使用者が改ざんしたトランザクションをネットワークに送信する。
不正ユーザのトランザクションがコンセンサスに達し、検証済みレジャーに記録される。
脆弱なシステムは、予期しているトランザクションハッシュを認識せず、トランザクションが実行されなかったという誤った結論に達する。
脆弱なシステムは、トランザクションが失敗したと想定してアクションを実行する。
展性のあるトランザクションを悪用から守るには、tfFullyCanonicalSigフラグを常に有効にし、マルチシグを使用する場合は必要な数以上の署名を提供しないようにする必要があります。
トランザクションの取消し
XRP Ledgerでは、検証済みレジャーに組み込まれたトランザクションは即時に最終的なものになりますが、まだ記録されていないトランザクションは無効に設定することで実質的に取り消すことができます。
取り消す方法は以下の通りです。
同じアカウントから同じ
Sequence値を指定した別のトランザクションを送信する。置換トランザクションが何もしないようにしたい場合は、オプションを指定せずに
AccountSetトランザクションを送信する。
例えば、シーケンス番号11、12、13の3つのトランザクションを送信しようとしたときに、トランザクション11が失われたり、十分なトランザクションコストがない場合は、オプションを指定せずシーケンス番号11を指定したAccuontSetトランザクションを送信することで、トランザクション11を取り消し、トランザクション12と13を有効にできます。
この方法は、異なるシーケンス番号のトランザクションの内容が実質的に重複することを防ぐため、トランザクション12と13の番号を変更して再送信するよりも望ましいとされています。
オプションが指定されていないAccountSetトランザクションは標準的な「no-op」トランザクションとして使用されます。
「no-op」トランザクションとは、"no operation"の略で、実際には何も操作を行わないトランザクションのことを指します。
XRP Ledgerにおいては、オプションが指定されていない
AccountSetトランザクションがこれに該当します。このトランザクションは、アカウントのプロパティを変更するためのものですが、オプションが指定されていない場合、実際にはアカウントの状態を変更せずに、トランザクションの処理だけを行います。「no-op」トランザクションは、以下のような目的で使用されます。
未処理のトランザクションを取り消すため。同じシーケンス番号を持つ「no-op」トランザクションを送信することで、まだ検証済みレジャーに記録されていない前のトランザクションを無効化できます。
アカウントのシーケンス番号を調整するため。「no-op」トランザクションを送信することで、アカウントのシーケンス番号を増やすことができます。
レジャーを閉鎖するため。一定期間、新しいトランザクションが送信されない場合、バリデータは「no-op」トランザクションを送信してレジャーを閉鎖します。
このように、「no-op」トランザクションは、実際には何も操作を行わないにもかかわらず、XRP Ledgerの管理と運用において重要な役割を果たしています。
最後に
今回はXRP LEDGERのコンセプトの1つである「トランザクションの確定」についてまとめました。
これからも他のブロックチェーンやサービスについてもまとめていきます。
情報を見逃したくないという方はぜひ以下の購読ボタンを教えてください。
更新があった時、登録しているメールアドレス宛に通知が飛ぶようになります。
また、拡散もしてくれると嬉しいです🙇♂️














