LinSoap

LinSoap

Null
github
x

使用JS透過WebRTC創建libp2p網絡並相互連接(實踐)

使用 JS 通過 WebRTC 創建 libp2p 網絡並相互連接(理論)
在上一篇理論的文章中介紹了使用 JS 通過 WebRTC 創建 libp2p 網絡並相互連接的原理,在這篇博客中會逐步介紹理論中的各種特性如何具體實踐。

準備項目#

實踐使用的是官方提供的 libp2p-webrtc-guide 項目,這個項目提供了一個 relay 節點項目,以及一個可以在瀏覽器中進行交互的 libp2p 網頁項目,首先 git clone 這個項目並安裝依賴

#git clone 項目  
git clone https://github.com/libp2p/libp2p-webrtc-guide  
#安裝npm依賴  
cd libp2p-webrtc-guide  
npm install  

啟動 libp2p Relay 節點#

在介紹理論的文章中說到,libp2p Relay 節點在網絡中有兩個角色,一個是 Crituit Relay V2 角色,幫助網絡中的其他節點發現對方,並轉發流量。還有一個是 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節點最重要的兩個角色。  
      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 節點的 PeerID 信息和 Multiaddrs 信息。運行 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()新建的身份自動生成的,如果不指定特定的 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  

根據錯誤信息,可以判斷是 @libp2p/webrtc 需要 @libp2p/circuit-relay-v2-transport 的支持,根據上篇理論的文章,libp2p 想要實現 WebRTC 的 P2P 連接需要借助 Circuit Relay V2,二者密不可分。打開 src/index.js 文件,裡面配置了瀏覽器的 libp2p 節點信息,在 createLibp2p 方法的 transports 配置中,為 libp2p 節點添加上 @libp2p/circuit-relay-v2-transport 支持。

   transports: [  
      webSockets({  
        // 允許所有WebSocket連接包括不帶TLS的  
        filter: filters.all,  
      }),  
      webTransport(),  
      webRTC({  
        rtcConfiguration: {  
          iceServers: [  
            {  
              // STUN servers help the browser discover its own public IPs  
              urls: ['stun:stun.l.google.com:19302', 'stun:global.stun.twilio.com:3478'],  
            },  
          ],  
        },  
      }),  
      // 👇 Required to create circuit relay reservations in order to hole punch browser-to-browser WebRTC connections  
      // 添加@libp2p/circuit-relay-v2-transport支持  
      circuitRelayTransport({  
        discoverRelays: 1,  
      }),  
    ]  

此時打開瀏覽器,可以發現瀏覽器已經可以成功創建 libp2p 節點,每次刷新都會產生不同的 PeerID。
根據理論文章,瀏覽器想要加入到 libp2p 網絡,需要借助 Relay 節點,那麼現在瀏覽器要做的第一步,就是先連接 Relay 節點,在打開的瀏覽器頁面中,輸入任意一個 Relay 節點的 multiaddr 地址(注意,需要是支持 WebSocket 的地址,根據理論文章,瀏覽器和 Relay 節點是通過 WebSocket 建立連接的),點擊 connect,成功連接後即可看到連接信息。

瀏覽器連接到 Relay 節點

觀察瀏覽器中的信息,可以發現該瀏覽器已經成功用 WebSockets 連接了一個節點,並且給出了該瀏覽器的 multiaddr。觀察該 multiaddr,可以發現由兩部分構成,前半部分為 Relay 節點的 multiaddr,後半部分為 /p2p-circuit/p2p / 本節點 PeerID。
在完成一個瀏覽器連接到 Relay 服務器後,可以嘗試使用一個新的瀏覽器節點與之連接,構成一個 2 個瀏覽器,一個 relay 節點組成的 libp2p 網絡。
新建一個瀏覽器,此時會產生一個與之前瀏覽器不同的 PeerID,在輸入框中輸入原瀏覽器的 multiaddr,點擊 connect,此時會發現新瀏覽器不僅能夠直接鏈接舊瀏覽器,並且也成功連接上了 Relay 節點。並顯示 Circuit Relay 連接個數為 1。如果此時關閉新的瀏覽器,那麼舊瀏覽器也會很快的顯示與新瀏覽器斷開連接了。

兩個瀏覽器連接
至此為止已經成功實現了瀏覽器的連接,但是每次打開瀏覽器都需要手動輸入地址連接到 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: [  
        // 👇 Listen for webRTC connection  
        '/webrtc',  
      ],  
    }  

完成添加後,打開新的瀏覽器並連接到 Relay 節點後,會發現該瀏覽器的 multiaddr 數量變成了原來的兩倍,觀察多出的 multiaddr,可以發現新地址比原地址多添加了一個 /webrtc,這些地址在原先的基礎上添加了對 WebRTC 的支持。
同樣打開新的瀏覽器,嘗試支持 WebSockets 和 WebRTC 的地址去連接舊瀏覽器,完成連接後可以發現 WebRTC 的連接數變為 1,至此兩個瀏覽器之間已經成功建立 WebRTC 連接。

WebRTC 連接

配置 PubSub peer discovery#

在理論文章中,說明了 libp2p Relay 節點有兩個作用,一個是 Circuit Relay V2,解決節點之間連接可行性問題。另一個是 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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。