-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Buffer votes for blocks we don't know about
Votes can arrive for blocks we aren't yet aware of in (at least) two circumstances: * If we disconnect and reconnect, we will download the blocks we missed, but nodes might send us their votes for the next block before we've received the missed blocks. * Due to network latency, a vote for a block proposal could arrive before the block proposal itself. Before this commit, the node ignores these votes and the network eventually recovers via a new view. However, this slows things down so we should recover faster if possible. Instead, we store votes for unknown blocks in memory and replay them if the block later becomes known to us. The implementation is fairly straight forward but there are a few caveats and TODOs: * The return type of `Consensus::proposal` is now more complicated, as it doesn't just return a `Message::Vote` any more. If the proposal results in some buffered votes being replayed and those votes form a supermajority, then the node can immediately propose the next block. * There's nothing which limits the memory usage of buffered votes. A malicious node is perfectly able to send us loads of votes with non-existant block hashes, which we will store forever. I've raised #719 to resolve this. * When applying buffered votes as a result of a proposal, they take priority over our own vote. This means we lose out on the cosigner reward. #720 * The unreliability test could be improved to be more efficient and to assert a stricter condition on the network - #721.
- Loading branch information
1 parent
b40fed1
commit 4385fc2
Showing
4 changed files
with
153 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
use crate::Network; | ||
|
||
#[zilliqa_macros::test] | ||
async fn blocks_are_produced_while_a_node_restarts(mut network: Network) { | ||
let restarted_node = network.random_index(); | ||
let wallet = network.wallet_of_node(restarted_node).await; | ||
|
||
// Select a wallet connected to a different node, so we can query the network when the first node is disconnected. | ||
let other_wallet = loop { | ||
let i = network.random_index(); | ||
if i != restarted_node { | ||
break i; | ||
} | ||
}; | ||
let other_wallet = network.wallet_of_node(other_wallet).await; | ||
|
||
// Produce a few blocks to start with. Enough for everyone to join the consensus committee. | ||
// TODO(#721): Once the committee is visible in the API, we can avoid waiting as long. | ||
network.run_until_block(&wallet, 8.into(), 400).await; | ||
|
||
// Disconnect the node we are 'restarting'. | ||
network.disconnect_node(restarted_node); | ||
|
||
// Produce 2 more blocks. | ||
network.run_until_block(&other_wallet, 10.into(), 400).await; | ||
|
||
// Reconnect the 'restarted' node. | ||
network.connect_node(restarted_node); | ||
|
||
// TODO(#721): We should assert here that a new view occurred if-and-only-if the 'restarted' node was the proposer | ||
// of blocks 3 or 4. This would tell us that we aren't producing new views unnecessarily. | ||
|
||
// Ensure more blocks are produced. | ||
network.run_until_block(&wallet, 12.into(), 400).await; | ||
} |