# コンセンサス

_著者: Dave Cohen、David Schwartz、Arthur Britto_

この記事では、XRP Ledgerの概要や格納される情報、[トランザクション](transaction-formats.html)によってレジャー（台帳）が変化する様子について説明します。

XRP Ledger上でアプリケーションを構築する場合は、XRP Ledger APIの動作や、その動作によってもたされる影響を知っておくために、このプロセスを理解することが重要です。


## まえがき

ピアツーピアサーバーのXRP Ledgerネットワークは世界で共有されている台帳であり、ここから、アプリケーションはこの台帳の内容の状態に関して信頼できる情報を得ることができます。この状態に関する情報には以下の内容が含まれます。

- 各[アカウント](accounts.html)の設定
- XRPおよび[発行済み通貨](issued-currencies.html)の残高
- 分散型取引所でのオファー（注文）
- ネットワーク設定（例: [トランザクションコスト](transaction-cost.html)と[準備金](reserves.html)の金額）
- タイムスタンプ

レジャーバージョンに含まれるデータの詳細な技術説明については、[レジャーフォーマットのリファレンス](ledger-data-formats.html)を参照してください。

[![図1: XRP Ledgerの要素](img/anatomy-of-a-ledger-complete.png)](img/anatomy-of-a-ledger-complete.png)

_図1: XRP Ledgerの要素_

XRP Ledgerでは、数秒ごとに新しいレジャーバージョンが作成されます。あるレジャーバージョンの内容にネットワークが同意すると、そのレジャーバージョンは _検証済み_ となり、その内容が変更されることはありません。それ以前の検証済みのレジャーバージョンによって、レジャー履歴が形成されます。検証済みの最新のレジャーも、少し前の時点のネットワークの状態を表しており、履歴の一部となります。現時点で、ネットワークは次のレジャーバージョンに適用されてファイナライズされる可能性のあるトランザクションを評価しています。この評価が行われている間、ネットワークには、検証前のレジャーバージョン候補が存在します。

[![図2: XRP Ledgerの履歴](img/ledger-history.png)](img/ledger-history.png)

_図2: XRP Ledgerの履歴_

レジャーバージョンには2つの識別子があります。1つ目の識別子は、そのレジャーバージョンの _レジャーインデックス_ です。レジャーバージョンの番号は1つずつ増加します。例えば、現行のレジャーバージョンのレジャーインデックスが100の場合、1つ前はレジャーインデックス99、1つ後はレジャーインデックスは101です。もう1つの識別子は _レジャーハッシュ_ で、レジャーの内容のデジタル指紋を表します。

サーバーがレジャーに適用するトランザクションを提案するときに、内容がわずかに異なる複数の候補レジャーバージョンが作成される場合があります。このような候補レジャーバージョンでは、レジャーインデックスは同じですがレジャーハッシュが異なります。多くの候補のうち、検証済みとなるのは1つだけです。それ以外の候補レジャーバージョンはすべて、破棄されます。そのため、履歴内の各レジャーインデックスに対して存在する検証済みのレジャーハッシュは1つのみです。

レジャーに対するユーザーレベルの変更は、トランザクションによってなされます。[トランザクション](transaction-formats.html)の例としては、決済、アカウントの設定またはトラストラインの変更、取引のオファー（注文）などがあります。各トランザクションは、レジャーに対する1つ以上の変更を承認するものであり、アカウント所有者によって暗号署名されます。アカウントの変更を承認したり、レジャーのそれ以外の内容を変更したりするには、トランザクションだけが唯一の方法です。

各レジャーバージョンには、一連のトランザクションと、そのようなトランザクションに関するメタデータも含まれています。それらのトランザクションは、新しいレジャーバージョンを作成するために前のバージョンのレジャーに適用されたものです。メタデータには、レジャーの状態データに対する、トランザクションの影響が正確に記録されています。

[![図3: レジャーバージョンに適用されるトランザクション](img/ledger-changes.png)](img/ledger-changes.png)

_図3: レジャーバージョンに適用されるトランザクション_

レジャーインスタンスに含まれる一連のトランザクションはそのレジャーに記録され、XRP Ledger履歴の監査を可能としています。レジャーN+1のアカウント残高がレジャーNのアカウント残高と異なる場合、レジャーN+1にはその変更の原因となったトランザクションが含まれます。

検証済みのレジャー内に出現するトランザクションは、レジャーの変更に成功したか、または要求されたアクションを実行せずに処理された可能性があります。成功したトランザクションには、要求された変更がレジャーに適用されたことを示す**tesSUCCESS** [結果コード](transaction-results.html)が含まれます。レジャー内の失敗したトランザクションには、**tec**クラスの結果コードが含まれます。<a href="#footnote_1" id="from_footnote_1"><sup>1</sup></a>

レジャーに含まれるトランザクションでは必ず、[トランザクションコスト](transaction-cost.html)として一部のXRPが消却されます。この場合、**tes**コードまたは**tec**コードが含まれていたかどうかは関係ありません。消却するXRPの正確な量は、署名されたトランザクションの手順で定義されます。

**tes**クラスや**tec**クラスの結果コード以外に、**ter**クラス、**tef**クラス、および**tem**クラスのコードがあります。後者の3つは、APIの呼び出しによって返された暫定的な失敗を示します。レジャーには、**tes**および**tec**のコードのみ表示されます。レジャーに含まれていないトランザクションによって、レジャーの状態（XRP残高を含む）が影響を受けることはありませんが、暫定的に失敗したトランザクションが後で成功する可能性があります。

[`rippled` API](rippled-api.html)を使用する場合、レジャーに含めるように提案された候補トランザクションと、検証済みのレジャーに含まれる検証済みのトランザクションをアプリケーションで区別する必要があります。検証済みのレジャー内にあるトランザクションの結果のみが不変です。検証済みのレジャーには、候補トランザクションが含まれる場合と含まれない場合があります。

重要: 一部の[`rippled` API](rippled-api.html)では、候補トランザクションに基づき暫定的な結果が返されます<a href="#footnote_2" id="from_footnote_2"><sup>2</sup></a>。アプリケーションで、トランザクションの最終的な結果を判断する目的で暫定的な結果を使用するのは望ましくありません。最終的にトランザクションが成功したことを確実に知る唯一の方法は、そのトランザクションが検証済みのレジャー内にあり、かつ、結果コードがtesSUCCESSになるまで、トランザクションの状況を確認することです。トランザクションが検証済みレジャー内にあるが、結果コードがそれ以外の場合、トランザクションの失敗を意味します。トランザクションの[`LastLedgerSequence`](transaction-common-fields.html)で指定されたレジャーが検証済みにもかかわらず、そのトランザクションがそのレジャーまたはそれ以前の他のレジャー内にない場合、トランザクションは失敗しており、どのレジャーにも表示されません。検証済みのレジャー内に表示されるトランザクションの場合にのみ、結果は最終的なものとなります。それ以外の場合、このドキュメントで後述するように、`LastLedgerSequence`の制限により、表示されることはありません。

## XRP Ledgerプロトコル - コンセンサスと検証

ピアツーピアのXRP Ledgerネットワークは、トランザクションを承認して処理する多数の独立したXRP Ledgerサーバー（通常、[`rippled`](the-rippled-server.html)を実行）で構成されています。クライアントアプリケーションは、トランザクションに署名してXRP Ledgerサーバーに送信します。サーバーは、これらの候補トランザクションを処理するためにネットワーク内を中継します。クライアントアプリケーションには、モバイルおよびウェブウォレット、金融機関へのゲートウェイ、電子取引プラットフォームなどがあります。

[![図4: XRP Ledgerプロトコルの参加者](img/xrp-ledger-network.png)](img/xrp-ledger-network.png)

_図4: XRP Ledgerプロトコルの参加者_

トランザクションを受信、中継、処理するサーバーは、追跡サーバーとバリデータのいずれかです。追跡サーバーの主な機能には、クライアントからのトランザクションの分散やレジャーに関する照会への応答が含まれます。検証サーバーは、追跡サーバーと同じ機能を実行し、さらにレジャー履歴を進めます<a href="#footnote_3" id="from_footnote_3"><sup>3</sup></a>。

クライアントアプリケーションによって送信されたトランザクションを受け入れるときに、各追跡サーバーは最後に検証されたレジャーを開始点として使用します。受け入れられたトランザクションは候補トランザクションとなります。サーバーから候補トランザクションがそれぞれのピアに中継され、候補トランザクションがネットワーク全体に伝達されます。理想的には、各候補トランザクションはすべてのサーバーに伝達される必要があります。その結果、各サーバーは最後に検証されたレジャーに同じ一連のトランザクションを適用できる可能性が高くなります。しかし、トランザクションが伝達されるまでには時間がかかるため、サーバーは常に同じ候補トランザクションを処理するわけではありません。このことを考慮に入れて、XRP Ledgerでは、コンセンサスと呼ばれるプロセスを使用して、同一のトランザクションが処理され、ピアツーピアのXRP Ledgerネットワーク全体で検証済みのレジャーの一貫性が確保できるようにしています。

### コンセンサス

ネットワーク内のサーバーは、候補トランザクションに関する情報を共有します。コンセンサスプロセスを通じて、バリデータは、候補トランザクションの特定のサブセットが次のレジャーで考慮されることに同意します。コンセンサスとは、サーバーが提案や一連の候補トランザクションを中継する反復プロセスです。サーバーは、選択されたバリデータの圧倒的多数<a href="#footnote_4" id="from_footnote_4"><sup>4</sup></a>が同じ候補トランザクションのセットについて合意するまで、提案の通信と更新を行います。

コンセンサスの間、各サーバーは、そのサーバーの信頼できるバリデータ（ _ユニークノードリスト（UNL）_ ）と呼ばれる特定のサーバー群からの提案を評価します。<a href="#footnote_5" id="from_footnote_5"><sup>5</sup></a>信頼できるバリデータとは、提案を評価するサーバーを欺こうと共謀しない、全体として「信頼できる」ネットワークのサブセットを表します。この「信頼」の定義では、選択された個々のバリデータが信頼されている必要はありません。バリデータの選択は、ネットワークに中継されたデータを改ざんする組織的な試みで共謀しないという想定に基づいて行われます<a href="#footnote_6" id="from_footnote_6"><sup>6</sup></a>。 <!-- STYLE_OVERRIDE: will -->

[![図5: バリデータによるトランザクションセットの提案と修正](img/consensus-rounds.png)](img/consensus-rounds.png)

_図5: バリデータによるトランザクションセットの提案と修正 - コンセンサスの開始時点で、バリデータ毎に異なるトランザクションセットを持っている可能性があります。後のラウンドで、サーバーは現在の提案を信頼できるバリデータの提案と一致するように変更します。このプロセスでは、現在議論しているレジャーバージョンに適用するトランザクションと、それ以降のレジャーバージョンに適用するトランザクションを決定します。_

合意済みの提案に含まれていない候補トランザクションは、その後も候補トランザクションとして残ります。これらは次のレジャーバージョンで再度検討される可能性があります。通常、1つのレジャーバージョンから除外されたトランザクションは、次のレジャーバージョンに含まれます。

状況によっては、いつまでもコンセンサスに達することができないトランザクションもあります。そのような状況として、ネットワークが、必要な[トランザクションコスト](transaction-cost.html)を、トランザクションで指定されたものよりも高い値に変更している場合が考えられます。将来のある時点でこの手数料が引き下げられると、そのトランザクションが成功する可能性があります。トランザクションの成功または失敗が一定時間内に確定するように、トランザクションが特定のレジャーインデックスによって一定時間処理されない場合は期限切れになるように設定することができます。詳細は、[信頼できるトランザクションの送信](reliable-transaction-submission.html)を参照してください。

### 検証

検証は、全体のコンセンサスプロセスの第2段階です。このプロセスでは、すべてのサーバーで同じ結果が得られたことを確認し、あるレジャーバージョンが最終バージョンとして宣言されます。まれに、第一段階の[コンセンサスプロセスが失敗する場合](consensus-principles-and-rules.html#コンセンサス失敗の可能性)があります。検証によって後で確認が行われるため、サーバーは結果を確認し、それに応じて対処することができます。

検証は、大きく分けて次の2つの部分に分かれます。

- 合意済みのトランザクションセットから結果として生じるレジャーバージョンを計算する。
- 結果を比較し、十分に信頼できるバリデータが同意した場合はレジャーバージョンの検証済みを宣言する。

#### 検証の計算と共有

コンセンサスプロセスが完了すると、各サーバーは合意済みの一連のトランザクションから新しいレジャーを個別に計算します。各サーバーは、同じ規則に従って結果を次のように計算します。

1. 一つ前の検証済みのレジャーから始めます。

2. すべてのサーバーが同じ方法で処理できるように、合意済みのトランザクションセットを _正規順序_ で並べ変えます。
   
   [正規順序](https://github.com/ripple/rippled/blob/8429dd67e60ba360da591bfa905b58a35638fda1/src/ripple/app/misc/CanonicalTXSet.cpp#L25-L36)は、トランザクションを受け取った順序ではありません（サーバーが同じトランザクションを異なる順序で受け取る可能性があるため）。参加者がトランザクションの順序付けで競合しないように、故意に操作するのが困難な正規順序を使います。

3. 指示に従って、各トランザクションを順番に処理します。それに応じてレジャーの状態データを更新します。
   
   トランザクションを正常に実行できない場合は、[`tec`クラス結果コード](tec-codes.html)を持つトランザクションを含めます。<a href="#footnote_1" id="from_footnote_1"><sup>1</sup></a>
   
   特定の「再試行可能な」トランザクションの失敗に対しては、同じレジャーバージョンの他のトランザクションが実行された後に再試行されるように、そのトランザクションを正規順序の最後に移動します。

4. 適切なメタデータでレジャーヘッダーを更新します。
   
   これには、レジャーインデックス、前に検証済みのレジャーの識別ハッシュ（このレジャーの「親」）、このレジャーバージョンの予定終了時刻、このレジャーの内容の暗号化ハッシュなどのデータが含まれます。

5. 新しいレジャーバージョンの識別用ハッシュを計算します。

[![図7: XRP Ledgerサーバーでレジャー検証を計算する](img/consensus-calculate-validation.png)](img/consensus-calculate-validation.png)

_図7: XRP Ledgerサーバーでレジャー検証を計算する - 各サーバーは、同意済みのトランザクションを前の検証済みレジャーに適用します。バリデータは結果をネットワーク全体に送信します。_

#### 結果を比較する

バリデータはそれぞれ、計算したレジャーバージョンのハッシュを含む署名付きメッセージの形式で結果を中継します。 _検証_ と呼ばれるこれらのメッセージによって、各サーバーで計算したレジャーとそのピアのレジャーを比較することができます。

[![図8: 圧倒的多数のピアが同じ結果を計算するとレジャーが検証される](img/consensus-declare-validation.png)](img/consensus-declare-validation.png)

_図8: 圧倒的多数のピアが同じ結果を計算するとレジャーが検証される - 各サーバーは、計算されたレジャーを、選択されたバリデータから受け取ったハッシュと比較します。一致しない場合、サーバーは正しいレジャーを再計算または取得する必要があります。_

ネットワーク内のサーバーは、圧倒的多数のピアが同じ検証ハッシュに署名してそれをブロードキャストしたときに、そのレジャーインスタンスを検証済みと認識します <a href="#footnote_7" id="from_footnote_7"><sup>7</sup></a>。それ以降のトランザクションは、レジャーインデックスN+1の更新および検証済みのこのレジャーに適用されます。

サーバーが少数で、ピアと異なるレジャーを計算した場合、計算したレジャーは無視されます<a href="#footnote_8" id="from_footnote_8"><sup>8</sup></a>。正しいレジャーを再計算するか、必要に応じて正しいレジャーを取得します。

ネットワークで、検証に関する圧倒的多数の同意が得られない場合、コンセンサスプロセスで一貫した提案を作成するにはトランザクション量が多すぎるか、ネットワーク遅延が大きすぎることを意味します。この場合、サーバーはコンセンサスプロセスを繰り返します。コンセンサスが始まってから時間が経過するにつれて、各コンセンサスラウンドで不一致は減少するため、過半数のサーバーが同じ候補トランザクションのセットを受け取った可能性が高くなります。XRP Ledgerは、これらの状況に応じて[トランザクションコスト](transaction-cost.html)と、コンセンサスを待つ時間を動的に調整します。

検証について圧倒的多数の合意が得られると、サーバーは検証済みの新しいレジャー、レジャーインデックスN+1との作業に入ることができます。最後のラウンドに含まれなかった候補トランザクションと、その間に送信された新しいトランザクションに対して、コンセンサスと検証プロセスが繰り返されます<a href="#footnote_9" id="from_footnote_9"><sup>9</sup></a>。


## 要点

XRP Ledgerに送信されたトランザクションはすぐには処理されません。一定期間、各トランザクションは候補状態になります。

単一トランザクションのライフサイクルは次のとおりです。

- アカウント所有者によってトランザクションが作成され、署名されます。
- トランザクションがネットワークに送信されます。
  - 書式が正しくないトランザクションはその場で拒否される可能性があります。
  - 書式が正しいトランザクションは暫定的に成功し、その後で失敗する可能性があります。
  - 書式が正しトランザクションは暫定的に失敗し、その後で成功する可能性があります。
- コンセンサスの間、トランザクションはレジャーに含まれます。
  - コンセンサスラウンドが成功すると、レジャーが有効になります。
  - コンセンサスラウンドが失敗すると、成功するまでコンセンサスプロセスが繰り返されます。
- 検証済みレジャーには、トランザクションとレジャーの状態への反映が含まれます。

アプリケーションでは、候補トランザクションの暫定的な結果ではなく、検証済みのレジャーの情報のみを信頼してください。一部の[`rippled` API](rippled-api.html)では、トランザクションの暫定的な結果が最初に返されます。トランザクションの結果が不変になるのは、そのトランザクションが検証済みレジャーに含まれている場合か、トランザクションに`LastLedgerSequence`が含まれ、そのレジャーインデックス以下の検証済みレジャーに出現しない場合に限られます。

トランザクションを送信するアプリケーションのベストプラクティスは次のとおりです。

- `LastLedgerSequence`パラメーターを使用して、トランザクションが確定的かつ迅速な方法で検証されるか、失敗するようにします。
- 検証されたレジャーでトランザクションの結果を確認します。
  - トランザクションを含むレジャーが検証されるか、`LastLedgerSequence`が経過するまで、結果は暫定的です。
  - 結果コードが**tesSUCCESS**で`"validated": true`のトランザクションは、恒久的に成功しています。
  - 結果コードがそれ以外の場合で`"validated": true`のトランザクションは、恒久的に失敗しています。
  - トランザクションの`LastLedgerSequence`によって識別された検証済みレジャーを含め、これまでの検証済みのレジャーに出現しないトランザクションは、恒久的に失敗しています。
    - このようなケースを検出するために、レジャーの継続的な履歴を有するサーバーを使用には注意してください<a href="#footnote_10" id="from_footnote_10"><sup>10</sup></a>。
  - `LastLedgerSequence`で識別されるレジャーが検証されるまで、トランザクションの状態を繰り返し確認する必要がある場合があります。

## 関連項目

- **コンセプト:**
  - [コンセンサスについて](intro-to-consensus.html)
  - [コンセンサスの研究](consensus-research.html)
  - [Rippleコンセンサスの動画](https://www.youtube.com/watch?v=pj1QVb1vlC0)
- **チュートリアル:**
  - [信頼できるトランザクションの送信](reliable-transaction-submission.html)
  - [バリデータとしての`rippled`の実行](run-rippled-as-a-validator.html)
- **リファレンス:**
  - [レジャーフォーマットのリファレンス](ledger-data-formats.html)
  - [トランザクションフォーマットのリファレンス](transaction-formats.html)
  - [Consensus_infoメソッド][]
  - [Validator_list_sitesメソッド][]
  - [Validatorsメソッド][]





## 脚注

<a href="#from_footnote_1" id="footnote_1"><sup>1</sup></a> – [**tec**結果コード](tec-codes.html)を持つトランザクションでは、リクエストされたアクションは実行されませんが、レジャーには影響します。ネットワークの悪用を防ぎ、トランザクションの分散コストを賄うために、XRPの[トランザクションコスト](transaction-cost.html)が消却されます。同じ送信者によって同時刻に送信された他のトランザクションをブロックしないようにするには、送信者のアカウントの[シーケンス番号](basic-data-types.html#アカウントシーケンス)を都度増やしてゆきます。`tec`クラスの結果を持つトランザクションは、期限切れのオブジェクトや資金のない取引注文を削除するなどのメンテナンスも行います。

<a href="#from_footnote_2" id="footnote_2"><sup>2</sup></a> – 例えば、Aliceが100ドルを持っていて、全額をBobに送信するシナリオを考えてみましょう。アプリケーションは最初にPaymentトランザクションを送信し、Aliceの残高を確認したらすぐにAPIから0ドルが返されます。この値は、候補トランザクションの暫定結果に基づいています。支払いが失敗し、Aliceの残高が100ドルのままになる（または他のトランザクションによって別の金額になる）場合があります。AliceからBobへの支払いが成功したことを確実に知る唯一の方法は、そのトランザクションが検証済みのレジャー内にあり、かつ結果コードが**tesSUCCESS**になるまで、トランザクションの状況を確認することです。トランザクションが検証済みレジャーにあるが、結果コードが異なる場合、支払いは失敗したことを意味します。

<a href="#from_footnote_3" id="footnote_3"><sup>3</sup></a> – 厳密に言えば、バリデータは追跡サーバーのサブセットです。同じ機能を提供することに加えて、「検証」メッセージを送信します。追跡サーバーは、レジャー履歴全体を保持しているか、部分的なレジャー履歴を保持しているかによって、さらに分類することができます。

<a href="#from_footnote_4" id="footnote_4"><sup>4</sup></a> – トランザクションを認識したピアの割合（%）がしきい値を下回った場合、コンセンサスのラウンドは失敗します。各ラウンドは反復プロセスです。第1ラウンドの開始時には、少なくともピアの50%が同意する必要があります。コンセンサスラウンドの最終的なしきい値は80%の合意です。これらの具体的な値は変更される可能性があります。

<a href="#from_footnote_5" id="footnote_5"><sup>5</sup></a> – 各サーバーは独自の信頼できるバリデータを定義しますが、ネットワークの一貫性は、様々なサーバーで重複の度合いが高いバリデータのリストが選択されるかどうかにかかっています。このため、Rippleでは推奨するバリデータのリストを公開しています。

<a href="#from_footnote_6" id="footnote_6"><sup>6</sup></a> – 共謀しないとされるバリデータからだけでなくすべてのバリデータからの提案が評価される場合は、悪意のある攻撃者によって、無効なトランザクションが導入されたり、提案から有効なトランザクションが除外されたりする可能性があります。選択されたバリデータリストによって、[シビル攻撃](consensus-protections.html#シビル攻撃)から保護することができます。

<a href="#from_footnote_7" id="footnote_7"><sup>7</sup></a> – 2014年11月の時点で、圧倒的多数を表すしきい値として、少なくともピアの80%が検証すべきレジャーに同意する必要があります。これは、コンセンサスのラウンドで要求される割合と同じです。いずれのしきい値も変更される可能性があり、同じである必要はありません。

<a href="#from_footnote_8" id="footnote_8"><sup>8</sup></a> – 実際には、サーバーは自身が少数であることを検知してから、すべてのピアの検証を受け取ります。ピアの20%以上から不一致の検証を受け取ると、その検証がしきい値の80%を満たしていないことが分かります。その時点で、レジャーの再計算を始めることができます。

<a href="#from_footnote_9" id="footnote_9"><sup>9</sup></a> – 実際には、効率的に実行できるように、検証の完了前に新しいコンセンサスのラウンドが開始されます。

<a href="#from_footnote_10" id="footnote_10"><sup>10</sup></a> – `rippled`サーバーはレジャーの履歴全体がなくてもAPIリクエストに応答することができます。サービスやネットワーク接続が中断すると、そのサーバーのレジャー履歴にレジャーの不足や誤差が生じることがあります。時間の経過とともに、`rippled`によってその誤差は埋まります（そのように設定されている場合）。欠落しているトランザクションを検証する場合は、トランザクションが送信されてからLastLedgerSequenceまでの連続した完全なレジャーを持つサーバーに照らして検証することが重要です。特定のサーバーで利用できるcomplete_ledgersを判断するには、RPCサーバーの状態を使用します。


<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}			
{% include '_snippets/tx-type-links.md' %}			
{% include '_snippets/rippled_versions.md' %}
