在閱讀本篇之前, 請先查看
泰嶽鏈使用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
感興趣的可以一起學習