#p2p #gossip #networking

hypar

通用感染式P2P Gossip协议

1个稳定版本

1.0.3 2023年7月16日

#10 in #gossip

27每月下载量

MIT授权

110KB
2.5K SLoC

HyPar P2P Gossip

最初作为anoma节点代码库的一部分开发。提取为一个独立的crate。

此crate实现了一种通用感染式Gossip协议,可用于形成对等拓扑并在节点之间传播任意数据。此协议可扩展到单个主题内的数千个节点。

对等节点之间的通信使用安全的节点到节点通道加密。节点身份基于每个节点生成的非对称加密密钥对。主题使用字符串标识符进行识别,并通过连接到已经是主题成员的引导节点来加入。节点可以不指定任何引导节点,在这种情况下,它可以作为主题上其他节点的引导节点。

此crate的公共API是

// API entry point:
pub struct Network { ... }

impl Network {
  pub fn new(config: network::Config, keypair: Keypair) -> Result<Self>;
  pub fn join(&mut self, config: topic::Config) -> Result<Topic>;
  pub async fn runloop(mut self);
}


// after joining a topic:
pub struct Topic { ... }

impl Topic {
  pub fn gossip(&self, data: Bytes); 
}

// polling on new data gossiped by other peers
impl Stream for Topic {
  type Item = Bytes;
  fn poll_next(...) -> Poll<Option<Self::Item>>;
}

P2P交互的基本单元是主题。单个主题是HyparView成员协议的独立实例,该协议维护一个主题内的对等覆盖。节点可以是多个主题的成员,在这种情况下,它将拥有多个并发实例的HyparView,每个实例都有自己的对等节点和不同的覆盖。主题可能重叠,如果需要在不同主题之间路由消息,请查看单向跨主题桥接双向跨主题桥接示例。

网络API故意不公开任何关于任何主题的P2P拓扑中的单个对等节点或其他事件的信息,除了来自其他节点的Gossip协议接收到的去重Gossip字节之外。这是在库之上构建的更高级结构携带此类信息的任务。

用法

在您的Cargo.toml中添加

[dependencies]
hypar = "1.0"

常见用例

完整的Gossip示例


// drives all networking across topics
let mut network = Network::default();

// join some topic by its name and a set of bootstrap nodes
let topic1 = network.join(topic::Config {
  name: "/example/topic1".into(),
  bootstrap: vec![ // Multiaddr
    "/ip4/1.2.3.4/tcp/12345".parse()?,
    "/ip6/2002:102:405::/tcp/12345".parse()?,
    "/dnsaddr/bootstrap.example.com/tcp/12345".parse()?
  ], 
})?;

// create a background task that will print all
// incoming gossip messages on this topic to stdout.
tokio::spawn(async move {
  let mut topic1 = topic1;
  while let Some(msg) = topic1.next().await {
    println!("topic1 message: {msg:?}");
  }
});

// gossip a message on the topic every second to all peers
tokio::spawn({
  let topic1 = topic1.clone();
  async move {
    let mut counter = 1u64;
    loop {
      tokio::time::sleep(Duration::from_secs(1)).await;
      topic1.gossip(counter.to_be_bytes().to_vec().into());
      counter += 1;
    }
  }
});

// run the network runloop forever.
tokio::spawn(network.runloop()).await?;

单向跨主题桥接


// drives all networking across topics
let mut network = Network::default();

// join two different topics/overlays
let topic1 = network.join(...)?;
let topic2 = network.join(...)?;

// listen on all incoming gossip from topic1
// and gossip a copy to topic2 overlay:
tokio::spawn(async move {
  let mut topic1 = topic1;
  while let Some(msg) = topic1.next().await {
    topic2.gossip(msg);
  }
});

// run the network runloop forever.
tokio::spawn(network.runloop()).await?;

双向跨主题桥接


// drives all networking across topics
let mut network = Network::default();

// join two different topics/overlays
let topic1 = network.join(...)?;
let topic2 = network.join(...)?;

// listen on all incoming gossip from topic1
// and gossip a copy to topic2 overlay:
tokio::spawn(async move {
  let mut topic1 = topic1;
  let mut topic2 = topic2;
  tokio::select! {
    Some(msg) = topic1.next() => {
      topic2.gossip(msg);
    }
    Some(msg) = topic2.next() => {
      topic1.gossip(msg);
    }
  };
});

// run the network runloop forever.
tokio::spawn(network.runloop()).await?;

依赖项

~18–56MB
~1M SLoC