Update Japanese translation files

This commit is contained in:
mDuo13
2020-06-05 17:21:18 -07:00
parent 5d47d4f288
commit fcad9d0376
110 changed files with 9094 additions and 2955 deletions

View File

@@ -1,14 +1,37 @@
# XRP Ledger APIの使用開始
`rippled`サーバーに対してコマンドを実行するには、接続先のサーバーをあらかじめ把握しておく必要があります。大多数のサーバーは、外部ネットワークからの直接のAPI要求を受け入れないよう設定されています。
XRP Ledgerのコアサーバーソフトウェアは[`rippled`](the-rippled-server.html)です。XRP Ledgerでの開発に進むには、`rippled`サーバーのAPIにアクセスします。
別の方法として、[`rippled`の独自のローカルコピーを運用](install-rippled.html)することもできます。[管理用のメソッド](admin-rippled-methods.html)のいずれかにアクセスする場合、これは必須です。この場合、サーバーのバインド用として設定したIPアドレスとポートを使用する必要があります例えば`127.0.0.1:54321`。また、管理機能にアクセスするには、構成ファイルで管理用としてマークされているポートおよびIPアドレスから接続しなければなりません
APIにアクセスする最も簡単な方法は、[**WebSocket API Tool**](websocket-api-tool.html)を使用するか、[XRP Ledger Explorer](https://livenet.xrpl.org/)を使用してレジャーの進行状況をその場で確認することです
[`rippled`の独自のインスタンスを実行](install-rippled.html)したり、[公開サーバー](#公開サーバー)を使用したりすることもできます。
## 公開サーバー
Rippleは、XRP Ledgerコミュニティ向けにいくつかの公開サーバーを提供しています。
| 演算子 | [ネットワーク][ | JSON-RPC URL | WebSocket URL | 注記 |
|:----------|:----------|:----------|:----------|:----------|
| Ripple | **Mainnet** | `https://s1.ripple.com:51234/` | `wss://s1.ripple.com/` | 汎用サーバークラスター |
| Ripple | **Mainnet** | `https://s2.ripple.com:51234/` | `wss://s2.ripple.com/` | [すべての履歴が記録されるサーバー](ledger-history.html#すべての履歴)クラスター |
| Ripple | Testnet | `https://s.altnet.rippletest.net:51234/` | `wss://s.altnet.rippletest.net/` | Testnet公開サーバー |
| Ripple | Devnet | `https://s.devnet.rippletest.net:51234/` | `wss://s.devnet.rippletest.net/` | Devnet公開サーバー |
[ネットワーク]: parallel-networks.html
これらの公開サーバーは継続的な使用やビジネスでの使用を想定したものではなく、いつでも使用不可となる可能性があります。日常的な使用については、独自の`rippled`サーバーを自社で運用するか、信頼できる事業者と運用委託契約を締結します。
## 管理者アクセス権限
`rippled`サーバーの[管理メソッド](admin-rippled-methods.html)を使用するには、次のように行います。この場合、サーバーのバインド用として設定したIPアドレスとポートを使用する必要があります例えば`127.0.0.1:54321`。また、管理機能にアクセスするには、構成ファイルで管理用としてマークされているポートおよびIPアドレスから接続しなければなりません。
[構成ファイルの例](https://github.com/ripple/rippled/blob/8429dd67e60ba360da591bfa905b58a35638fda1/cfg/rippled-example.cfg#L1050-L1073)では、ローカルループバックネットワーク上127.0.0.1のポート5005でJSON-RPCHTTP、ポート6006でWebSocketWSの接続をリッスンし、接続されるすべてのクライアントを管理者として扱っています。
## WebSocket API
いくつかのメソッドをXRP Ledgerで試すことを予定している場合は、独自のWebSocketコードを記述することなく、[Ripple WebSocket APIツール](websocket-api-tool.html)でAPIをすぐに使用できます。後ほど、独自の`rippled`サーバーへの接続が必要となった時点で、[ブラウザー](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)または[Node.jsで独自のクライアントをビルド](https://www.npmjs.com/package/ws)することが可能です。
いくつかのメソッドをXRP Ledgerで試すことを予定している場合は、独自のWebSocketコードを記述することなく、[Ripple WebSocket APIツール](websocket-api-tool.html)でAPIをすぐに使用できます。後ほど、独自の`rippled`サーバーへの接続が必要となった時点で、[ブラウザー](monitor-incoming-payments-with-websocket.html)または[Node.jsで独自のクライアントをビルド](https://www.npmjs.com/package/ws)することが可能です。
### 要求フォーマット
@@ -20,25 +43,13 @@
応答はJSONオブジェクトとして返されます。
### 公開サーバー
現在、Ripple社は以下の一連の公開WebSocketサーバーを運用しています。
| `Domain` | ポート | 注記 |
|:----------------|:-----|:--------------------------------------|
| `s1.ripple.com` | 443 | `wss://`のみ。汎用サーバー |
| `s2.ripple.com` | 443 | `wss://`のみ。すべての履歴が記録されるサーバー |
これらの公開サーバーは継続的な使用やビジネスでの使用を想定したものではなく、いつでも使用不可となる可能性があります。日常的な使用については、独自の`rippled`サーバーを自社で運用するか、信頼できる事業者と運用委託契約を締結します。
## JSON-RPC
任意のHTTPクライアント[RESTED for Firefox](https://addons.mozilla.org/en-US/firefox/addon/rested/)[Postman for Chrome](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en)などを使用して、JSON-RPCで`rippled`サーバーを呼び出すことができます。ほとんどのプログラミング言語には、HTTP要求を組み込むためのライブラリーが用意されています。
任意のHTTPクライアント[RESTED for Firefox](https://addons.mozilla.org/en-US/firefox/addon/rested/)[Postman for Chrome](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en)、[Online HTTP client ExtendsClass](https://extendsclass.com/rest-client-online.html)などを使用して、JSON-RPCで`rippled`サーバーを呼び出すことができます。ほとんどのプログラミング言語には、HTTP要求を組み込むためのライブラリーが用意されています。
### 要求フォーマット
JSON-RPC要求を作成するには、`rippled`サーバーがJSON-RPC接続をリッスンしているポートおよびIPアドレス上で、HTTP **POST**要求をルートパス(`/`に送信します。HTTP/1.0またはHTTP/1.1を使用できます。HTTPSを使用する場合は、TLS v1.2を使用してください。セキュリティーの維持を理由として、`rippled` _は_ SSL v3以前をサポートしていません。
JSON-RPC要求を作成するには、`rippled`サーバーがJSON-RPC接続をリッスンしているポートおよびIPアドレス上で、HTTP **POST**要求をルートパス(`/`に送信します。HTTP/1.0またはHTTP/1.1を使用できます。HTTPSを使用する場合は、TLS v1.2を使用してください。セキュリティーの維持を理由として、`rippled`SSL v3以前を _サポートしていません_
値を`application/json`として、`Content-Type`ヘッダーを常に記述してください。
@@ -51,17 +62,6 @@ JSON-RPC要求を作成するには、`rippled`サーバーがJSON-RPC接続を
応答もJSONオブジェクトになります。
### 公開サーバー
現在、Ripple社は以下の一連の公開JSON-RPCサーバーを運用しています。
| `Domain` | ポート | 注記 |
|:----------------|:------|:-----------------------|
| `s1.ripple.com` | 51234 | 汎用サーバー |
| `s2.ripple.com` | 51234 | すべての履歴が記録されるサーバー |
これらの公開サーバーは継続的な使用やビジネスでの使用を想定したものではなく、いつでも使用不可となる可能性があります。日常的な使用については、独自の`rippled`サーバーを自社で運用するか、信頼できる事業者と運用委託契約を締結します。
## コマンドライン
@@ -71,13 +71,14 @@ JSON-RPC要求を作成するには、`rippled`サーバーがJSON-RPC接続を
rippled --conf=/etc/rippled.cfg server_info
```
**注記:** コマンドラインインターフェイスは、管理の目的でのみ使用されることを想定しています。_サポートされるAPIではありません_。
**注記:** コマンドラインインターフェイスは、管理の目的でのみ使用されることを想定しています。 _サポートされるAPIではありません_
### 要求フォーマット
コマンドラインでは、通常の(先頭にダッシュが付いた)コマンドラインオプションに続けてコマンドを記述した後、一連の限定的なパラメーターを空白文字で区切って記述します。空白文字などの特殊な文字が含まれている可能性があるパラメーター値は、一重引用符で囲みます。
## 要求の例
<!-- MULTICODE_BLOCK_START -->
@@ -102,7 +103,7 @@ POST http://s1.ripple.com:51234/
"method": "account_info",
"params": [
{
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"strict": true,
"ledger_index": "validated"
}
@@ -118,6 +119,7 @@ rippled account_info r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59 validated true
<!-- MULTICODE_BLOCK_END -->
## 応答フォーマット
### 成功した場合の応答の例
@@ -128,7 +130,7 @@ rippled account_info r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59 validated true
```
{
"id": 2,
"id": 2,
"status": "success",
"type": "response",
"result": {
@@ -151,7 +153,7 @@ rippled account_info r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59 validated true
*JSON-RPC*
```
HTTP Status: 200 OK
HTTP Status:200 OK
{
"result": {
"account_data": {
@@ -165,11 +167,12 @@ HTTP Status: 200 OK
"Sequence": 1400,
"index": "4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05"
},
"ledger_index": 6761012,
"status": "success"
"ledger_index": 6761012,
"status": "success"
}
}
```
*コマンドライン*
```
@@ -196,13 +199,28 @@ HTTP Status: 200 OK
成功した場合の応答に含まれているフィールドは、以下のとおりです。
| `Field` | 型 | 説明 |
|:----------------|:---------|:------------------------------------------------|
| `id` | (場合により異なる) | WebSocketのみこの応答の要求元となった要求で提供されているID。 |
| `status` | 文字列 | WebSocketのみ値が`success`である場合、要求がサーバーによって正常に受信され、理解されたことを示します。 |
| `result.status` | 文字列 | JSON-RPCおよびコマンドライン値が`success`である場合、要求がサーバーによって正常に受信され、理解されたことを示します。 |
| `type` | 文字列 | WebSocketのみ値が`response`である場合、コマンドに対する正常な応答であることを示します。[非同期の通知](subscribe.html)では、`ledgerClosed``transaction`など異なる値が使用されます。 |
| `result` | オブジェクト | クエリーの結果。内容はコマンドによって異なります。 |
| `Field` | 型 | 説明 |
|:----------|:----------|:----------|
| `id` | (場合により異なる) | WebSocketのみこの応答の要求元となった要求で提供されているID。 |
| `status` | 文字列 | WebSocketのみ値が`success`である場合、要求がサーバーによって正常に受信され、理解されたことを示します。 |
| `result.status` | 文字列 | JSON-RPCおよびコマンドライン値が`success`である場合、要求がサーバーによって正常に受信され、理解されたことを示します。 |
| `type` | 文字列 | WebSocketのみ値が`response`である場合、コマンドに対する正常な応答であることを示します。[非同期の通知](subscribe.html)では、`ledgerClosed``transaction`など異なる値が使用されます。 |
| `result` | オブジェクト | クエリーの結果。内容はコマンドによって異なります。 |
### コマンドライン
コマンドラインのメソッドはJSON-RPCと同一のインターフェイスを使用しているため、応答フォーマットはJSON-RPCの応答と同一です。
## 関連項目
- **コンセプト:**
- [XRP Ledgerの概要](xrp-ledger-overview.html)
- [ソフトウェアエコシステム](software-ecosystem.html)
- [並列ネットワーク](parallel-networks.html)
- **チュートリアル:**
- [RippleAPI for JavaScriptの使用開始](get-started-with-rippleapi-for-javascript.html)
- [信頼できるトランザクションの送信](reliable-transaction-submission.html)
- [rippledサーバーの管理](manage-the-rippled-server.html)
- **リファレンス:**
- [rippled APIリファレンス](rippled-api.html)
- [Ripple Data API v2](data-api.html)

View File

@@ -1,21 +1,449 @@
# トランザクションの結果の確認
トランザクションの最終結果を確認するには、[txメソッド][]または[account_txメソッド][]を使用するか、`rippled`の他の応答を使用します。コンセンサスにより検証されたレジャーバージョンがこの応答に使用されていることを示す`"validated": true`を検索します。
XRP Ledgerを効果的に使用するには、[トランザクション](transaction-basics.html)の結果を次のように把握することが重要です。トランザクションは成功したか?トランザクションは何を遂行したか?失敗した場合は、なぜか?
| フィールド | 値 | 説明 |
|:-----------------------|:--------|:------------------------------------------|
| meta.TransactionResult | 文字列 | 結果を以下のように分類するコード(`tecPATH_DRY`など) |
| validated | ブール値 | この結果が検証済みレジャーの結果であるかどうか。`false`の場合、結果は暫定的です。`true`の場合、結果は最終結果です。 |
XRP Ledgerは共有システムとなっていて、すべてのデータが公開された形で正確に記録され、データはそれぞれ新しい[レジャーバージョン](ledgers.html)で安全に更新されます。誰もが任意のトランザクションの結果を確認し、[トランザクションメタデータ](transaction-metadata.html)によってその実行内容を確認できます。
このドキュメントでは、トランザクションの結果がもたらされた理由を把握する方法について、詳細に説明します。エンドユーザー向けには、トランザクションの処理内容を表示するとわかりやすいです。例えば、[XRPチャートを使用して、記録されたトランザクションについての説明を英語で参照](https://xrpcharts.ripple.com/#/transactions/)できます。
## 前提条件
これらの手順で説明されているトランザクションの結果を理解するには、以下が必要となります。
- 理解する対象となるトランザクションがわかっている。トランザクションの[識別用ハッシュ][]がわかっていれば、それによりトランザクションを検索できます。また、最近のレジャーで実行されたトランザクションまたは特定のアカウントに最後に影響を及ぼしたトランザクションを確認することもできます。
- 信頼できる情報と、トランザクションの送信日時に関する必要な履歴を提供する`rippled`サーバーにアクセスできる。
- 最近送信したトランザクションの結果を確認する場合、トランザクションの送信時に使用したサーバーがネットワークと同期されていれば、そのサーバーにアクセスできるだけで十分です。
- 古いトランザクションの結果については、[全履歴を記録するサーバー](ledger-history.html#すべての履歴)を使用できます。
**ヒント:** この他にも、[Data API](data-api.html)やエクスポートされた他のデータベースを使用するなど、XRP Ledgerからトランザクションのデータを照会する方法があります。ただし、これらのインターフェイスは正式なものではありません。このドキュメントでは、最も直接的で信頼できる結果を得るために、`rippled` APIを直接使用してデータを確認する方法を説明します。
## 1. トランザクションステータスの取得
トランザクションが成功したか失敗したかを確認するには、2つの問いが必要です。
1. トランザクションが検証済みレジャーに記録されたか。
2. 記録されていた場合、結果としてレジャーの状態はどのように変化したか。
検証済みレジャーにトランザクションが記録されていたかどうかを確認するには、通常、トランザクションが記録されている可能性のあるすべてのレジャーにアクセスする必要があります。最も簡単で確実な方法は、[全履歴を記録するサーバー](ledger-history.html#すべての履歴)でトランザクションを検索する方法です。[txメソッド][]、[account_txメソッド][]またはその他の`rippled`からの応答を使用します。コンセンサスにより検証されたレジャーバージョンがこの応答に使用されていることを示す`"validated": true`を検索します。
- 結果に`"validated": true`がない場合は、その結果は一時的である可能性があり、トランザクションの結果が最終的なものであるかどうかを知るには、レジャーが検証されるまで待機する必要があります。
- 結果に目的のトランザクションが含まれていない場合、または`txnNotFound`エラーが返される場合は、サーバーにある利用可能な履歴に保存されているどのレジャーにもそのトランザクションはありません。ただし、このことだけでトランザクションが失敗したかどうかを判断できないことがあります。サーバーに保存されていない検証済みレジャーバージョンにトランザクションが記録されている、または今後検証されるレジャーにトランザクションが記録されている場合があるためです。以下を把握することで、トランザクションが記録されるレジャーの範囲を制限することができます。
- トランザクションが記録されている可能性のある最古のレジャー。つまり、**トランザクションを初めて送信した _後に_ 最初に検証されるレジャー**。
- トランザクションが記録されている可能性のある最新のレジャー。つまり、トランザクションの`LastLedgerSequence`フィールドで定義されるレジャー
以下の例では、成功したトランザクションが[txメソッド][]によって返され、検証済みレジャーバージョンに記録されています。わかりやすくするために、JSON応答のフィールドの順序を並べ替え、一部を省略しています。
```json
"hash": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7",
"meta": {
...
"TransactionResult": "tesSUCCESS"
},
"validated": true
{
"TransactionType": "AccountSet",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Sequence": 376,
"hash": "017DED8F5E20F0335C6F56E3D5EE7EF5F7E83FB81D2904072E665EEA69402567",
... (省略) ...
"meta": {
"AffectedNodes": [
... (省略) ...
],
"TransactionResult": "tesSUCCESS"
},
"ledger_index": 46447423,
"validated": true
}
```
この例では、rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpnというアドレスを持つ[アカウント](accounts.html)が、[シーケンス番号][] 376を使用して、[AccountSetトランザクション][]を送信したことを示しています。トランザクションの[識別用ハッシュ][]は`017DED8F5E20F0335C6F56E3D5EE7EF5F7E83FB81D2904072E665EEA69402567`で、その[結果](transaction-results.html)は`tesSUCCESS`です。トランザクションは、検証済みのレジャーバージョン46447423に記録されたため、結果は最終的なものです。
### ケース: 検証済みレジャーに記録されていない
**トランザクションが検証済みレジャーに記録されていない場合は、共有XRP Ledgerの状態には _いかなる_ 影響も及ぼしません。** 今後レジャーに記録されるトランザクションの失敗が[_最終的_](finality-of-results.html)となる場合、その失敗が将来影響を及ぼすことはありません。
トランザクションの失敗が最終的でない場合は、 _将来の_ 検証済みレジャーに記録される可能性があります。トランザクションを現在のオープンレジャーに適用して得た暫定的な結果から、トランザクションが最終レジャーに及ぼすと思われる影響を事前に確認できます。ただし、実際の結果は[さまざまな要因](finality-of-results.html#未確定の結果はどのように変更できますか)によって変わる場合があります。
### ケース: 検証済みレジャーに記録されている
トランザクションが検証済みレジャーに記録 _されている_ 場合、[トランザクションメタデータ](transaction-metadata.html)にはトランザクションの処理結果として、レジャーの状態に対して行われたすべての変更を網羅したレポートが含まれます。メタデータの`TransactionResult`フィールドには、以下のような、結果を要約した[トランザクション結果コード](transaction-results.html)が含まれます。
- コード`tesSUCCESS`は、トランザクションが、おおよそ成功したことを示します。
- `tec`-クラスコードは、トランザクションが失敗したことを示します。このことがレジャーの状態に及ぼす影響は、XRP[トランザクションコスト](transaction-cost.html)を消却し、場合によっては[有効期限切れのオファー](offers.html#オファーの有効期限)の削除および[Payment Channelの閉鎖](payment-channels.html#payment-channelのライフサイクル)などのブックキーピングを行うことだけです。
- どのレジャーにもその他のコードは表示されません。
結果コードは、トランザクションの結果の要約にすぎません。トランザクションの実行内容を詳しく理解するには、トランザクションの指示とトランザクションの実行前のレジャーの状態に照らして残りのメタデータを確認する必要があります。
## 2. メタデータの解釈
トランザクションメタデータは、以下に示すフィールドをはじめとして、トランザクションがレジャーに適用された方法を _正確に_ 示します。
{% include '_snippets/tx-metadata-field-table.md' %} <!--_ -->
ほとんどのメタデータは、[`AffectedNodes`配列](transaction-metadata.html#affectednodes)に含まれています。この配列で探す対象は、トランザクションのタイプによって異なります。ほぼすべてのトランザクションが、送金元の[AccountRootオブジェクト][]を変更してXRP[トランザクションコスト](transaction-cost.html)を消却し、[アカウントのシーケンス番号](basic-data-types.html#アカウントシーケンス)を増やします。
**情報:** このルールの例外として[疑似トランザクション](pseudo-transaction-types.html)があります。このトランザクションは実在するアカウントから送信されないため、AccountRootオブジェクトを変更しません。その他の例外として、AccountRootオブジェクトの`Balance`フィールドを変更せずに、AccountRootオブジェクトを変更するトランザクションがあります。[Free Key Resetトランザクション](transaction-cost.html#key-resetトランザクション)の場合、送金元のXRP残高は変わりません。トランザクションによって消却される金額と同額のXRPをアカウントが受け取る場合ただし、このようなことはほとんどありません、そのアカウントの正味残高は変わりません。XRPを受領したアカウントに関係なくトランザクションコストはメタデータの別の場所に反映されます。
以下は、上記のステップ1からの応答全文例です。レジャーに対して行われた変更を把握できるか確認してください。
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
"Flags": 2147483648,
"LastLedgerSequence": 46447424,
"Sequence": 376,
"SigningPubKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
"TransactionType": "AccountSet",
"TxnSignature": "30450221009B2910D34527F4EA1A02C375D5C38CF768386ACDE0D17CDB04C564EC819D6A2C022064F419272003AA151BB32424F42FC3DBE060C8835031A4B79B69B0275247D5F4",
"date": 608257201,
"hash": "017DED8F5E20F0335C6F56E3D5EE7EF5F7E83FB81D2904072E665EEA69402567",
"inLedger": 46447423,
"ledger_index": 46447423,
"meta": {
"AffectedNodes": [
{
"ModifiedNode": {
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
"FinalFields": {
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"AccountTxnID": "017DED8F5E20F0335C6F56E3D5EE7EF5F7E83FB81D2904072E665EEA69402567",
"Balance": "396015164",
"Domain": "6D64756F31332E636F6D",
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
"Flags": 8519680,
"MessageKey": "0000000000000000000000070000000300",
"OwnerCount": 9,
"Sequence": 377,
"TransferRate": 4294967295
},
"PreviousFields": {
"AccountTxnID": "E710CADE7FE9C26C51E8630138322D80926BE91E46D69BF2F36E6E4598D6D0CF",
"Balance": "396015176",
"Sequence": 376
},
"PreviousTxnID": "E710CADE7FE9C26C51E8630138322D80926BE91E46D69BF2F36E6E4598D6D0CF",
"PreviousTxnLgrSeq": 46447387
}
}
],
"TransactionIndex": 13,
"TransactionResult": "tesSUCCESS"
},
"validated": true
}
```
この[no-opトランザクション](cancel-or-skip-a-transaction.html)によって行われた _唯一_ の変更は[AccountRootオブジェクト][]の更新で、送金元のアカウントは以下のように表されています。
- `Sequence`値は376から377に増えます。
- このアカウントのXRPの`Balance`は、`396015176`から`396015164`[XRPのdrop数](basic-data-types.html#xrp)に変わります。残高から差し引かれた12dropは[トランザクションコスト](transaction-cost.html)で、このトランザクションの`Fee`フィールドに指定されています。
- このトランザクションが、このアドレスから送信された最新のトランザクションとなったことを反映して[`AccountTxnID`](transaction-common-fields.html#accounttxnid)が変わります。
- このアカウントに影響を及ぼした以前のトランザクションは、レジャーバージョン46447387で実行されたトランザクション`E710CADE7FE9C26C51E8630138322D80926BE91E46D69BF2F36E6E4598D6D0CF`で、`PreviousTxnID`および`PreviousTxnLgrSeq`フィールドに指定されています。(このことは、アカウントのトランザクション履歴をさかのぼる際に役立つ場合があります。)
**注記:** メタデータには明示的に示されませんが、トランザクションがレジャーオブジェクトを変更すると、必ずそのオブジェクトの`PreviousTxnID`および`PreviousTxnLgrSeq`フィールドが現在のトランザクションの情報で更新されます。同じ送金元の複数のトランザクションが1つのレジャーバージョンに含まれている場合、最初のトランザクション以降の各トランザクションは、これらすべてのトランザクションを記録するレジャーバージョンの[レジャーインデックス](basic-data-types.html#レジャーインデックス)を値とする`PreviousTxnLgrSeq`を提供します。
rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpnのアカウントの`ModifiedNode`エントリーが`AffectedNodes`配列の唯一のオブジェクトであるため、このトランザクションの結果として、このレジャーに対してその他の変更は行われませんでした。
**ヒント:** トランザクションによってXRPが送信または受信される場合、送金元の残高の変動額はトランザクションコストと合算され、`Balance`フィールドの正味金額は1回で変更されます。例えば、1XRP1,000,000dropを送信し、トランザクションコストで10drop消却した場合、メタデータには`Balance`が1,000,010XRPのdrop数減少したと示されます。
### 汎用的なブックキーピング
ほぼすべてのトランザクションにより、以下のような変更が行われます。
- **シーケンスとトランザクションコストの変更:** 送金元のシーケンス番号を増やし、トランザクションコストの支払いに使用するXRPを消却するために、[前述のとおりどのトランザクション(疑似トランザクションを除く)も、送金元の`AccountRoot`オブジェクトに変更を加えます](#2-メタデータの解釈)。
- **アカウントのスレッド化:** オブジェクトを作成する一部のトランザクションでは、目的の受取人または宛先のアカウントの[AccountRootオブジェクト](accountroot.html)も変更し、そのアカウントに関連する何らかの要素が変更されたことを示します。このアカウントを「タグ付け」する手法で、オブジェクトの`PreviousTxnID`および`PreviousTxnLgrSeq`フィールドのみを変更します。これにより、これらのフィールドに指定されたトランザクションの「スレッド」を追跡することで、アカウントが保持するアカウントのトランザクション履歴を効率よく検索することができます。
- **ディレクトリーの更新:** レジャーオブジェクトを作成または削除するトランザクションは、多くの場合[DirectoryNodeオブジェクト](directorynode.html)を変更して、どのオブジェクトが存在しているかを追跡します。また、トランザクションによって、アカウントの[所有者準備金](reserves.html#所有者準備金)に反映されるオブジェクトが追加されると、所有者の[AccountRootオブジェクト][]の`OwnerCount`が増加します。オブジェクトを削除すると、`OwnerCount`が減少します。
アカウントの`OwnerCount`を増やす例:
```json
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"Balance": "9999999990",
"Flags": 0,
"OwnerCount": 1,
"Sequence": 2
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05",
"PreviousFields": {
"Balance": "10000000000",
"OwnerCount": 0,
"Sequence": 1
},
"PreviousTxnID": "B24159F8552C355D35E43623F0E5AD965ADBF034D482421529E2703904E1EC09",
"PreviousTxnLgrSeq": 16154
}
}
```
多くのトランザクションのタイプで、[DirectoryNodeオブジェクト](directorynode.html)が作成または変更されます。これらのオブジェクトは、ブックキーピングに使用します。アカウントが所有するすべてのオブジェクト、またはすべてのオファーを追跡して、同じ為替レートで通貨を交換します。トランザクションがレジャーに新しいオブジェクトを作成した場合、トランザクションは既存のDirectoryNodeオブジェクトにエントリーを追加するか、別のDirectoryNodeオブジェクトを追加してディレクトリーの別のページを表さなければならないことがあります。トランザクションがレジャーからオブジェクトを削除した場合、トランザクションは不要となった1つ以上のDirectoryNodeオブジェクトを削除しなければならないことがあります。
新しいオファーディクトリーを表すCreatedNodeの例:
```json
{
"CreatedNode": {
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "F60ADF645E78B69857D2E4AEC8B7742FEABC8431BD8611D099B428C3E816DF93",
"NewFields": {
"ExchangeRate": "4E11C37937E08000",
"RootIndex": "F60ADF645E78B69857D2E4AEC8B7742FEABC8431BD8611D099B428C3E816DF93",
"TakerPaysCurrency": "0000000000000000000000004254430000000000",
"TakerPaysIssuer": "5E7B112523F68D2F5E879DB4EAC51C6698A69304"
}
}
},
```
トランザクションメタデータを処理する際に探すその他の項目は、トランザクションのタイプによって異なります。
### 支払い
[Paymentトランザクション][]はXRP間の直接トランザクション、[複数通貨間の支払い](cross-currency-payments.html)、または[XRP以外の発行済み通貨](issued-currencies.html)での直接トランザクションを表します。発行済み通貨からXRPへのトランザクション、またはXRPから発行済み通貨へのトランザクションなど、XRP間の直接トランザクション以外はすべて[partial payment](partial-payments.html)が可能です。
XRPの額は、`AccountRoot`オブジェクトの`Balance`フィールドで追跡されます。XRPは[Escrowオブジェクト](escrow-object.html)および[PayChannelオブジェクト](paychannel.html)にも存在する可能性がありますが、Paymentトランザクションがそれらに影響を及ぼすことはありません。
支払いでいくら支払われたかを確認するには、必ず[delivered_amountフィールド](partial-payments.html#delivered_amountフィールド)を使用する必要があります。
支払いにLedgerEntryTypeが`AccountRoot``CreatedNode`が含まれている場合は、その支払いによってレジャーの[新しいアカウントへの資金供給](accounts.html#アカウントの作成)が行われたことを意味します。
#### 発行済み通貨での支払い
発行済み通貨を利用する支払いは、多少複雑です。
発行済み通貨残高の変更は、[トラストライン](trust-lines-and-issuing.html)を表す[RippleStateオブジェクト](ripplestate.html)にすべて反映されます。一方の当事者のトラストラインで残高が増加すると、相手側当事者の残高は同じ額だけ減少すると考えられます。このことは、メタデータには、RippleStateオブジェクトの共有`Balance`に対する1回の変更としてのみ記録されます。この変更が「増加」または「減少」のどちらで記録されるかは、どちらのアカウントのアドレスが数値として大きいかによって決まります。
1回の支払いは、複数のトラストラインとオーダーブックで構成される長い[パス](paths.html)をたどる場合があります。間接的に当事者間を接続する複数のトラストラインの残高を変更するプロセスを[Rippling](rippling.html)と呼びます。トランザクションの`Amount`フィールドに指定された`issuer`に応じて、支払先アカウントに結び付けられている複数のトラストライン(`RippleState`アカウント)で支払額を分割することもできます。
**ヒント:** 変更されたオブジェクトがメタデータに表示される順序は、支払いを処理するときにこれらのオブジェクトにアクセスした順序とは必ずしも一致しません。`AffectedNodes`メンバーを並べ替えて資金がレジャーまでたどったパスを再構成すると、支払いの実行の詳細を把握しやすくなります。
複数通貨間の支払いでは、[オファー](offer.html)の一部または全額を消費して、通貨コードとイシュアーが異なる通貨間で変更が行われます。トランザクションで`Offer`タイプの`DeletedNode`オブジェクトが示される場合は、全額が消費されたオファーを示しているか、または処理の時点で[期限切れになるか、または資金化されない](offers.html#オファーのライフサイクル)ことがわかったオファーを示している可能性があります。トランザクションで`Offer`タイプの`ModifiedNode`が示される場合は、オファーの一部が消費されたことを示します。
[トラストラインの`QualityIn`および`QualityOut`設定](trustset.html)は、トラストラインの一方の側における発行済み通貨の額に影響を与える可能性があるため、残高の数値の変化は、送金元におけるその通貨の額と異なります。`delivered_amount`は、受取人による評価額でいくら送金されたのかを示します。
送金額と受取額が[発行済み通貨の精度](currency-formats.html#発行済み通貨の精度)の範囲外である場合は、一方のトランザクションで0に丸められる金額が、他方から引き出される可能性があります。そのため、両当事者が、お互いの残高に10<sup>16</sup>倍の差があるときに取引をすると、丸めることによって少額の発行済み通貨が「作成」または「消却」される可能性があります。XRPは丸められないので、XRPではこの状況は発生しません。
[パス](paths.html)の長さに応じて、複数通貨間の支払いのメタデータは _長く_ なります。例えば、[トランザクション8C55AFC2A2AA42B5CE624AEECDB3ACFDD1E5379D4E5BF74A8460C5E97EF8706B](https://xrpcharts.ripple.com/#/transactions/8C55AFC2A2AA42B5CE624AEECDB3ACFDD1E5379D4E5BF74A8460C5E97EF8706B)では、rHaaans...が発行した2.788 GCBを送金しXRPを支払いますが、2人のイシュアーのUSDを経由し、2つのアカウントにXRPを支払います。r9ZoLsJからのEURをETHと交換する資金供給されていないオファーを削除し、変更された合計17の異なるレジャーオブジェクトのブックキーピングを行います。
### オファー
[OfferCreateトランザクション][]では、成立した額や、トランザクションが`tfImmediateOrCancel`などのフラグを使用したかどうかによって、レジャーにオブジェクトが作成される場合と作成されない場合があります。トランザクションがレジャーのオーダーブックに新しいオファーを追加したどうかを確認するには、LedgerEntryTypeが`Offer``CreatedNode`エントリーを探します。例:
```json
{
"CreatedNode": {
"LedgerEntryType": "Offer",
"LedgerIndex": "F39B13FA15AD2A345A9613934AB3B5D94828D6457CCBB51E3135B6C44AE4BC83",
"NewFields": {
"Account": "rETSmijMPXT9fnDbLADZnecxgkoJJ6iKUA",
"BookDirectory": "CA462483C85A90DB76D8903681442394D8A5E2D0FFAC259C5B0C59269BFDDB2E",
"Expiration": 608427156,
"Sequence": 1082535,
"TakerGets": {
"currency": "EUR",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "2157.825"
},
"TakerPays": "7500000000"
}
}
}
```
タイプ`Offer``ModifiedNode`は、成立し、かつ一部が消費されたオファーを示します。1つのトランザクションで多数のオファーを消費できます。2種類の発行済み通貨を交換するオファーが、[オートブリッジング](autobridging.html)によってXRPを交換するオファーを消費することもあります。両替取引のすべてまたは一部をオートブリッジングできます。
LedgerEntryTypeが`Offer``DeletedNode`は、すべて消費された成立オファー、処理の時点で[期限切れになるか、または資金化されない](offers.html#オファーのライフサイクル)ことがわかったオファー、または新しいオファーを発行する過程でキャンセルされたオファーを示すことができます。キャンセルされたオファーは識別できます。これは、キャンセルされたオファーを発行した`Account`は、そのオファーを削除するトランザクションの送信元であるためです。
削除されたオファーの例:
```json
{
"DeletedNode": {
"FinalFields": {
"Account": "rETSmijMPXT9fnDbLADZnecxgkoJJ6iKUA",
"BookDirectory": "CA462483C85A90DB76D8903681442394D8A5E2D0FFAC259C5B0C595EDE3E1EE9",
"BookNode": "0000000000000000",
"Expiration": 608427144,
"Flags": 0,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "0CA50181C1C2A4D45E9745F69B33FA0D34E60D4636562B9D9CDA1D4E2EFD1823",
"PreviousTxnLgrSeq": 46493676,
"Sequence": 1082533,
"TakerGets": {
"currency": "EUR",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "2157.675"
},
"TakerPays": "7500000000"
},
"LedgerEntryType": "Offer",
"LedgerIndex": "9DC99BF87F22FB957C86EE6D48407201C87FBE623B2F1BC4B950F83752B55E27"
}
}
```
オファーでは、両方のタイプの[DirectoryNodeオブジェクト](directorynode.html)を作成、削除、変更して、オファーの発行者と、どのオファーがどのような為替レートで利用可能になっているのかを追跡できます。一般的に、ユーザーがこのブックキーピングに細かな注意を払う必要はありません。
削除するオファーがなかった場合でも、[OfferCancelトランザクション][]には、コード`tesSUCCESS`が含まれる可能性があります。トランザクションが実際にオファーを削除したことを確認するには、LedgerEntryTypeが`Offer``DeletedNode`を探します。削除されていなかった場合は、そのオファーは以前のトランザクションによってすでに削除された可能性があります。またはOfferCancelトランザクションで、`OfferSequence`フィールドに誤ったシーケンス番号が使用された可能性があります。
OfferCreateトランザクションが、タイプが`RippleState``CreatedNode`を示す場合は、取引で受け取った発行済み通貨を保持するために、[オファーがトラストラインを作成した](offers.html#オファーとトラスト)ことを示しています。
### Escrow
成功した[EscrowCreateトランザクション][]は、レジャーに[Escrowオブジェクト](escrow-object.html)を作成します。LedgerEntryTypeが`Escrow``CreatedNode`エントリーを探します。`NewFields`には、escrowに預託されたXRPと同じ`Amount`と、指定したその他のプロパティが示されます。
成功したEscrowCreateトランザクションは、送金元から同じ額のXRPを引き出します。最終的なフィールドの`Account`がトランザクションの指示にある`Account`のアドレスと一致する、LedgerEntryTypeが`AccountRoot``ModifiedNode`を探します。XRPの`Balance`は、トランザクションコストの支払いのためにXRPが消却されたのに加えてXRPがescrowに預託されたため減少します。
成功した[EscrowFinishトランザクション][]は、受取人の`AccountRoot`を変更して(`Balance`フィールドのXRP残高を増やし、`Escrow`オブジェクトを削除し、escrow作成者の所有者数を減らします。escrow作成者、受取人および終了者をすべて異なるアカウントにしても、同じアカウントにしてもかまわないため、結果としてLedgerEntryTypeが`AccountRoot``ModifiedNode`オブジェクトが _13個_ になる可能性があります。XRPがescrowの最初の作成者に返されることを除けば、成功した[EscrowCancelトランザクション][]は極めて類似しています。
EscrowFinishは、escrowの条件を満たす場合にのみ成功し、EscrowCancelはEscrowオブジェクトの期限が前のレジャーの閉鎖時刻よりも前である場合にのみ成功します。
Escrowトランザクションでは、関係する送金元の所有者準備金やアカウントのディレクトリーを調整するために通常の[ブックキーピング](#汎用的なブックキーピング)も行われます。
次に示すコードの抜粋では、r9UUEX...の残高が10億XRP増加し、その所有者の数が1人減少しています。これは、そのアカウントからの自分自身へのescrowが正常に終了したためです。[第三者がescrowを完了した](https://xrpcharts.ripple.com/#/transactions/C4FE7F5643E20E7C761D92A1B8C98320614DD8B8CD8A04CFD990EBC5A39DDEA2)ため`Sequence`番号は変更されません。
```json
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9UUEXn3cx2seufBkDa8F86usfjWM6HiYp",
"Balance": "1650000199898000",
"Flags": 1048576,
"OwnerCount": 11,
"Sequence": 23
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "13FDBC39E87D9B02F50940F9FDDDBFF825050B05BE7BE09C98FB05E49DD53FCA",
"PreviousFields": {
"Balance": "650000199898000",
"OwnerCount": 12
},
"PreviousTxnID": "D853342BC27D8F548CE4D7CB688A8FECE3229177790453BA80BC79DE9AAC3316",
"PreviousTxnLgrSeq": 41005507
}
},
{
"DeletedNode": {
"FinalFields": {
"Account": "r9UUEXn3cx2seufBkDa8F86usfjWM6HiYp",
"Amount": "1000000000000000",
"Destination": "r9UUEXn3cx2seufBkDa8F86usfjWM6HiYp",
"FinishAfter": 589075200,
"Flags": 0,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "D5FB1C7D18F931A4FBFA468606220560C17ADF6DE230DA549F4BD11A81F19DFC",
"PreviousTxnLgrSeq": 35059548
},
"LedgerEntryType": "Escrow",
"LedgerIndex": "62F0ABB58C874A443F01CDCCA18B12E6DA69C254D3FB17A8B71CD8C6C68DB74D"
}
},
```
### Payment Channel
Payment Channelの作成時に、LedgerEntryTypeが`PayChannel``CreatedNode`を探します。また、送金元の残高の減少を示す、LedgerEntryTypeが`AccountRoot``ModifiedNode`も探す必要があります。アドレスが送金元に一致することを確認するために`FinalFields``Account`フィールドを探し、XRP残高の変化を確認するために`Balance`フィールドの差異を確認します。
[fixPayChanRecipientOwnerDir Amendment](known-amendments.html#fixpaychanrecipientownerdir) :not_enabled: が有効な場合は、メタデータは宛先のアカウントの[所有者ディレクトリー](directorynode.html)を変更して、新しく作成されるPayment Channelをリストで示す必要もあります。これにより、アカウントがオープンPayment Channelの受取人である場合に、そのアカウントが[削除される](accounts.html#アカウントの削除)ことを防ぎます。fixPayChanRecipientOwnerDir Amendmentが有効になる前にPayment Channelが作成された場合は、アカウントを削除できます。
Payment Channelの閉鎖を要求する方法は、Payment Channelの不変の`CancelAfter`時刻作成時にのみ設定されます以外にもいくつかあります。トランザクションでChannelの閉鎖をスケジュールする場合は、そのChannel用にLedgerEntryTypeが`PayChannel``ModifiedNode`エントリーがあり、`FinalFields``Expiration`フィールドには閉鎖時刻が新たに追加されています。以下の例は、送金元がクレームを清算せずにChannelを閉鎖するよう要求した場合に`PayChannel`に対して行われる変更を示します。
```json
{
"ModifiedNode": {
"FinalFields": {
"Account": "rNn78XpaTXpgLPGNcLwAmrcS8FifRWMWB6",
"Amount": "1000000",
"Balance": "0",
"Destination": "rwWfYsWiKRhYSkLtm3Aad48MMqotjPkU1F",
"Expiration": 608432060,
"Flags": 0,
"OwnerNode": "0000000000000002",
"PublicKey": "EDEACA57575C6824FC844B1DB4BF4AF2B01F3602F6A9AD9CFB8A3E47E2FD23683B",
"SettleDelay": 3600,
"SourceTag": 1613739140
},
"LedgerEntryType": "PayChannel",
"LedgerIndex": "DC99821FAF6345A4A6C41D5BEE402A7EA9198550F08D59512A69BFC069DC9778",
"PreviousFields": {},
"PreviousTxnID": "A9D6469F3CB233795B330CC8A73D08C44B4723EFEE11426FEE8E7CECC611E18E",
"PreviousTxnLgrSeq": 41889092
}
}
```
### TrustSetトランザクション
TrustSetトランザクションは、[`RippleState`オブジェクト](ripplestate.html)として表される[トラストライン](trust-lines-and-issuing.html)を作成、変更、または削除します。1つの`RippleState`オブジェクトに、関与する両当事者の設定が含まれます。これには両当事者の制限や[Ripplingの設定](rippling.html)などがあります。トラストラインの作成と変更によって[送金元の所有者準備金と所有者ディレクトリーの調整](#汎用的なブックキーピング)も行われます。
以下の例は、**rf1BiG...** が**rsA2Lp...** によって発行されたUSDを最大110 USDまで保持するという新しいトラストラインを示します。
```json
{
"CreatedNode": {
"LedgerEntryType": "RippleState",
"LedgerIndex": "9CA88CDEDFF9252B3DE183CE35B038F57282BC9503CDFA1923EF9A95DF0D6F7B",
"NewFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"value": "110"
},
"LowLimit": {
"currency": "USD",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "0"
}
}
}
}
```
### その他のトランザクション
その他のほとんどのトランザクションは、特定のタイプのレジャーエントリーを作成し、[送金元の所有者準備金と所有者ディレクトリーの調整](#汎用的なブックキーピング)を行います。
- [AccountSetトランザクション][]は、送金元の既存の[AccountRoot object][]を変更し、指定されたとおりに設定とフラグを変更します。
- [DepositPreauthトランザクション][]は、特定の送金元の[DepositPreauthオブジェクト](depositpreauth-object.html)を追加または削除します。
- [SetRegularKeyトランザクション][]は、送金元の[AccountRootオブジェクト][]を変更し、指定されたとおりに`RegularKey`フィールドを変更します。
- [SignerListSetトランザクション][]は、[SignerListオブジェクト](signerlist.html)を追加、削除、または置換します。
### 疑似トランザクション
[疑似トランザクション](pseudo-transaction-types.html)にもメタデータがありますが、これらのトランザクションは通常のトランザクションのすべてのルールに従うとは限りません。これらのトランザクションは、実在のアカウントには関連付けられていないため(この`Account`の値は、[base58エンコード形式の数字の0](accounts.html#特別なアドレス)です、レジャーのAccountRootオブジェクトを変更して`Sequence`シーケンス番号を増やしたり、XRPを消却したりしません。疑似トランザクションは、特別なレジャーオブジェクトに対して特定の変更のみを行います。
- [EnableAmendment疑似トランザクション][]は、[Amendmentレジャーオブジェクト](amendments-object.html)を変更して、有効なAmendment、過半数の支持を得ている保留中のAmendment、および保留中の期間を追跡します。
- [SetFee疑似トランザクション][]は、[FeeSettingsレジャーオブジェクト](feesettings.html)を変更して、[トランザクションコスト](transaction-cost.html)および[必要準備金](reserves.html)のベースレベルを変更します。
## 関連項目
- **コンセプト:**
- [結果のファイナリティー](finality-of-results.html) - トランザクションの成功また失敗が最終的なものとなるタイミングを判断する方法。(簡単な説明: トランザクションが検証済みレジャーにある場合は、その結果とメタデータは最終的なものです。)
- **チュートリアル:**
- [信頼できるトランザクションの送信](reliable-transaction-submission.html)
- [WebSocketを使用した着信ペイメントの監視](monitor-incoming-payments-with-websocket.html)
- **リファレンス:**
- [レジャーオブジェクトタイプのリファレンス](ledger-object-types.html) - レジャーオブジェクトの使用可能なすべてのタイプのフィールド
- [トランザクションのメタデータ](transaction-metadata.html) - メタデータフォーマットとメタデータに表示されるフィールドの概要
- [トランザクションの結果](transaction-results.html) - トランザクションのすべての結果コードを掲載した表一覧
<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}

View File

@@ -0,0 +1,601 @@
# WebSocketを使用した着信ペイメントの監視
このチュートリアルでは、[WebSocket `rippled` API](rippled-api.html)を使用して、着信[ペイメント](payment-types.html)を監視する方法を説明します。すべてのXRP Ledgerトランザクションは公開されているため、誰もが任意のアドレスへの着信ペイメントを監視できます。
WebSocketは、クライアントとサーバーが1つの接続を確立し、その接続を経由して両方向にメッセージを送信するモデルに従います。この接続は、明示的に閉じるまたは接続に障害が発生するまで続きます。これは、要求ごとにクライアントが新しい接続を開いて閉じるHTTPベースのAPIモデルJSON-RPCやRESTful APIなどとは対照的です[¹](#footnote-1)<a id="from-footnote-1"></a>
**ヒント:** このページの例はJavaScriptを使用しているため、Webブラウザーでネイティブに実行できます。JavaScriptで開発している場合は、[JavaScript向けRippleAPIライブラリ](rippleapi-reference.html)も利用すると、一部の作業を簡素化できます。このチュートリアルでは、RippleAPIを使用できないその他のプログラミング言語にステップを適合できるよう、RippleAPIを使用 _しない_ でトランザクションを監視する方法を説明します。
## 前提条件
- このページの例では、すべての主要な最新ブラウザーで使用できるJavaScriptおよびWebSocketプロトコルを使用しています。JavaScriptにある程度習熟し、WebSocketクライアントを使用する他のプログラミング言語の専門知識があれば、選択する言語に手順を適合させながら進めていくことができます。
- 安定したインターネット接続と`rippled`サーバーへアクセスが必要です。埋め込まれている例では、Rippleの公開サーバーのプールに接続します。[独自の`rippled`サーバーを運用](install-rippled.html)する場合は、ローカルでそのサーバーに接続することもできます。
- 丸め方によるエラーを発生させることなくXRPの価値を適切に処理するには、64ビット符号なし整数で計算できる数値タイプを使用できる必要があります。このチュートリアルの例では、[big.js](https://github.com/MikeMcl/big.js/)を使用しています。[発行済み通貨](issued-currencies.html)を使用する場合は、さらに高い精度が求められます。詳細は、[通貨の精度](currency-formats.html#xrpの精度)を参照してください。
<!-- Helper for interactive tutorial breadcrumbs -->
<script type="application/javascript" src="assets/vendor/big.min.js"></script>
<script type="application/javascript" src="assets/js/interactive-tutorial.js"></script>
<script type="application/javascript">
// Helper stuff for this interactive tutorial specifically
function writeToConsole(console_selector, message) {
let write_msg = "<div class='console-entry'>" + message + "</div>"
$(console_selector).find(".placeholder").remove()
$(console_selector).append(write_msg)
// TODO: JSON pretty-printing, maybe w/ multiple input args?
}
</script>
{% set n = cycler(* range(1,99)) %}
## {{n.next()}}. XRP Ledgerへの接続
着信ペイメントを監視する最初のステップとして、XRP Ledger、つまり`rippled`サーバーに接続します。
以下のJavaScriptコードでは、Rippleの公開サーバーのクラスターの1つに接続します。その後、コンソールにメッセージを記録し、[pingメソッド][]を使用して要求を送信します。次に、サーバー側からのメッセージを受信するときに、ハンドラーを設定してコンソールに再度メッセージを記録します。
```js
const socket = new WebSocket('wss://s.altnet.rippletest.net:51233')
socket.addEventListener('open', (event) => {
// This callback runs when the connection is open
console.log("Connected!")
const command = {
"id": "on_open_ping_1",
"command": "ping"
}
socket.send(JSON.stringify(command))
})
socket.addEventListener('message', (event) => {
console.log('Got message from server:', event.data)
})
socket.addEventListener('close', (event) => {
// Use this event to detect when you have become disconnected
// and respond appropriately.
console.log('Disconnected...')
})
```
上記の例では、[Test Net](xrp-test-net-faucet.html)上にあるRippleの公開APIサーバーの1つに対して、安全な接続`wss://`)を開きます。代わりにデフォルトの構成を使用してローカルで運用している`rippled`サーバーに接続するには、最初の行に以下を使用して、ローカルのポート**6006**で _安全ではない_ 接続(`ws://`)を開きます。
```js
const socket = new WebSocket('ws://localhost:6006')
```
**ヒント:** デフォルトでは、ローカル`rippled`サーバーに接続することで、インターネット上の公開サーバーに接続する際に使用できる[パブリックメソッド](public-rippled-methods.html)以外に、すべての[管理メソッド](admin-rippled-methods.html)と、[server_info][server_infoメソッド]などの一部の応答に含まれる管理者専用データを利用できます。
例:
{{ start_step("Connect") }}
<button id="connect-button" class="btn btn-primary">Connect</button>
<strong>Connection status:</strong>
<span id="connection-status">Not connected</span>
<div id='loader-{{n.current}}' style="display: none;"><img class='throbber' src="assets/img/xrp-loader-96.png"></div>
<h5>Console:</h5>
<div class="ws-console" id="monitor-console-connect"><span class="placeholder">(Log is empty)</span></div>
{{ end_step() }}
<script type="application/javascript">
let socket;
$("#connect-button").click((event) => {
socket = new WebSocket('wss://s.altnet.rippletest.net:51233')
socket.addEventListener('open', (event) => {
// This callback runs when the connection is open
writeToConsole("#monitor-console-connect", "Connected!")
$("#connection-status").text("Connected")
const command = {
"id": "on_open_ping_1",
"command": "ping"
}
socket.send(JSON.stringify(command))
complete_step("Connect")
$("#connect-button").prop("disabled", "disabled")
$("#enable_dispatcher").prop("disabled",false)
})
socket.addEventListener('close', (event) => {
$("#connection-status").text("Disconnected")
$("#connect-button").prop("disabled", false)
})
socket.addEventListener('message', (event) => {
writeToConsole("#monitor-console-connect", "Got message from server: " +
JSON.stringify(event.data))
})
})
</script>
## {{n.next()}}. ハンドラーへの着信メッセージのディスパッチ
WebSocket接続では、複数のメッセージをどちらの方向にも送信することが可能で、要求と応答の間に厳密な1:1の相互関係がないため、各着信メッセージに対応する処理を識別する必要があります。この処理をコーディングする際の優れたモデルとして、「ディスパッチャー」関数の設定が挙げられます。この関数は着信メッセージを読み取り、各メッセージを正しいコードのパスに中継して処理します。メッセージを適切にディスパッチできるように、`rippled`サーバーでは、すべてのWebSocketメッセージで`type`フィールドを使用できます。
- クライアント側からの要求への直接の応答となるメッセージの場合、`type`は文字列の`response`です。この場合、サーバーは以下も提供します。
- この応答に対する要求で指定された`id`に一致する`id`フィールド(応答が順序どおりに到着しない可能性があるため、これは重要です)。
- APIが要求の処理に成功したかどうかを示す`status`フィールド。文字列値`success`は、[成功した応答](response-formatting.html)を示します。文字列値`error`は、[エラー](error-formatting.html)を示します。
**警告:** トランザクションを送信する際、WebSocketメッセージの先頭にある`success``status`は、必ずしもトランザクション自体が成功したことを意味しません。これは、サーバーによって要求が理解されたということのみを示します。トランザクションの実際の結果を確認するには、[トランザクションの結果の確認](look-up-transaction-results.html)を参照してください。
- [サブスクリプション](subscribe.html)からのフォローアップメッセージの場合、`type`は、新しいトランザクション、レジャーまたは検証の通知など、フォローアップメッセージのタイプを示します。または継続している[pathfinding要求](path_find.html)のフォローアップを示します。クライアントがこれらのメッセージを受信するのは、それらをサブスクライブしている場合のみです。
**ヒント:** [JavaScript向けRippleAPI](rippleapi-reference.html)は、デフォルトでこのステップに対応しています。すべての非同期API要求はPromiseを使用して応答を提供します。また[`.on(event, callback)`メソッド](rippleapi-reference.html#listening-to-streams)を使用して、ストリームをリッスンできます。
以下のJavaScriptコードでは、API要求を便利な非同期[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises)に変換するヘルパー関数を定義し、他のタイプのメッセージをグローバルハンドラーにマップするインターフェイスを設定します。
```js
const AWAITING = {}
const handleResponse = function(data) {
if (!data.hasOwnProperty("id")) {
console.error("Got response event without ID:", data)
return
}
if (AWAITING.hasOwnProperty(data.id)) {
AWAITING[data.id].resolve(data)
} else {
console.error("Response to un-awaited request w/ ID " + data.id)
}
}
let autoid_n = 0
function api_request(options) {
if (!options.hasOwnProperty("id")) {
options.id = "autoid_" + (autoid_n++)
}
let resolveHolder;
AWAITING[options.id] = new Promise((resolve, reject) => {
// Save the resolve func to be called by the handleResponse function later
resolveHolder = resolve
try {
// Use the socket opened in the previous example...
socket.send(JSON.stringify(options))
} catch(error) {
reject(error)
}
})
AWAITING[options.id].resolve = resolveHolder;
return AWAITING[options.id]
}
const WS_HANDLERS = {
"response": handleResponse
// Fill this out with your handlers in the following format:
// "type": function(event) { /* handle event of this type */ }
}
socket.addEventListener('message', (event) => {
const parsed_data = JSON.parse(event.data)
if (WS_HANDLERS.hasOwnProperty(parsed_data.type)) {
// Call the mapped handler
WS_HANDLERS[parsed_data.type](parsed_data)
} else {
console.log("Unhandled message from server", event)
}
})
// Demonstrate api_request functionality
async function pingpong() {
console.log("Ping...")
const response = await api_request({command: "ping"})
console.log("Pong!", response)
}
pingpong()
```
{{ start_step("Dispatch Messages") }}
<button id="enable_dispatcher" class="btn btn-primary" disabled="disabled">Enable Dispatcher</button>
<button id="dispatch_ping" class="btn btn-primary" disabled="disabled">Ping!</button>
<h5>Responses</h5>
<div class="ws-console" id="monitor-console-ping"><span class="placeholder">(Log is empty)</span></div>
{{ end_step() }}
<script type="application/javascript">
const AWAITING = {}
const handleResponse = function(data) {
if (!data.hasOwnProperty("id")) {
writeToConsole("#monitor-console-ping", "Got response event without ID:", data)
return
}
if (AWAITING.hasOwnProperty(data.id)) {
AWAITING[data.id].resolve(data)
} else {
writeToConsole("#monitor-console-ping", "Response to un-awaited request w/ ID " + data.id)
}
}
let autoid_n = 0
function api_request(options) {
if (!options.hasOwnProperty("id")) {
options.id = "autoid_" + (autoid_n++)
}
let resolveFunc;
AWAITING[options.id] = new Promise((resolve, reject) => {
// Save the resolve func to be called by the handleResponse function later
resolveFunc = resolve
try {
// Use the socket opened in the previous example...
socket.send(JSON.stringify(options))
} catch(error) {
reject(error)
}
})
AWAITING[options.id].resolve = resolveFunc
return AWAITING[options.id]
}
const WS_HANDLERS = {
"response": handleResponse
}
$("#enable_dispatcher").click((clickEvent) => {
socket.addEventListener('message', (event) => {
const parsed_data = JSON.parse(event.data)
if (WS_HANDLERS.hasOwnProperty(parsed_data.type)) {
// Call the mapped handler
WS_HANDLERS[parsed_data.type](parsed_data)
} else {
writeToConsole("#monitor-console-ping", "Unhandled message from server: " + event)
}
})
complete_step("Dispatch Messages")
$("#dispatch_ping").prop("disabled", false)
$("#tx_subscribe").prop("disabled", false)
})
async function pingpong() {
const response = await api_request({command: "ping"})
writeToConsole("#monitor-console-ping", "Pong! " + JSON.stringify(response))
}
$("#dispatch_ping").click((event) => {
pingpong()
})
</script>
## {{n.next()}}. アカウントのサブスクライブ
トランザクションがアカウントに影響を及ぼすたびに即座に通知を取得するには、[subscribeメソッド][]を使用してアカウントをサブスクライブします。実際には、このアカウントはあなた自身のアカウントでなくてもかまいません。すべてのトランザクションは公開されているため、任意のアカウントで、または複数のアカウントでもサブスクライブできます。
1つ以上のアカウントをサブスクライブした場合、指定したアカウントのいずれかに何らかの影響を及ぼす各検証済みトランザクションについて、`"type": "transaction"`が含まれるメッセージがサーバーから送信されます。これを確認するには、トランザクションメッセージで`"validated": true`を探します。
以下のコードサンプルは、Test Net Faucetの送信側アドレスをサブスクライブします。このコードサンプルでは、前のステップのディスパッチャーにハンドラーを追加することで、該当する各トランザクションのメッセージを記録します。
```js
async function do_subscribe() {
const sub_response = await api_request({
command:"subscribe",
accounts: ["rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM"]
})
if (sub_response.status === "success") {
console.log("Successfully subscribed!")
} else {
console.error("Error subscribing: ", sub_response)
}
}
do_subscribe()
const log_tx = function(tx) {
console.log(tx.transaction.TransactionType + " transaction sent by " +
tx.transaction.Account +
"\n Result: " + tx.meta.TransactionResult +
" in ledger " + tx.ledger_index +
"\n Validated? " + tx.validated)
}
WS_HANDLERS["transaction"] = log_tx
```
以下の例では、別のウィンドウまたは別のデバイスで[Transaction Sender](tx-sender.html)を開くことと、サブスクライブしているアドレスへのトランザクションの送信を試みます。
{{ start_step("Subscribe") }}
<label for="subscribe_address">Test Net Address:</label>
<input type="text" class="form-control" id="subscribe_address" value="rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM">
<button id="tx_subscribe" class="btn btn-primary" disabled="disabled">Subscribe</button>
<h5>Transactions</h5>
<div class="ws-console" id="monitor-console-subscribe"><span class="placeholder">(Log is empty)</span></div>
{{ end_step() }}
<script type="application/javascript">
async function do_subscribe() {
const sub_address = $("#subscribe_address").val()
const sub_response = await api_request({
command:"subscribe",
accounts: [sub_address]
})
if (sub_response.status === "success") {
writeToConsole("#monitor-console-subscribe", "Successfully subscribed!")
} else {
writeToConsole("#monitor-console-subscribe",
"Error subscribing: " + JSON.stringify(sub_response))
}
}
$("#tx_subscribe").click((event) => {
do_subscribe()
complete_step("Subscribe")
$("#tx_read").prop("disabled", false)
})
const log_tx = function(tx) {
writeToConsole("#monitor-console-subscribe",
tx.transaction.TransactionType + " transaction sent by " +
tx.transaction.Account +
"<br/>&nbsp;&nbsp;Result: " + tx.meta.TransactionResult +
" in ledger " + tx.ledger_index +
"<br/>&nbsp;&nbsp;Validated? " + tx.validated)
}
WS_HANDLERS["transaction"] = log_tx
</script>
## {{n.next()}}. 着信ペイメントの読み取り
アカウントをサブスクライブすると、 _アカウントへのすべてのトランザクションとアカウントからのすべてのトランザクション_ 、および _アカウントに間接的に影響を及ぼすトランザクション_ に関するメッセージが表示されます。この例として、[発行済み通貨](issued-currencies.html)の取引があります。アカウントが着信ペイメントを受け取った日時を認識することを目的とする場合、トランザクションストリームを絞り込んで、実際に支払われた額に基づいて支払いを処理する必要があります。以下の情報を探します。
- **`validated`フィールド**は、トランザクションの結果が[最終的である](finality-of-results.html)ことを示します。これは、`accounts`をサブスクライブする場合に常に当てはまりますが、`accounts_proposed`または`transactions_proposed`ストリーム _も_ サブスクライブしている場合は、サーバーは未確認のトランザクションに関して同様のメッセージを同じ接続で送信します。予防策として、`validated`フィールドを常に確認することをお勧めします。
- **`meta.TransactionResult`フィールド**は、[トランザクションの結果](transaction-results.html)です。結果が`tesSUCCESS`でない場合は、トランザクションは失敗したため、値を送信できません。
- **`transaction.Account`** フィールドはトランザクションの送信元です。他の人が送信したトランザクションのみを探している場合は、このフィールドがあなたのアドレスと一致するトランザクションを無視できます(自身に対する複数通貨間の支払いが _可能である_ 点に注意してください)。
- **`transaction.TransactionType`フィールド**はトランザクションのタイプです。アカウントに通貨を送金できる可能性があるトランザクションのタイプは以下のとおりです。
- **[Paymentトランザクション][]** はXRPまたは[発行済み通貨](issued-currencies.html)を送金できます。受取人のアドレスを含んでいる`transaction.Destination`フィールドによってこれらを絞り込み、必ず`meta.delivered_amount`を使用して実際に支払われた額を確認します。XRPの額は、[文字列のフォーマットで記述されます](basic-data-types.html#通貨額の指定)。
**警告:** 代わりに`transaction.Amount`フィールドを使用すると、[Partial Paymentの悪用](partial-payments.html#partial-paymentの悪用)に対して脆弱になる可能性があります。不正使用者はこの悪用を行ってあなたをだまし、あなたが支払ったよりも多くの金額を交換または引き出すことができます。
- **[CheckCashトランザクション][]** :not_enabled: では、アカウントは別のアカウントの[CheckCreateトランザクション][]によって承認された金額を受け取ることができます。**CheckCashトランザクション**のメタデータを確認すると、アカウントが受け取った通貨の額を確認できます。
- **[EscrowFinishトランザクション][]** は、以前の[EscrowCreateトランザクション][]によって作成された[Escrow](escrow.html)を終了することでXRPを送金できます。**EscrowFinishトランザクション**のメタデータを確認すると、escrowからXRPを受け取ったアカウントと、その額を確認できます。
- **[OfferCreateトランザクション][]** はアカウントがXRP Ledgerの[分散型取引所](decentralized-exchange.html)で以前発行したオファーを消費することで、XRPまたは発行済み通貨を送金できます。オファーを発行しないと、この方法で金額を受け取ることはできません。メタデータを確認して、アカウントが受け取った通貨この情報がある場合と、金額を確認します。
- **[PaymentChannelClaimトランザクション][]** では、[Payment Channel](payment-channels.html)からXRPを送金できます。メタデータを確認して、トランザクションからXRPを受け取ったアカウントこの情報がある場合を確認します。
- **[PaymentChannelFundトランザクション][]** は、閉鎖された期限切れのPayment Channelから送金元にXRPを返金することができます。
- **`meta`フィールド**には、1つまたは複数の通貨の種類とその正確な金額、その送金先などを示す[トランザクションメタデータ](transaction-metadata.html)が示されています。トランザクションメタデータを理解する方法の詳細は、[トランザクションの結果の確認](look-up-transaction-results.html)を参照してください。
以下のサンプルコードは、上に示したすべてのトランザクションのタイプのトランザクションメタデータを確認し、アカウントが受け取ったXRPの金額をレポートします。
```js
{% include '_code-samples/monitor-payments-websocket/read-amount-received.js' %}
```
{{ start_step("Read Payments") }}
<button id="tx_read" class="btn btn-primary" disabled="disabled">Start Reading</button>
<h5>Transactions</h5>
<div class="ws-console" id="monitor-console-read"><span class="placeholder">(Log is empty)</span></div>
{{ end_step() }}
<script type="application/javascript">
function CountXRPDifference(affected_nodes, address) {
// Helper to find an account in an AffectedNodes array and see how much
// its balance changed, if at all. Fortunately, each account appears at most
// once in the AffectedNodes array, so we can return as soon as we find it.
// Note: this reports the net balance change. If the address is the sender,
// any XRP balance changes combined with the transaction cost.
for (let i=0; i<affected_nodes.length; i++) {
if ((affected_nodes[i].hasOwnProperty("ModifiedNode"))) {
// modifies an existing ledger entry
let ledger_entry = affected_nodes[i].ModifiedNode
if (ledger_entry.LedgerEntryType === "AccountRoot" &&
ledger_entry.FinalFields.Account === address) {
if (!ledger_entry.PreviousFields.hasOwnProperty("Balance")) {
writeToConsole("#monitor-console-read", "XRP balance did not change.")
}
// Balance is in PreviousFields, so it changed. Time for
// high-precision math!
const old_balance = new Big(ledger_entry.PreviousFields.Balance)
const new_balance = new Big(ledger_entry.FinalFields.Balance)
const diff_in_drops = new_balance.minus(old_balance)
const xrp_amount = diff_in_drops.div(1e6)
if (xrp_amount.gte(0)) {
writeToConsole("#monitor-console-read", "Received " + xrp_amount.toString()+" XRP.")
return
} else {
writeToConsole("#monitor-console-read", "Spent " + xrp_amount.abs().toString() + " XRP.")
return
}
}
} else if ((affected_nodes[i].hasOwnProperty("CreatedNode"))) {
// created a ledger entry. maybe the account just got funded?
let ledger_entry = affected_nodes[i].CreatedNode
if (ledger_entry.LedgerEntryType === "AccountRoot" &&
ledger_entry.NewFields.Account === address) {
const balance_drops = new Big(ledger_entry.NewFields.Balance)
const xrp_amount = balance_drops.div(1e6)
writeToConsole("#monitor-console-read", "Received " + xrp_amount.toString() + " XRP (account funded).")
return
}
} // accounts cannot be deleted at this time, so we ignore DeletedNode
}
writeToConsole("#monitor-console-read", "Did not find address in affected nodes.")
return
}
function CountXRPReceived(tx, address) {
if (tx.meta.TransactionResult !== "tesSUCCESS") {
writeToConsole("#monitor-console-read", "Transaction failed.")
return
}
if (tx.transaction.TransactionType === "Payment") {
if (tx.transaction.Destination !== address) {
writeToConsole("#monitor-console-read", "Not the destination of this payment. (We're " +
address + "; they're " + tx.transaction.Destination + ")")
return
}
if (typeof tx.meta.delivered_amount === "string") {
const amount_in_drops = new Big(tx.meta.delivered_amount)
const xrp_amount = amount_in_drops.div(1e6)
writeToConsole("#monitor-console-read", "Received " + xrp_amount.toString() + " XRP.")
return
} else {
writeToConsole("#monitor-console-read", "Received non-XRP currency.")
return
}
} else if (["PaymentChannelClaim", "PaymentChannelFund", "OfferCreate",
"CheckCash", "EscrowFinish"].includes(
tx.transaction.TransactionType)) {
CountXRPDifference(tx.meta.AffectedNodes, address)
} else {
writeToConsole("#monitor-console-read", "Not a currency-delivering transaction type (" +
tx.transaction.TransactionType + ").")
}
}
$("#tx_read").click((event) => {
// Wrap the existing "transaction" handler to do the old thing and also
// do the CountXRPReceived thing
const sub_address = $("#subscribe_address").val()
const old_handler = WS_HANDLERS["transaction"]
const new_handler = function(data) {
old_handler(data)
CountXRPReceived(data, sub_address)
}
WS_HANDLERS["transaction"] = new_handler
// Disable the button so you can't stack up multiple levels of the new handler
$("#tx_read").prop("disabled", "disabled")
complete_step("Read Payments")
})
</script>
## 次のステップ
- [トランザクションの結果の確認](look-up-transaction-results.html)で、トランザクションの実行内容を確認し、適切に対応するソフトウェアを構築します。
- あなた自身のアドレスから[XRPの送金](send-xrp.html)を試します。
- [Escrow](escrow.html)、[Checks](checks.html)または[Payment Channel](payment-channels.html)のような高度なタイプのトランザクションの監視と着信通知への応答を試します。
<!--{# TODO: uncomment when it's ready. - To more robustly handle internet instability, [Follow a Transaction Chain](follow-a-transaction-chain.html) to detect if you missed a notification. #}-->
## その他のプログラミング言語
多くのプログラミング言語には、WebSocket接続を使用して、データの送受信を行うためのライブラリが用意されています。JavaScript以外の言語で`rippled`のWebSocket APIとの通信を効率良く始めるには、同様な機能を利用している以下の例を参考にしてください。
<!-- MULTICODE_BLOCK_START -->
*Go*
```go
package main
// Connect to the XRPL Ledger using websocket and subscribe to an account
// translation from the JavaScript example to Go
// https://developers.ripple.com/monitor-incoming-payments-with-websocket.html
// This example uses the Gorilla websocket library to create a websocket client
// install: go get github.com/gorilla/websocket
import (
"encoding/json"
"flag"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
// websocket address
var addr = flag.String("addr", "s.altnet.rippletest.net:51233", "http service address")
// Payload object
type message struct {
Command string `json:"command"`
Accounts []string `json:"accounts"`
}
func main() {
flag.Parse()
log.SetFlags(0)
var m message
// check for interrupts and cleanly close the connection
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
u := url.URL{Scheme: "ws", Host: *addr, Path: "/"}
log.Printf("connecting to %s", u.String())
// make the connection
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
// on exit close
defer c.Close()
done := make(chan struct{})
// send a subscribe command and a target XRPL account
m.Command = "subscribe"
m.Accounts = append(m.Accounts, "rUCzEr6jrEyMpjhs4wSdQdz4g8Y382NxfM")
// struct to JSON marshalling
msg, _ := json.Marshal(m)
// write to the websocket
err = c.WriteMessage(websocket.TextMessage, []byte(string(msg)))
if err != nil {
log.Println("write:", err)
return
}
// read from the websocket
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
// print the response from the XRP Ledger
log.Printf("recv: %s", message)
// handle interrupt
for {
select {
case <-done:
return
case <-interrupt:
log.Println("interrupt")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
```
<!-- MULTICODE_BLOCK_END -->
**ヒント:** 目的のプログラミング言語の例がない場合があります。このページの最上部にある「GitHubで編集する」リンクをクリックして、作成したサンプルコードを提供してください。
## 脚注
[1.](#from-footnote-1)<a id="footnote-1"></a>実際には、HTTPベースのAPIを何度も呼び出す場合、クライアントとサーバーは複数の要求と応答を処理する際に同じ接続を再利用できます。この方法は、[HTTP永続接続、またはキープアライブ](https://en.wikipedia.org/wiki/HTTP_persistent_connection)と呼ばれます。開発の観点から見ると、基本となる接続が新しい場合でも、再利用される場合でも、HTTPベースのAPIを使用するコードは同じです。
## 関連項目
- **コンセプト:**
- [トランザクションの基本](transaction-basics.html)
- [結果のファイナリティー](finality-of-results.html) - トランザクションの成功また失敗が最終的なものとなるタイミングを判断する方法(簡単な説明: トランザクションが検証済みレジャーにある場合は、その結果とメタデータは最終的なものです)。
- **チュートリアル:**
- [信頼できるトランザクションの送信](reliable-transaction-submission.html)
- [トランザクションの結果の確認](look-up-transaction-results.html)
- **リファレンス:**
- [トランザクションのタイプ](transaction-types.html)
- [トランザクションのメタデータ](transaction-metadata.html) - メタデータフォーマットとメタデータに表示されるフィールドの概要
- [トランザクションの結果](transaction-results.html) - トランザクションのすべての結果コードを掲載した表一覧
<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}
{% include '_snippets/rippled_versions.md' %}

View File

@@ -0,0 +1,127 @@
# 安全な署名の設定
[トランザクション](transaction-basics.html)をXRP Ledgerに送信するには、[秘密鍵](cryptographic-keys.html)のセキュリティを損なわない方法でトランザクションにデジタル署名する必要があります。(他の人があなたの秘密鍵にアクセスできる場合、その人はあなたと同じようにあなたのアカウントを操作できるため、すべての資金が盗まれたり消却されたりする可能性があります。)このページでは、トランザクションに安全に署名できる環境の設定方法について説明します。
**ヒント:** ネットワークにトランザクションを送信していない場合は、Rippleが運用しているサーバーなど、信頼できる公開サーバーを安全に使用して、着信トランザクションの監視やその他のネットワークアクティビティの読み取りを行うことができます。XRP Ledgerのすべてのトランザクション、残高、データは公開されています。
セキュリティのレベルが異なるさまざまな構成があるため、状況に応じて適したものは異なります。次の中からニーズに最適なものを選択してください。
- [`rippled`をローカルで実行](#ローカルでrippledを実行する)または[同じLAN内で実行](#同じlan内でrippledを実行する)
- ローカル署名を行える[クライアントライブラリを使用](#ローカル署名機能のあるクライアントライブラリを使用する)
- XRP Ledgerの署名に対応した[専用の署名デバイスを使用](#専用の署名デバイスを使用する)
- 信頼できる[リモート`rippled`マシンに接続するために安全なVPNを使用](#リモートrippledサーバーに対して安全なvpnを使用する)
<!-- Source for all diagrams in this article: https://docs.google.com/presentation/d/1BfGyWgC0njoPiKUZz3gXHMVSUINE3Q-_lHqY_D0TGwg/ -->
## 安全でない構成
[![安全でない構成の図](img/insecure-signing-options.png)](img/insecure-signing-options.png)
外部のソースからあなたの秘密鍵にアクセスできる構成は危険で、不正使用者によってあなたのすべてのXRPおよびあなたのXRP Ledgerのアドレスにあるすべてのものが盗まれる可能性があります。そのような構成の例としては、インターネット経由で他の人の`rippled`サーバーの[signメソッド][]を使用する構成や、秘密鍵をインターネットを経由してプレーンテキストで自己所有サーバーに送信する構成などがあります。
秘密鍵の秘匿性は常に保持する必要があります。自分にメールで送信したり、人の目に触れるところで入力したりしてはいけません。秘密鍵を使用しないときは、決してプレーンテキストではなく、暗号化された形式で保存する必要があります。セキュリティと利便性のバランスは、アドレスの保有額によっても変わります。さまざまな目的に合わせてさまざまなセキュリティ構成の複数のアドレスを使用することをお勧めします。
<!-- Note: I'd link "issuing and operational addresses" for an explanation of hot/cold wallet security, but it's particularly gateway/issued-currency centric, which is not appropriate for this context. -->
## ローカルでrippledを実行する
[![署名にローカルrippledサーバーを使用する構成の図](img/secure-signing-local-rippled.png)](img/secure-signing-local-rippled.png)
この構成では、トランザクションを生成するマシンで`rippled`を実行します。 秘密鍵はマシンから出ていかないため、マシンへのアクセス権がない人は秘密鍵にアクセスできません。もちろん、マシンのセキュリティ保護に関する業界標準のプラクティスに従ってください。この構成を使用するには、次の手順を実行します。
1. [`rippled`をインストール](install-rippled.html)します。
ローカルマシンが[`rippled`の最小システム要件](system-requirements.html)を満たしていることを確認します。
2. トランザクションに署名する必要がある場合は、`localhost`または`127.0.0.1`のサーバーに接続します。シングル署名の場合は[signメソッド][]、マルチ署名の場合は[sign_forメソッド][]を使用します。
[構成ファイルの例](https://github.com/ripple/rippled/blob/8429dd67e60ba360da591bfa905b58a35638fda1/cfg/rippled-example.cfg#L1050-L1073)では、ローカルループバックネットワーク上127.0.0.1のポート5005でJSON-RPCHTTP、ポート6006でWebSocketWSの接続をリッスンし、接続されるすべてのクライアントを管理者として扱っています。
**注意:** 署名に[コマンドラインAPI](request-formatting.html#コマンドライン形式)を使用する場合は、コマンドラインでないクライアントで[Websocket APIやJSON-RPC APIを使用](get-started-with-the-rippled-api.html)する場合よりもセキュリティが弱くなります。コマンドライン構文を使用すると、秘密鍵がシステムのプロセスリストで他のユーザーに見える可能性があり、シェル履歴にプレーンテキスト形式でキーが保存される可能性があります。
3. サーバーの使用中は、稼働状態と最新状態を維持して、ネットワークと同期されるようにしておく必要があります。
**注記:** トランザクションを送信していないときは`rippled`サーバーをオフにすることが _可能_ ですが、再び起動したときにネットワークとの同期に最大15分かかります。
## 同じLAN内でrippledを実行する
[![署名にLAN経由でrippledサーバーを使用する構成の図](img/secure-signing-lan-rippled.png)](img/secure-signing-lan-rippled.png)
この構成では、署名するトランザクションを生成するマシンと同じプライベートローカルエリアネットワークLAN内の専用マシンで`rippled`サーバーを実行します。この構成では、`rippled`を実行する専用の1台のマシンを使用しながら、中程度のシステムスペックの1台以上のマシンでトランザクションの指示を組み立てることができます。自己所有のデータセンターやサーバールームがある場合に魅力的な選択肢です。
この構成を使用するには、`rippled`サーバーをLAN内の`wss`および`https`接続を受け入れるように設定します。[証明書ピンニング](https://en.wikipedia.org/wiki/Transport_Layer_Security#Certificate_pinning)を使用する場合は自己署名証明書を使用できます。あるいは、社内や既知の認証局が署名した証明書を使用できます。[Let's Encrypt](https://letsencrypt.org/)などの一部の認証局は無料で証明書を自動発行しています。
<!--{# TODO: link api-over-lan.html with the detailed instructions when those are ready #}-->
必ず、マシンのセキュリティ保護に関する業界標準のプラクティスに従ってください。例えば、ファイアウォール、ウイルス対策、適切なユーザー権限を使用するなどです。
## ローカル署名機能のあるクライアントライブラリを使用する
[![ローカル署名機能のあるクライアントライブラリを使用する構成の図](img/secure-signing-client-library.png)](img/secure-signing-client-library.png)
この構成では、トランザクションにローカルで署名するために使用しているプログラミング言語のクライアントライブラリを使用します。使用しているプログラミング言語に対応するクライアントライブラリが必要です。Rippleは、XRP Ledgerのトランザクションにローカルで署名することができる次のクライアントライブラリを公開しています。
- **RippleAPIripple-libfor JavaScript**
- [設定](get-started-with-rippleapi-for-javascript.html)
- [APIリファレンス](rippleapi-reference.html)
- **Signing Library for C++**`rippled`に付属)
- [ドキュメント](https://github.com/ripple/rippled/tree/develop/Builds/linux#signing-library)
Rippleが公開したものでないクライアントライブラリを使用する場合は、そのライブラリが実装している署名アルゴリズムの実装が適切で安全であることを確認してください。例えば、クライアントライブラリがデフォルトのECDSAアルゴリズムを使用している場合は、そのライブラリは[RFC6979](https://tools.ietf.org/html/rfc6979)に記載されているとおりに決定論的ノンスを使用している必要があります。)Rippleが公開している上記のすべてのライブラリは、業界のベストプラクティスに従っています。
最高レベルのセキュリティを実現するために、クライアントライブラリを安定した最新バージョンの状態に保ってください。
### RippleAPIを使用したローカル署名の例
以下のサンプルコードは、RippleAPI for JavaScriptを使用してトランザクションの指示にローカルで署名する方法を示しています。
```js
{% include '_code-samples/secure-signing/js/signPayment.js' %}
```
セキュリティを強化するために、[Vault](https://www.vaultproject.io/)などの管理ツールから秘密鍵を読み込みます。
## 専用の署名デバイスを使用する
[![専用の署名ハードウェアの使用の図](img/secure-signing-dedicated-hardware.png)](img/secure-signing-dedicated-hardware.png)
専用の署名デバイスが各社から販売されており、例えば[Ledger Nano S](https://www.ledger.com/products/ledger-nano-s)は、秘密鍵をデバイスから出さずに使ってXRP Ledgerトランザクションに署名できます。すべてのタイプのトランザクションに対応していないデバイスもあります。
この構成の設定は、特定のデバイスによって異なります。場合によっては、署名デバイスと通信するためにマシンで「マネージャー」アプリケーションを実行する必要があります。そのようなデバイスの設定と使用方法については、メーカーの手順を参照してください。
## リモートrippledサーバーに対して安全なVPNを使用する
[![VPNを経由してリモート`rippled`に安全に接続する構成の図](img/secure-signing-over-vpn.png)](img/secure-signing-over-vpn.png)
この構成では、コロケーション施設や遠隔地のデータセンターなどにあるリモートでホストされている`rippled`サーバーを使用し、暗号化されたVPNを使用してそのサーバーに接続します。
この構成を使用するには、[プライベートLANで`rippled`を実行](#同じlan内でrippledを実行する)するための手順に従いますが、VPNを使用してリモート`rippled`サーバーのLANに接続します。VPNの設定手順は環境によって異なり、このガイドでは説明しません。
## 関連項目
- **コンセプト:**
- [暗号鍵](cryptographic-keys.html)
- [マルチ署名](multi-signing.html)
- **チュートリアル:**
- [rippledのインストール](install-rippled.html)
- [レギュラーキーペアの割り当て](assign-a-regular-key-pair.html)
- [信頼できるトランザクションの送信](reliable-transaction-submission.html)
- [パブリック署名の有効化](enable-public-signing.html)
- **リファレンス:**
- [signメソッド][]
- [submitメソッド][]
- [RippleAPIリファレンス](rippleapi-reference.html)
<!--{# common link defs #}-->
{% include '_snippets/rippled-api-links.md' %}
{% include '_snippets/tx-type-links.md' %}
{% include '_snippets/rippled_versions.md' %}