在阅读本篇之前, 请先查看
泰岳链使用rust-libp2p实现节点同步(一)
新区块缓存
同步的启动策略一般是当本地高度和对方节点上链高度相差一定高度常量
,才会启动。
想象一下,握手时对方高度是100
,当你同步完这些区块时,对方节点已经到120
了,对方发送的区块121
,收到后是无法上链的,而同步高度常
量是50
,只能等到150才能再次启动同步。
解决这个问题需要引入区块缓存。
新区块gossip通知
每产生一个区块,区块生产者
都会通过gossip
发送到订阅这个topic
的节点,gossip为libp2p实现,内部维护节点管理。
// create the network topic to send on
let topic = GossipTopic::MapBlock;
let message = PubsubMessage::Block(bincode::serialize(&data).unwrap());
self.network_send
.try_send(NetworkMessage::Publish {
topics: vec![topic.into()],
message,
})
.unwrap_or_else(|_| warn!(self.log, "Could not send gossip message."));
优先级队列
将收到的区块缓存到队列里面,按着高度的负数进行插入,这样每次获取队列元素第一个都是最小区块
,和本地上链高度比较。
- 如果高度刚好
等于
上链高度+1,则插入blockchain
小于
则丢弃大于
丢入队列。
if !self.queue.is_empty() {
let (block_low,height_low_negative) = self.queue.peek().unwrap();
let height_low_ref = *height_low_negative;
let height_low = (-height_low_ref) as u64;
if height_low > current_block.height() + 1 {
self.queue.push(block_low.clone(),height_low_ref);
} else if height_low == current_block.height() + 1 {
let broadcast = match self.chain.write().expect("").insert_block_ref(&block) {
Ok(_) => {
true
}
Err(e) => {
println!("network insert_block,Error: {:?}", e);
false
}
};
return broadcast
}
}
异步库
网络同步少不了异步线程,需要channel来传递消息。libp2p 0.16以前好像都是使用Tokio io
,之后换成了async std
。
futures
也发生了一些变化。
- 0.1 版本的 Future 签名中包含了一个 Error 关联类型,而且 poll 总是会返回一个 Result。
- 0.3 版本里该错误类型已被移除,对于错误需要显式处理。为了保持行为上的一致性,我们需要将代码里所有
Future<Item=Foo, Error=Bar>
替换为Future<Output=Result<Foo, Bar>>
(留意 Item 到 Output 的名称变化)
pool()方法返回值也变了
Async::Ready -> Poll::Pending
感兴趣的可以一起学习