libp2p-rs kad 使用及调试方法

libp2p-rs v0.2.0已经支持Kad-DHT,支持节点通过DHT网络发现节点和内容。
本文主要展示如何在libp2p-rs使用DHT,以及罗列出swarm和kad的部分API。

使用kad

step1p p { 6: 创建swarm

    let sec = _ N | f _ - secio::Config::new(keys.clone());
let mux = yamux::Config::new();
let tu = TransportUpgrade::new(TcpConfig::default(), mux, sec);
let mut swarm = Swarm::new(keys.public())& F z *
.with? 9 |_transport(Box::new(tu))
.with_identify(IdentifyConfig::new(false));
swarm.liX ~ ) J Nsten_on(vec![; e S a n @ J 8listen_adb q + kdr]| R Y a F U j @ 3).expect0 U !("listen on");
le+ v { H * C k - gt mutF H g o g swarm_control = swarm.control();

step2: 创建kad

    let store = MemoryStore::1 m o X ?new(o m c ;swarm.local_peer_id().clone());
let kad = Kademlia::new(% g - ? 3swarm.local_peerA  l C * ; e_id().clone(), store);
let kad_handler = kad.handler();
let mut kad_ctrl = kad.control();

step3: 注册kad

将swarm升级,使# o r 4 ! Q w % v其具备routing功能。

    // register handler to swarm
sw* D b 1 i l # garm = swarm.with_protocol(Box::new(kad_handler)).with_routing(Box::new(kad_ctrl* | x * G.clone()));

step4: 启动kad和swarm

    kad.start(swarm_control.clone());
swarm.start();

step5: 使用kad

先将bootstrap节点添加到peerstore和路由表,再启动bootstrap。

    kad_control.add_nG L y $ ode(bos y #otstrap_peer, vec![bootstrap_addr]).await;
kad_control2 H } w.bootstrap().aw[ n 8 = ? 5ait;

step6: 启用cli

集成cli,可调试swarm和kad。

    let mut app = App::new("xCLI").O { H n ^version("v0.1").author("kingwel.xie@139.com");
app.add_subcommand_with_use) 5 k 2 Z @ 5rdata(swarm_cli_commands(), Box:k L # [:new(swarm_control.o E H : 3 e Bclone()));
app.add_subcommand_with_userdata(dht_cli_commands(), Box::new(kad_control.clone())~ ? 9 =);
app.rT ? [ pun();

cli调试

以下只列出部分常用的调试命令,更多玩法请亲自下场解锁。

swarm connection

connection` R : @ G t T L命令可以用于获取当前所有连接及其子流的信息,也可以获取和某个peerJ f x . 6 i j o的连接信息。

# s con
CID   DIR Remote-S F T [ S u ?Peer-Id                                       I/O  RemoW  bte-Multiaddr
231   In  Q6 ! smf3ZX3yHnmzaXFGH5G149HyrAeKRFantVnZ9gZdne # . %uPv1U       2/0  /ip4/114.227.83.230/tcp/24792
(231   Sid(7) In  /ipfs/kad/1.0.0)
(231   Sid(9) Inv L -  /ipfs/kad/1.0.0)
161   In  QmZC9dZPyJWXSB2Ao2ChGJMjfuFiT7TyKdsGsFEKVSqnnf       0/0  /ip4/212.102.37.201/tcp/4001
2185  In  QmTmnqSEarcSLJxhehJRKX64pxSkeKn7jS2fDEZFjjt9Bn       1/0  /ip4/114.226.44.86/tcp/3109
(2185  Sid(7) In  /ipfs/kad/1e 8  0.0.0)
2069  In  12D3KooWPtfLkqAVMPP6FNufHvqxPYe55XuAdEZWUn2cPbLLAwG T YuT 1/0  /ip4/111.16.39.80/tcp/17881
(2069  Sid(1) In  /ipfs/kad/1.0.0)
2349  In  QmVcXP4bnoCJkUUJinduuM68n5M ? V a X l u ~ @jfSjDj6s{ V s [ ! p p E 1KaTjRhHoecpt       1/0  /ip4/83.248.150.24/tcp/42761
(2349  Sid(3) In  /iX f / )  } $pfs/kad/1.0.0)
492   In  12$ l y % 6 p , z pD3KooWKBkFNUCvyP5PbV2mAhrzcvPi4EPL4vD3CjieGGU9ZcQr 1/0  /ip4/203.145.95.o A P b ; 6 , K k60/tcp/64417
(492   Sid(1) In  /ipfs/kad/1.0.0)
18    In  QmP6waLA8S6M8WPoQ5tWPE6xpgtsJ44LGQcq7vDTUAmyob       1/0  /ip4/188.127.190.220/tcp_ = k r } U/4001
(18    Sid(7) In  /ipfs/kad/1.0.0)
# s con Qmf3ZX37 C F & , J A ) syHnmzaXFGH5G149HyrAeKRFane R | K &tVnZ9gZdnuPv1U
CID   DIR Remoten 4 l 0 y s } 4-Peer-Id                                       I/O  RemoteW k 7 l $ I | F ;-MultL M } ; / 7iaddr
231   In  Qmf3ZX3yHnmzaXFGH5G149HyrAeKRFantVnZ9gZdnuPv1U       2/0  /ip4/114.227.83.230/tcp/24792
(231   Sid(7) In  /ipfs/kad/1.0.0)
(231   Sid(9) In  /ipfs/kad/1.0.0)

dht states

states用于统计迭代查询运行状况,也可以观察当前节点接收到的Kad请求的次数。

# d st
Total refreshes : 1
Successful quer! 9 { z f L vies   : 4
Timeout querie$ x c ~s   : 0
Query details   : QueryStats { requests: 59, succeM z k P r Oss: 41, failure: 10, duration: 18.198653932s }
Kad rx messages : Messa6 & / R 6 zgeStats { ping: 0, find_node: 176 s t216, geta w r a l I_provider: 559, add_providerl L H = Z ~ w 5: 3667, get_value: 1, put_value: 27 }

dhtz 9 & Q c dump

dump命令用于dum/ . Hp出路由表的信息,使用verbose可以打印详细信息。

# d dp
Index Entries Active
244   1       1
246   1       1
247   2       2
248   7       7
249   10      8
250   20      20
251   20      20
252   20      20
253   20      20
254   20      19
255   20      20
# d dp 1
Index Entries Active
244   1       1
Qme9PR5oDcSSGog V @ B U o v E :S2He53RqaML4vinDD5CNgxxmV2qPefFP       Conn(false) Some(52292.68894773s) Addrs([])
246   1       1
QmboRZYso6VdQ5yfXe1DAj9u8EqouZGUm { * N w / 0sf2inoqYDtzdf8       Conn(true) Some(4330.367016609s) Addrs([])
247   2       2
QmZsbivLpaVpWQ4Mum2nzbEcoXbH7QbftRkQCmmJiTqcUp       Conn(false) Some(77688.875853187s) Adh ) D u 6 S Zdrs([])
QmZaCQ6anyaPuebhLeomzpyKRAY6GnNS5NCU8h7kSL } 8 ) ] 0 O ) DjwFKN       Conn(false) Some(43775.12096365s) Addrs(["/ip4/127.0.0.1/tcp/4001", "/ip4/138.68.29.104/tc2 - ! j = 3p/4001", "/ip4/10.46.0.6/tcp/4001", "/s v & ` r - *ip4/10.138.16.85/tcp/4001", "/i1 / c i _ d 4 m *p6/::1/tcp/4001"])

API介绍

目前swarm和kad的API已经比较完善,以下只列出部分常用的API,想了解6 E R更多API请直接阅读= * i L 9 b d x v源码。

swarm

peerstore

    /// Gets the public key by peer_id.
pub fn get_key(&self, peer_i) $ u f od: &PeerId) -> Op& e l & & ] 7tion<PublicKey>
/// Geu C ets all mul` 2 ? C @ . {tiaddr of a peer.
pub fn getm B ` ~ O ._addrs(&self, peer_id: &PeerId) -> Option<Vec<MultU O , 4iaddr>>
/// Adds% ( R } Q b i F C a address to address_b2 + l D V $ Iook by peer_id, if exists, update rtt.
pub fn add_addr(&self, peer_i* G l H r $d: &PeerId, ad& . i ? ; Bdr: Multiaddr, ttl: Duration)
/// Adr O ^ Y $ z ]ds many new addresses if they're not already in the pV )  Jeer store.
pub f| % ] X ] Zn add_addrs(&self, peer_id: &PeerId, addrs: Vec<Multiaddr>, ttl: Duration)
/// Clears all multiaddr of a peer from the peer store.
pub fn clear_addrs(&self, peer_id: &Pes o q T X b % me% g q f & $rId)

connN D ( v p , 7ection

    /// Make a new connection towards the remote peer with addresS W Y G 8 O L cses specified.
pub async fn connect_with_addrs(&mut self,6 R k . o  d z peer_$ b j / M L Cid: PeerId, addrs: Vec<Multiaddr>) -> Result<()>
/// Make a new connection towards the remote peer.
///
/// It will lookup the p+ ? q - v H ceQ 0 r ) -er store for address of the peer( ,  O 8, otherwise
/// initiate the routing interface for querying the addresses, if routing
/// is available.
pub async fn new_connection(&mut self, peer_id: PeerId) -> Result<()&gm n ~ S ht;
/// Make a new connection towards the remote peer, wiU  u /thout using routing(Kad-DHT).
pub async fn new_connection_no_routing(&mut self, peer_id: Peeh K & ` _ p @ HrId) -> Rp 8 0 4 q Q =esult<()>
/// CK S { 2 ( V 5 2lose connection towards the remotE j D j k Ze peeF 5 ? C v V v 7 ~r.
pub async fn disconnect(&mR Z _ a g } Out self, peer_id 1 H 1 N M 6 : PeerId) -> Result<()>

stre= C - o . s p 1 =am

    /// Open a new outbound stream towards the remote peer.
///
/// It will lookup the peer store for address of the peer,
/// otherwise initiate the routing interface for address queryj * 9ing,
/// when routing is enabled. In the end, it will open an outgoing
/// sub-l Z B B n Sstream when the connection is evk K k 5 h F 2 L {entuallye 2 x _ l established.
pub async fn new_stream(&mut self, peea ~ ^ d Gr_id: PeerId, pids: Vec<ProtocolId>) -> Result<Substream>
/// Open a new outbound stream towards the remote peer, without r9 Y N youting.
pub async fn new_stream_no_routing(&mut self, peer_id: PeerIdT j l B F *, pids: Vec<ProtocolId>) ->B # U m F p; Result<Substream>
/// Open a new outbound st4 | % M T 1ream towards the remote peer, without routing.
pub async fn new_stream_no_routing(&mut self, peer_id: PeerN ( u D b BId, pids: Veq p ^ Kc<ProtocolId>) -> Result<Substream> 

kad

    /// Add a node and its listening addresses to KBuckets.
pu6 O l ] O 2 mb async fn add_node(&mut sO 0 Helf, peer_id: PeerId, addrs: Vec<+ a . b g XMulti% J Zaddr>)
/// Add a node and its listening addresses to KBuckets.
pub async fn rem7 t ! move_node(&mut selv * ^ p ] * v Y ]f, peer_id: PeerId)
/// Initiate bootstrapping.
///
/// In general it should1 $ ] P 6 | be done only once upon Kad startup.
pub async fn bootstrap(&mut self)
/// L^ ) | v r ;ookup the closer peers with the given keq G * t 5 yy.
pub asyncF 1 ^ v ` L ` ] 8 fn look#  i , oup(&mut self, key: reJ F R P w [ Gcord::Key) -> ResuS  | l i g S 9lt<Vec<KadPeer>>
/// Lookup z ( N # z Q 0 (p the given peer.
pub async fn find_peer(&mut self, peer_id: &PeerId) -> Result<KadPeea z m k s ur>
/// Put value in local andd K Q j @ other peeG s T 6  5 )rs whi0 i 7 C 4 c F X IchC [ m f m closest to the given key.
pub async fn put_value(&M g E D;mut s} N x m W Delf, key: Vec<u8&g 3 s v G T { agt;, value: Vec<E ; J = s a ` j;u8>) -> Result<()&v C = Q D D Agt;
/// Get value from local and othT Y = b g d Eer peers  which closest to the given key.
pub async fn get_value(&mut self, key: Vecz c } p 0 J v<u8>) -> Result<Vec&! R : P Xlt;u8>>
/// AnnounE C $ 3 $ w ece to peers whicF c rh closer to the given key that self provide content.
pub async fn provide(&mut self, key: Vec<u8>) -> Result&B V P @ { ilt;()>
/// Find pee( 2 B / T v 6 g 0rs who provide contev  y (nt.
pub async fn find_providers(&mut self, key: Vec<u8>, count: us/ Q 2 ! mize) -> Option<Vec&i } Jlt;KadPeer>>

总结

在启动kad和swarm后,就可以通过句柄(controller),调用A- Y v | 1 N Q QPI。当前
swU N W 3arm的API已经比较完善,目前已经可2 P Q以支持m e 6 o G V A SKad-DHT这种比较复杂的协议,这也为新协议的添加创造了条件。


NetS - ; | @warps 由国内资深的云计算和分布式技术开发团队组成,该团队在金融、电力、J Z [ , Q H ( z通信及互联网行业有非常丰富的落地经验。Netwarps 目前在深圳、北京均设立了研发中心,团队规模30+,其中大部分k f U F % R 6 i为具备十年以上开发经验的技术人员,分别来自互联网、金融、云计算、区块链以及科研机构等专业领域。
Netwarps 专注于安全存储技术产品的研发与应用,主要产品有去中心化文件系统(DFS)、去中心化计算平台(DCP),致力于提供基于去中心化网络技术实现的分布式存储和分布式计算平台,具有高, T z可用、低功耗和低网络的技术特5 = . K u B点,适用于物联网、工业互联网等场景。
公众号:Netwarps