LinSoap

LinSoap

Null

JSを使用してWebRTCを介してlibp2pネットワークを作成し、相互接続する(実践)

JS を使用して WebRTC を介して libp2p ネットワークを作成し、相互接続する(理論)
前回の理論の記事では、JS を使用して WebRTC を介して libp2p ネットワークを作成し、相互接続する原理について紹介しました。このブログでは、理論のさまざまな機能がどのように具体的に実践されるかを段階的に紹介します。

プロジェクトの準備#

実践には、公式が提供する libp2p-webrtc-guide プロジェクトを使用します。このプロジェクトは、リレー ノード プロジェクトと、ブラウザで対話できる libp2p Web プロジェクトを提供します。まず、このプロジェクトを git clone し、依存関係をインストールします。

#git clone プロジェクト
git clone https://github.com/libp2p/libp2p-webrtc-guide
#npm依存関係をインストール
cd libp2p-webrtc-guide
npm install

libp2p Relay ノードを起動#

理論の記事で述べたように、libp2p Relay ノードはネットワーク内で 2 つの役割を持っています。1 つは Crituit Relay V2 の役割で、ネットワーク内の他のノードが互いに発見し、トラフィックを転送するのを助けます。もう 1 つは PubSub Peer Discovery の役割で、ノード間の自動接続を支援します。このプロジェクトでは、JS の Relay 実装が提供されており、以下のコマンドを入力して libp2p Relay ノードを起動します。

#libp2p relayノードを起動
npm run start:relay

上記のコマンドは、実際には node 環境で src/relay.js ファイルを実行しています。relay.js ファイルを観察します。

async function main() {
  // enable('*')
  const libp2p = await createLibp2p({
    addresses: {
      listen: [
        '/ip4/0.0.0.0/tcp/9001/ws',
        '/ip4/0.0.0.0/tcp/9002',
      ],
    },
    transports: [
      webSockets(),
      tcp(),
    ],
    connectionEncryption: [noise()],
    streamMuxers: [yamux()],
    connectionGater: {
      // ローカルテスト用にプライベートアドレスを許可
      denyDialMultiaddr: async () => false,
    },
    services: {
      identify: identify(),
      autoNat: autoNAT(),
      // Relayノードの最も重要な2つの役割を構成しました。
      relay: circuitRelayServer(),
      pubsub: gossipsub(),
    },
  })

  libp2p.services.pubsub.subscribe(PUBSUB_PEER_DISCOVERY)

  console.log('PeerID: ', libp2p.peerId.toString())
  console.log('Multiaddrs: ', libp2p.getMultiaddrs())
}

main()

上記のコードは、libp2p ノードを作成し、すべてのアドレスの 9001 ポートと 9002 ポートでリッスンするように構成しています。9001 は WebSocket プロトコルを使用し、暗号化方式を noise として定義し、yamux をストリーム多重化方式として定義しています。最も重要なのは、services で Relay ノードの重要な CircuitRelayServer と gossipsub 情報を構成したことです。また、PUBSUB_PEER_DISCOVERY という変数をサブスクライブしました。Relay ノードを実行すると、コンソールに次の情報が表示されます。

> node src/relay.js
PeerID:  12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ
Multiaddrs:  [
  Multiaddr(/ip4/127.0.0.1/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/172.30.63.206/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/192.168.5.101/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/0.0.1.1/tcp/9001/ws/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/127.0.0.1/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/172.30.63.206/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/192.168.5.101/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ),
  Multiaddr(/ip4/0.0.1.1/tcp/9002/p2p/12D3KooWDpJEwVdPBrQf6ZcwRYPzynBU2PZNGTQs3X8uh6FpxRTZ)
]

各 libp2p ノードには一意のPeerIDがあり、この ID は Services 構成で identity () を呼び出して新しく作成されたアイデンティティによって自動生成されます。特定のアイデンティティを指定しない場合、毎回異なる PeerID が生成されます。

コンソールには 8 つのアドレスが表示されます。これは libp2p ノードの multiaddr であり、実際にはローカルのすべての ipv4 アドレスに対応し、9001 ポートで WebSocket を使用し、9002 ポートで TCP を使用します。

ブラウザノードを起動#

これで libp2p Relay ノードが正常に起動しました。次に、ブラウザノードを起動し、libp2p Relay ノードに接続を試みることができます。新しいターミナルを開き、以下のコマンドを実行し、ブラウザを開くことで新しいブラウザノードを作成できます。

npm run start

しかし、この時点でブラウザを開くと、ノードの PeerID が Unknown であることがわかります。ブラウザのコンソールを開くと、次のエラーが表示されます。

CodeError: Service "@libp2p/webrtc" required capability "@libp2p/circuit-relay-v2-transport" but it was not provided by any component, you may need to add additional configuration when creating your node.
    at checkServiceDependencies (components.ts:173:15)
    at new Libp2pNode (libp2p.ts:193:5)
    at createLibp2pNode (libp2p.ts:423:10)
    at async createLibp2p (index.ts:167:16)
    at async App (index.js:19:18)
(anonymous) @ index.js:121
Promise.catch (async)
(anonymous) @ index.js:120
(anonymous) @ index.js:122

エラーメッセージから、@libp2p/webrtc が @libp2p/circuit-relay-v2-transport のサポートを必要としていることがわかります。前回の理論の記事によると、libp2p が WebRTC の P2P 接続を実現するには Circuit Relay V2 を利用する必要があり、両者は密接に関連しています。src/index.js ファイルを開くと、ブラウザの libp2p ノード情報が構成されており、createLibp2p メソッドの transports 構成に @libp2p/circuit-relay-v2-transport のサポートを追加します。

   transports: [
      webSockets({
        // TLSなしを含むすべてのWebSocket接続を許可
        filter: filters.all,
      }),
      webTransport(),
      webRTC({
        rtcConfiguration: {
          iceServers: [
            {
              // STUNサーバーはブラウザが自分のパブリックIPを発見するのを助けます
              urls: ['stun:stun.l.google.com:19302', 'stun:global.stun.twilio.com:3478'],
            },
          ],
        },
      }),
      // 👇 ブラウザ間のWebRTC接続をホールパンチするためにCircuit Relay予約を作成するために必要
      // @libp2p/circuit-relay-v2-transportのサポートを追加
      circuitRelayTransport({
        discoverRelays: 1,
      }),
    ]

この時点でブラウザを開くと、ブラウザが libp2p ノードを正常に作成できることがわかります。毎回リフレッシュするたびに異なる PeerID が生成されます。
理論記事によると、ブラウザが libp2p ネットワークに参加するには Relay ノードを利用する必要があります。したがって、ブラウザが最初に行うべきことは、Relay ノードに接続することです。開いているブラウザページに、任意の Relay ノードの multiaddr アドレスを入力します(注意:WebSocket をサポートするアドレスである必要があります。理論記事によると、ブラウザと Relay ノードは WebSocket を介して接続を確立します)。接続をクリックすると、成功裏に接続情報が表示されます。

ブラウザが Relay ノードに接続

ブラウザ内の情報を観察すると、このブラウザが WebSockets を介してノードに正常に接続されており、そのブラウザの multiaddr が表示されます。この multiaddr は 2 つの部分で構成されていることがわかります。前半部分は Relay ノードの multiaddr で、後半部分は /p2p-circuit/p2p / 本ノードの PeerID です。
ブラウザが Relay サーバーに接続した後、新しいブラウザノードを使用して接続を試みることができ、2 つのブラウザと 1 つの Relay ノードで構成される libp2p ネットワークを形成します。
新しいブラウザを作成すると、前のブラウザとは異なる PeerID が生成されます。入力ボックスに元のブラウザの multiaddr を入力し、接続をクリックすると、新しいブラウザが古いブラウザに直接接続できるだけでなく、Relay ノードにも正常に接続されていることがわかります。そして、Circuit Relay 接続数が 1 であることが表示されます。この時点で新しいブラウザを閉じると、古いブラウザもすぐに新しいブラウザとの接続が切れたことが表示されます。

2 つのブラウザが接続
これでブラウザの接続が正常に実現されましたが、ブラウザを開くたびに手動でアドレスを入力して Relay ノードに接続する必要があります。この問題を解決するために、src/index.js の createLibp2p メソッドの peerDiscovery 構成に bootstrap を追加し、Relay ノードのアドレスを設定します。

    peerDiscovery: [
      bootstrap({
        list: ['RelayノードのWebSocketsアドレス'],
      }),

新しいブラウザを開くと、ブラウザノードが自動的に Relay ノードに接続されることがわかります。

WebRTC 接続を起動#

理論記事の接続プロセス図では、ブラウザノードが最初に Circuit Relay V2 を介してブラウザノードを発見し、その後標準の WebRTC 接続を確立することが示されています。以上の手順で、Circuit Relay V2 を介してブラウザを接続することに成功しました。次に、WebRTC 接続のサポートを起動します。
src/index.js で、createLibp2p メソッドの addresses に listen アドレスを追加します。

    addresses: {
      listen: [
        // 👇 WebRTC接続のためにリッスン
        '/webrtc',
      ],
    }

追加が完了したら、新しいブラウザを開いて Relay ノードに接続すると、そのブラウザの multiaddr の数が元の 2 倍になっていることがわかります。多くの multiaddr を観察すると、新しいアドレスは元のアドレスに /webrtc が追加されていることがわかります。これらのアドレスは、元の基盤に WebRTC のサポートが追加されています。
同様に、新しいブラウザを開き、WebSockets と WebRTC の両方をサポートするアドレスを使用して古いブラウザに接続を試みると、接続が完了した後、WebRTC の接続数が 1 に変わっていることがわかります。

WebRTC 接続

PubSub ピアディスカバリーの構成#

理論記事では、libp2p Relay ノードには 2 つの役割があることが説明されています。1 つは Circuit Relay V2 で、ノード間の接続の実現可能性の問題を解決します。もう 1 つは PubSub Peer Discovery で、ノード間の自動接続の問題を解決します。
この実践では、GossipSub を使用して、同じトピックをサブスクライブし、接続されたノードにブロードキャストすることで、ノード間の自動接続の問題を実現します。
src/index.js ファイルで、ノードに pubsubPeerDiscovery と gossipsub を構成します。

    peerDiscovery: [
      bootstrap({
        list: ['/ip4/127.0.0.1/tcp/9001/ws/p2p/12D3KooWKsQgy75zYnHWqoMw4fgE9R7FmjzFDD8grnsjABuXtAoN'],
      }),
      // 新しい構成、トピックをサブスクライブ
      pubsubPeerDiscovery({
        interval: 10_000,
        topics: [PUBSUB_PEER_DISCOVERY],
      }),
    ],
    services: {
      // 新しい構成、Gossipsubサービスを追加
      pubsub: gossipsub(),
      identify: identify(),
    },

最後に、複数のブラウザを新しく作成し、何も操作せずにしばらく待つと、ブラウザが自動的に相互接続します。これで、JS を介して WebRTC を使用してブラウザ間に基本的に使用可能な libp2p ネットワークが成功裏に構築されました。

image

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。