転送トランザクションの作成⚓︎
転送トランザクション は、Symbol における最も基本的なトランザクションのタイプです。 これを使用すると、ある アカウント から別のアカウントへ XYM やその他の任意の モザイク を送信でき、オプションでメッセージを含めることも可能です。
このチュートリアルでは、転送トランザクションを作成、署名、およびアナウンスし、その後トランザクションが承認されるまでステータスをポーリングする方法を説明します。 現在の時間や手数料など、必要なトランザクションパラメータは、最新の値を使用するためにネットワークから取得されます。
前提条件⚓︎
開始する前に、以下を確認してください。
- 開発環境をセットアップしていること。 開発環境のセットアップ を参照してください。
- 転送トランザクションを送信するための アカウント を、 コード または ウォレットを使用して 作成していること。
- トランザクション手数料と転送額を支払うための XYM を入手していること。 蛇口 (Faucet) からの通貨の入手 を参照してください。
完全なコード⚓︎
このチュートリアルの完全なコード一覧を以下に示します。 詳細な手順ごとの説明は次のセクションで行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
コード全体は、単純なエラー処理を提供するために単一の try ブロックでラップされていますが、実際のアプリケーションではより詳細な制御が必要になるでしょう。
コード解説⚓︎
アカウントのセットアップ⚓︎
署名者アカウントは、 SIGNER_PRIVATE_KEY 環境変数から読み込まれます。
指定されていない場合は、デフォルトでテストキーが使用されます。
ネットワーク時間の取得⚓︎
Symbol の トランザクション には、有効期限(deadline)を含める必要があります。これは、ネットワークがトランザクションを破棄する前に承認を試みる期間を定義します。 有効期限は絶対的なネットワーク時間で表されるため、最初のステップは ノード から現在のネットワーク時間を取得することです。
ネットワーク時間とは何ですか?
Symbol では、時間を最初のブロックである ネメシスブロック(他のブロックチェーンではジェネシスブロックとして知られています)の作成から経過した秒数として定義しています。
すべてのトランザクションの有効期限とタイムスタンプは、この起点を基準に計算されます。
UTC などのより人間が理解しやすい形式でタイムスタンプを表示したい場合は、ネットワークプロパティから取得できるネメシスブロックのタイムスタンプを加算する必要があります。
properties_path = '/network/properties'
print(f'{properties_path} からネットワークプロパティを取得しています')
with urllib.request.urlopen(f'{NODE_URL}{properties_path}') as response:
response_json = json.loads(response.read().decode())
epoch_adjustment = datetime.datetime.fromtimestamp(
int(response_json['network']['epochAdjustment'].rstrip('s')))
print(f' ネメシスタイムスタンプ: {epoch_adjustment}')
const propertiesPath = '/network/properties';
console.log(propertiesPath, 'からネットワークプロパティを取得しています');
const propertiesResponse = await fetch(`${NODE_URL}${propertiesPath}`);
const propertiesJSON = await propertiesResponse.json();
const epochAdjustment = new Date(parseInt(
propertiesJSON['network']['epochAdjustment']) * 1000);
console.log(' ネメシスタイムスタンプ:', epochAdjustment);
トランザクションの有効期限が現在のネットワーク時間より前、または2時間以上先の場合、トランザクションは拒否されます。
これを回避するには、 /node/time GET エンドポイントを使用して、トランザクションを構築する前に現在のネットワーク時間を知る必要があります。
ただし、アプリケーションはトランザクションごとにネットワーク時間を照会する必要はありません。 一度取得すれば、必要に応じてローカルのシステムクロックを使用して調整できます。これにより、精度とパフォーマンスのバランスが得られます。
推奨手数料の取得⚓︎
Symbol の トランザクションは、ノードにトランザクションをブロックに含めるインセンティブを与えるために手数料を支払う必要があります。 手数料が低すぎると、どのノードもトランザクションを含めない可能性があります。 高すぎると、送信者は資金を無駄にします。 さらに、各ノードは入ってくるトランザクションに対して最低手数料のしきい値を強制する場合があります。
最適な手数料は、ネットワークの現在の状態、特に送信されているトランザクションの数とそれらが提示している手数料に依存します。
手数料の見積もりをサポートするために、Symbol は最近のトランザクション活動に基づく 推奨手数料乗数(recommended fee multiplier) を返す /network/fees/transaction GET エンドポイントを提供しています。
最終的な手数料は、推奨乗数にトランザクションのサイズ(バイト単位)を掛けることで計算されます。 これにより、大きなトランザクションは比例して手数料が高くなり、小さなトランザクションはコスト効率がよいまま維持されます。
アプリケーションは簡略化のために固定の手数料を使用することもできますが、ネットワークの推奨に従う方がより効率的です。 ネットワーク時間と同様に、トランザクションごとに乗数を照会する必要はありませんが、定期的に更新する必要があります。
上記のスニペットは、推奨乗数( medianFeeMultiplier )とノードの最小乗数( minFeeMultiplier )の大きい方を取得し、トランザクションのサイズが判明した後に使用できるように保存します。
トランザクションの構築⚓︎
Use a
TransferTransactionV1Descriptorto create this transaction in a type-safe way.
See the Typed Descriptors tutorial for details.
転送トランザクションを構築する際には、必要なすべてのトランザクションプロパティを指定する必要があります。 スニペットには以下のフィールドが含まれています。
-
Type (タイプ): 転送トランザクションにはタイプ
transfer_transaction_v1を使用します。 -
Signer public key (署名者の公開鍵): 署名者は手数料を支払うアカウントです。 転送トランザクションでは、転送されるモザイクの送信元でもあります。
-
Deadline (有効期限): この値は現在のネットワーク時間から2時間後に設定されており、これが許容される最大の有効期限です。
-
Recipient address (受信者アドレス): この例では、受信者は送信者と同じです。 これはデモンストレーションとしては有用ですが、実用的ではありません。
-
Mosaics (モザイク): 転送トランザクションは一度に複数のモザイクを送信できるため、これは配列になります。 各エントリにはモザイク IDと金額が含まれます。
この例では、XYM のモザイク ID は、完全な 16 進数 ID よりも覚えやすいエイリアスである
symbol.xymを使用して取得されています。金額は絶対単位で表され、これはモザイクの 可分性 に依存します。 XYM の場合、可分性は 6 であるため、 1 XYM は
1_000_000として表現する必要があります。
記述子には fee フィールドが設定されていないことに注意してください。
代わりに、手数料はトランザクションが構築された後に計算されます。計算には、事前に取得した乗数とトランザクションのサイズ(バイト単位)が使用されます。サイズは記述子が構築されて初めて判明します。
トランザクションにメッセージを含める
トランザクションには、オプションで自由形式のメッセージを含めることができます。 転送トランザクションでのメッセージの送信 で、その方法を説明しています。
署名とシリアライズ⚓︎
トランザクションが作成されたら、署名するアカウントの秘密鍵を使用して署名する必要があります。 署名により、トランザクションが本物であり、送信者によって承認されていることが保証されます。
は、16 進数文字列としてエンコードされた署名 を返します。
は、署名をトランザクションに追加し、アナウンスのためにノードに直接送信できる状態の JSON ペイロードにシリアライズします。
トランザクションのアナウンス⚓︎
トランザクションのアナウンスは、任意の SymbolのAPI ノードの /transactions PUT エンドポイントへの単純なリクエストです。
ペイロードが正しく形成されていれば、リクエストは HTTP 200 レスポンスで成功します。
しかし、このレスポンスはトランザクションが有効であること、またはネットワークによって受け入れられたことを示すものでは ありません。 検証、手数料の確認、およびその他のルールは、トランザクションが受信された後に非同期に適用されます。
トランザクションが実際に受け入れられ、ブロックに含まれたことを確認するには、次のステップで示すように、そのステータスを個別に監視する必要があります。
承認の待機⚓︎
Note
このステップでは、トランザクションが承認されたかどうかを確認するためにポーリングを使用しています。 ポーリングはここでは説明の目的で使用されていますが、実際のアプリケーションには推奨されるアプローチではありません。
WebSocket を使用すると、API 呼び出しを繰り返すオーバーヘッドなしに、よりレスポンスの高いソリューションを提供できます。
さらに、トランザクションステータスを確認するロジックは再利用可能です。 すべてのトランザクションをアナウンスした後に必要となるため、ユーティリティ関数やモジュールに移動させることができます。
上記のスニペットは、送信されたトランザクションのハッシュを使用して、繰り返し /transactionStatus/{hash} GET エンドポイントを照会します。
レスポンスは以下のいずれかの形式をとる可能性があります。
- HTTP エラー。ノードがまだトランザクションの処理を開始していないことを示します。
- トランザクションステータスを含む有効な JSON オブジェクト。
ステータスグループが confirmed の場合、トランザクションは受け入れられ、ブロックに含まれています。
ステータスグループが failed の場合、トランザクションは拒否されています。例えば、残高不足などが原因です。
それ以外の場合は、コードは 1 秒待機してから再試行します(最大 60 回まで)。
コードは、最初のステータス確認を実行する 前に 最初の待機を行っていることに注目してください。 これにより、アナウンス後にノードがトランザクションの処理を開始するための時間が確保されます。
出力⚓︎
以下に示す出力は、プログラムの典型的な実行結果に対応しています。
Using node https://reference.symboltest.net:3001
Fetching current network time from /node/time
Network time: 78235462065n ms since nemesis
Fetching recommended fees from /network/fees/transaction
Fee multiplier: 100
Built transaction:
{
signature: '728D968E14F50EBB2496B560721E938629D6B4C1522B4A22DD659507B469C0EC5125485EBD38D48FBF351FF9DEC9CF3AFD7A5AFC5E945087E53173589B0B6B08',
signerPublicKey: '87DA603E7BE5656C45692D5FC7F6D0EF8F24BB7A5C10ED5FDA8C5CFBC49FCBC8',
version: 1,
network: 152,
type: 16724,
fee: '17600',
deadline: '78242662065',
recipientAddress: '98F96BD2F803DE1EE39AACFC53A246F4F7A46901A5D0A53E',
mosaics: [ { mosaicId: '16666583871264174062', amount: '1000000' } ],
message: ''
}
Announcing transaction to /transactions
Response: {"message":"packet 9 was pushed to the network via /transactions"}
Waiting for confirmation from /transactionStatus/260CD293E05C2853A967874BCF67FAB36FD331CE14925CA611B3877B99BB325D
Transaction status: unknown | Cause: Not Found
Transaction status: unconfirmed
Transaction status: unconfirmed
Transaction status: unconfirmed
Transaction status: unconfirmed
Transaction status: confirmed
Transaction confirmed in 5 seconds
承認までのステータス確認の回数はネットワークの状況によって変化し、ノードがトランザクションの処理を開始する速度によっては、最初の unknown ステータスが表示されたりされなかったりします。
ネットワークの観点からトランザクションを確認するには、 Symbol Testnet Explorer にアクセスし、トランザクションハッシュを検索します。
ハッシュは Waiting for confirmation from /transactionStatus/... と書かれた行に出力されています。
トランザクションが承認プロセスを進む様子をリアルタイムで確認できるはずです。
あるいは、 signerPublicKey を検索して、署名者アカウントの履歴内でトランザクションを表示することもできます。
結論⚓︎
このチュートリアルでは、以下の方法を説明しました。
| ステップ | 関連ドキュメント |
|---|---|
| 有効期限情報の取得 | /node/time GET |
| 手数料情報の取得 | /network/fees/transaction GET |
| トランザクションの作成 | |
| トランザクションの署名 | |
| トランザクションのアナウンス | /transactions PUT |
| 承認の待機 | /transactionStatus/{hash} GET |
他のトランザクションタイプも、同じ一般的なプロセスに従います。