如何使用Rust rust-libp2p向IPFS DHT插入/pk类型记录?
核心错误原因
- 键格式错误:你的Rust代码中
/pk/后缀拼接的是PeerID的原始二进制字节,而IPFS DHT规范要求/pk/记录的键后缀是PeerID的base58编码字符串,和Go代码的处理逻辑一致。 - 值格式错误:你使用
into_protobuf_encoding()输出的是libp2p公钥的protobuf封装格式,而IPFS/pk记录要求值为公钥的原始二进制编码,和Go代码中GetPublic().Bytes()的输出一致。 - Kademlia配置不兼容IPFS DHT:rust-libp2p默认的Kademlia协议标识不是IPFS公共DHT使用的
/ipfs/kad/1.0.0,且未开启对应记录校验规则,同时你提交的Record中publisher字段留空,IPFS节点会拒绝存储无发布者签名的记录。 - Quorum配置不合理:IPFS公共DHT写入至少需要Quorum::Majority才能保证写入成功。
可用演示代码
use libp2p::{ identity, kad::{Kademlia, KademliaConfig, Record, Key, Quorum, store::MemoryStore}, multiaddr::Protocol, swarm::{Swarm, SwarmEvent}, PeerId, Transport, tcp::TcpConfig, noise::NoiseConfig, yamux::YamuxConfig, }; use std::error::Error; use base58::ToBase58; #[tokio::main] async fn main() -> Result<(), Box<dyn Error>> { // 生成本地密钥对 let local_key = identity::Keypair::generate_ed25519(); let local_peer_id = PeerId::from(local_key.public()); println!("本地节点ID: {local_peer_id}"); // 构建传输层 let transport = TcpConfig::new() .upgrade(libp2p::core::upgrade::Version::V1) .authenticate(NoiseConfig::xx(&local_key).into_authenticated()) .multiplex(YamuxConfig::default()) .boxed(); // 配置Kademlia为IPFS公共DHT兼容模式 let mut kad_config = KademliaConfig::default(); kad_config.set_protocol_name(&b"/ipfs/kad/1.0.0"[..]); kad_config.set_record_ttl(Some(std::time::Duration::from_secs(48 * 3600))); kad_config.set_publication_interval(Some(std::time::Duration::from_secs(12 * 3600))); let store = MemoryStore::new(local_peer_id); let mut kademlia = Kademlia::with_config(local_peer_id, store, kad_config); // 接入IPFS公共DHT引导节点 let bootstrap_peer_id: PeerId = "QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN".parse()?; let bootstrap_addr = "/ip4/104.131.131.82/tcp/4001".parse()?; kademlia.add_address(&bootstrap_peer_id, bootstrap_addr); kademlia.bootstrap()?; // 构建Swarm let mut swarm = Swarm::new(transport, kademlia, local_peer_id); swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?; // 等待引导完成 loop { match swarm.select_next_some().await { SwarmEvent::Behaviour(libp2p::kad::KademliaEvent::BootstrapResult(Ok(_))) => { println!("DHT引导完成"); break; } SwarmEvent::Behaviour(libp2p::kad::KademliaEvent::BootstrapResult(Err(e))) => { eprintln!("引导失败: {e}"); return Ok(()); } _ => {} } } // 构造符合规范的/pk记录 let peer_id_b58 = local_peer_id.to_base58(); let key = Key::from(format!("/pk/{peer_id_b58}").into_bytes()); // 取公钥原始编码,不是protobuf封装格式 let value = match &local_key.public() { identity::PublicKey::Ed25519(pk) => pk.to_bytes().to_vec(), identity::PublicKey::Secp256k1(pk) => pk.to_bytes().to_vec(), _ => unimplemented!("仅支持ed25519/secp256k1公钥"), }; // 提交记录 let record = Record { key: key.clone(), value, publisher: Some(local_peer_id), expires: None, }; swarm.behaviour_mut().put_record(record, Quorum::Majority)?; println!("已提交/pk记录写入请求"); // 等待写入结果 loop { match swarm.select_next_some().await { SwarmEvent::Behaviour(libp2p::kad::KademliaEvent::PutRecordResult(Ok(res))) => { println!("写入成功,成功存储节点数: {}", res.successes.len()); break; } SwarmEvent::Behaviour(libp2p::kad::KademliaEvent::PutRecordResult(Err(e))) => { eprintln!("写入失败: {e}"); break; } _ => {} } } Ok(()) }
依赖配置(Cargo.toml)
[dependencies] libp2p = { version = "0.39.1", features = ["tcp", "noise", "yamux", "kad"] } tokio = { version = "1.0", features = ["full"] } base58 = "0.2.0"
内容的提问来源于stack exchange,提问作者fygesser
相关产品推荐
相关产品推荐

