概要
ADAMANT Nodeは2つのオプトインのクライアントWebSocket機能をサポートするようになりました。正常に適用および保存されたブロックに対するnewBlockイベント、および確定したbalanceとunconfirmedBalanceの更新に対するbalances/changeイベントです。実装は素のWebSocket接続ではなくSocket.IOを使用しています。サブスクリプションは単一のソケットにスコープされ、再接続後に復元する必要があります。
この実装はNode issue #256およびNode issue #217に対応するもので、ドキュメントはAdamant-im/docs#35に、OpenAPIの関連コントラクトはAdamant-im/adamant-schema#48にあります。
新規ブロックイベント
クライアントはblocks: trueを発行することでブロック通知を明示的に有効化します。newBlockペイロードにはコンパクトな公開ヘッダーが含まれます:ブロックID、高さ、タイムスタンプ、ジェネレーター公開鍵、トランザクション数、合計金額、合計手数料、および報酬。意図的にトランザクションリスト、署名、ペイロードハッシュは省略されており、クライアントは必要に応じてREST経由で完全なブロックを要求できます。
connection.emit('blocks', true);
connection.on('newBlock', (block) => {
console.log('Applied block:', block);
});
ノードはこのイベントを、完全なブロック適用パイプラインが成功しブロックが保存された後にのみ発行します。履歴リプレイおよびメモリテーブルの再構築では、ライブ同様のブロックイベントは生成されません。
残高変更イベント
残高の配信にはアドレスのサブスクリプションと明示的なフィールドのサブスクリプションの両方が必要です。ペイロードには変更されたサブスクライブ済みフィールドのみが含まれ、値は1/10^8 ADM単位の10進数文字列として表されます。
connection.emit('address', ['U1234567890123456']);
connection.emit('balances', ['balance', 'unconfirmedBalance']);
connection.on('balances/change', (account) => {
console.log('Balance changed:', account);
});
balanceは確定したブロックチェーン状態を表します。unconfirmedBalanceはノードの現在の未確認プールも反映し、トランザクションが受け入れ、確定、期限切れ、ロールバック、または再検証された際に変化する可能性があります。
配信とパフォーマンス設計
主な目標は、すべてのアカウント変更を接続済みソケット全体のスキャンや不要なデータベース読み取りに変えることなく、有用なイベントを追加することでした。専用のブロックおよびアドレスごとの残高インデックスにより、関心のあるソケットのみが選択され、ノードはサブスクライバーが変更されたアドレスとフィールドを必要としない場合にアカウント読み取りをスキップします。ブロック適用とロールバックは内部の残高変更をバッチ処理し、変更されたアドレスごとに1回の最終アカウント読み取りを実行します。ネストされたバッチ抑制は外側のバッチが閉じるまでラッチされ、内側のバッチ失敗後の部分的な発行を防ぎます。ブロック適用の失敗、ロールバックの失敗、リプレイ、再構築、および完了したスナップショットの切り詰めは、すべて永続化されていない残高通知を抑制します。ソケットマッチング、アカウント検索、および個別ソケット発行の失敗は、ブロック、ラウンド、およびアカウント処理から分離されています。ラウンド報酬の変更は、永続化されたラウンド操作が完了した後にのみ発行されます。
これらの変更はコンセンサスルール、ブロックまたはトランザクションのシリアライゼーション、署名、ID、データベーススキーマ、報酬、手数料、またはピアプロトコルの動作を変更するものではありません。
ベストエフォート型のイベントセマンティクス
これらのイベントは低レイテンシの通知であり、永続的なイベントログではありません。クライアントは切断中にイベントを見逃す可能性があり、RESTを通じて重要な状態を整合化する必要があります。残高サブスクリプションは初期スナップショットを送信せず、非同期の残高読み取りは急速な独立した更新中に順序通りに完了しない場合があります。重複するトランザクションIDおよびブロックIDは少なくとも60秒間抑制され、定期的なクリーンアップにより実効的なウィンドウは約2分に延長されます。ブロックがロールバックされ、同じIDがそのウィンドウ内で再適用された場合、2回目の通知は抑制される可能性があります。
現在残高の文字列表現は意図的にRESTの動作と一致させています。JavaScriptの安全な整数範囲を超える正確な値には、WebSocketのみの変更ではなくAPI全体での協調的な変更が必要です。任意のサイレントなソケットごとのサブスクリプション上限は導入されていません。現在のAPIには部分的な拒否に対する応答メカニズムがないため、リソース制限は明示的なクライアントフィードバックを伴う、別途設定可能で文書化されたコントラクトであるべきです。
バリデーション
バリデーションには、WebSocket、アカウント、トランザクション、ブロック、およびラウンドのパスをカバーする226件の機能対象Nodeテストの合格、ならびにスナップショット抑制とネストされたバッチ破棄に特化したフォローアップ回帰テストが含まれます。より広範な高速ユニットスイートでは940件のテストに合格しました。追加のチェックとして、ESLint、本番VitePressドキュメントビルド、OpenAPIフォーマットおよびバンドル検証、ならびにブロックおよび残高配信のための実際のSocket.IO統合カバレッジを実施しました。関連しない長時間実行テストスイートは意図的にスキップされました。この機能はコンセンサスバリデーション、シリアライゼーション、SQL、ピアトランスポート、またはRESTエンドポイントを変更しないためです。