mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 04:39:24 +00:00
Don't return from sync_block until the Tendermint machine returns if it's valid or not
We had a race condition where'd we be informed of blocks 1 .. 3, and immediately add 1 .. 3. Because we immediately tried to add 2 after 1, it'd fail since the tip was still the genesis, yet 2 needs the tip to be 1. Adding a channel, while ugly, was the simplest way to accomplish this. Also has any added block be broadcasted. Else there's a race condition where a node which syncs up to the most recent block does so, yet fails to add the next block when it's committed to.
This commit is contained in:
@@ -9,7 +9,7 @@ use std::{
|
||||
use parity_scale_codec::{Encode, Decode};
|
||||
|
||||
use futures::{
|
||||
FutureExt, StreamExt,
|
||||
FutureExt, StreamExt, SinkExt,
|
||||
future::{self, Fuse},
|
||||
channel::mpsc,
|
||||
};
|
||||
@@ -135,6 +135,7 @@ pub struct TendermintMachine<N: Network> {
|
||||
queue: VecDeque<MessageFor<N>>,
|
||||
msg_recv: mpsc::UnboundedReceiver<SignedMessageFor<N>>,
|
||||
synced_block_recv: mpsc::UnboundedReceiver<SyncedBlock<N>>,
|
||||
synced_block_result_send: mpsc::UnboundedSender<bool>,
|
||||
|
||||
block: BlockData<N>,
|
||||
}
|
||||
@@ -146,6 +147,7 @@ pub struct SyncedBlock<N: Network> {
|
||||
}
|
||||
|
||||
pub type SyncedBlockSender<N> = mpsc::UnboundedSender<SyncedBlock<N>>;
|
||||
pub type SyncedBlockResultReceiver = mpsc::UnboundedReceiver<bool>;
|
||||
|
||||
pub type MessageSender<N> = mpsc::UnboundedSender<SignedMessageFor<N>>;
|
||||
|
||||
@@ -154,6 +156,8 @@ pub struct TendermintHandle<N: Network> {
|
||||
/// Channel to trigger the machine to move to the next block.
|
||||
/// Takes in the the previous block's commit, along with the new proposal.
|
||||
pub synced_block: SyncedBlockSender<N>,
|
||||
/// A channel to communicate the result of a synced_block message.
|
||||
pub synced_block_result: SyncedBlockResultReceiver,
|
||||
/// Channel to send messages received from the P2P layer.
|
||||
pub messages: MessageSender<N>,
|
||||
/// Tendermint machine to be run on an asynchronous task.
|
||||
@@ -253,8 +257,10 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
||||
) -> TendermintHandle<N> {
|
||||
let (msg_send, msg_recv) = mpsc::unbounded();
|
||||
let (synced_block_send, synced_block_recv) = mpsc::unbounded();
|
||||
let (synced_block_result_send, synced_block_result_recv) = mpsc::unbounded();
|
||||
TendermintHandle {
|
||||
synced_block: synced_block_send,
|
||||
synced_block_result: synced_block_result_recv,
|
||||
messages: msg_send,
|
||||
machine: {
|
||||
let sys_time = sys_time(last_time);
|
||||
@@ -275,6 +281,7 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
||||
queue: VecDeque::new(),
|
||||
msg_recv,
|
||||
synced_block_recv,
|
||||
synced_block_result_send,
|
||||
|
||||
block: BlockData::new(
|
||||
weights,
|
||||
@@ -313,16 +320,19 @@ impl<N: Network + 'static> TendermintMachine<N> {
|
||||
if let Some(SyncedBlock { number, block, commit }) = msg {
|
||||
// Commit is for a block we've already moved past
|
||||
if number != self.block.number {
|
||||
self.synced_block_result_send.send(false).await.unwrap();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Commit is invalid
|
||||
if !self.network.verify_commit(block.id(), &commit) {
|
||||
self.synced_block_result_send.send(false).await.unwrap();
|
||||
continue;
|
||||
}
|
||||
|
||||
let proposal = self.network.add_block(block, commit.clone()).await;
|
||||
self.reset_by_commit(commit, proposal).await;
|
||||
self.synced_block_result_send.send(true).await.unwrap();
|
||||
None
|
||||
} else {
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user