Skip to content

Commit b40ea1a

Browse files
acatangiuukint-vs
authored andcommitted
client/beefy: request justifs from peers further in consensus (paritytech#13343)
For on-demand justifications, peer selection is based on witnessed gossip votes. This commit changes the condition for selecting a peer to request justification for `block` from "last voted on >= `block`" to "peer last voted on strict > `block`". When allowing `>=` we see nodes continuously spamming unsuccessful on-demand requests to nodes which are still voting on a block without having a justification available. One way to fix the spam would be to add some rate-limiting or backoff period when requesting justifications. The other solution (present in this commit) is to simply request justifications from peers that are voting on future blocks so we know they're _guaranteed_ to have the wanted mandatory justification available to send back. Signed-off-by: acatangiu <[email protected]>
1 parent 374304c commit b40ea1a

File tree

4 files changed

+24
-25
lines changed

4 files changed

+24
-25
lines changed

client/beefy/src/communication/peers.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ impl<B: Block> KnownPeers<B> {
5757
self.live.remove(peer);
5858
}
5959

60-
/// Return _filtered and cloned_ list of peers that have voted on `block` or higher.
61-
pub fn at_least_at_block(&self, block: NumberFor<B>) -> VecDeque<PeerId> {
60+
/// Return _filtered and cloned_ list of peers that have voted on higher than `block`.
61+
pub fn further_than(&self, block: NumberFor<B>) -> VecDeque<PeerId> {
6262
self.live
6363
.iter()
64-
.filter_map(|(k, v)| (v.last_voted_on >= block).then_some(k))
64+
.filter_map(|(k, v)| (v.last_voted_on > block).then_some(k))
6565
.cloned()
6666
.collect()
6767
}
@@ -92,32 +92,32 @@ mod tests {
9292
assert!(peers.contains(&bob));
9393
assert!(peers.contains(&charlie));
9494

95-
// Get peers at block >= 5
96-
let at_5 = peers.at_least_at_block(5);
95+
// Get peers at block > 4
96+
let further_than_4 = peers.further_than(4);
9797
// Should be Bob and Charlie
98-
assert_eq!(at_5.len(), 2);
99-
assert!(at_5.contains(&bob));
100-
assert!(at_5.contains(&charlie));
98+
assert_eq!(further_than_4.len(), 2);
99+
assert!(further_than_4.contains(&bob));
100+
assert!(further_than_4.contains(&charlie));
101101

102102
// 'Tracked' Alice seen voting for 10.
103103
peers.note_vote_for(alice, 10);
104104

105-
// Get peers at block >= 9
106-
let at_9 = peers.at_least_at_block(9);
105+
// Get peers at block > 9
106+
let further_than_9 = peers.further_than(9);
107107
// Should be Charlie and Alice
108-
assert_eq!(at_9.len(), 2);
109-
assert!(at_9.contains(&charlie));
110-
assert!(at_9.contains(&alice));
108+
assert_eq!(further_than_9.len(), 2);
109+
assert!(further_than_9.contains(&charlie));
110+
assert!(further_than_9.contains(&alice));
111111

112112
// Remove Alice
113113
peers.remove(&alice);
114114
assert_eq!(peers.live.len(), 2);
115115
assert!(!peers.contains(&alice));
116116

117117
// Get peers at block >= 9
118-
let at_9 = peers.at_least_at_block(9);
118+
let further_than_9 = peers.further_than(9);
119119
// Now should be just Charlie
120-
assert_eq!(at_9.len(), 1);
121-
assert!(at_9.contains(&charlie));
120+
assert_eq!(further_than_9.len(), 1);
121+
assert!(further_than_9.contains(&charlie));
122122
}
123123
}

client/beefy/src/communication/request_response/outgoing_requests_engine.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<B: Block> OnDemandJustificationsEngine<B> {
8080

8181
fn reset_peers_cache_for_block(&mut self, block: NumberFor<B>) {
8282
// TODO (issue #12296): replace peer selection with generic one that involves all protocols.
83-
self.peers_cache = self.live_peers.lock().at_least_at_block(block);
83+
self.peers_cache = self.live_peers.lock().further_than(block);
8484
}
8585

8686
fn try_next_peer(&mut self) -> Option<PeerId> {
@@ -199,7 +199,6 @@ impl<B: Block> OnDemandJustificationsEngine<B> {
199199
let (peer, req_info, resp) = match &mut self.state {
200200
State::Idle => {
201201
futures::pending!();
202-
// Doesn't happen as 'futures::pending!()' is an 'await' barrier that never passes.
203202
return None
204203
},
205204
State::AwaitingResponse(peer, req_info, receiver) => {

client/beefy/src/tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ async fn on_demand_beefy_justification_sync() {
893893
[BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave];
894894
let validator_set = ValidatorSet::new(make_beefy_ids(&all_peers), 0).unwrap();
895895
let session_len = 5;
896-
let min_block_delta = 5;
896+
let min_block_delta = 4;
897897

898898
let mut net = BeefyTestNet::new(4);
899899

@@ -912,7 +912,7 @@ async fn on_demand_beefy_justification_sync() {
912912
let dave_index = 3;
913913

914914
// push 30 blocks
915-
let hashes = net.generate_blocks_and_sync(30, session_len, &validator_set, false).await;
915+
let hashes = net.generate_blocks_and_sync(35, session_len, &validator_set, false).await;
916916

917917
let fast_peers = fast_peers.into_iter().enumerate();
918918
let net = Arc::new(Mutex::new(net));
@@ -921,7 +921,7 @@ async fn on_demand_beefy_justification_sync() {
921921
finalize_block_and_wait_for_beefy(
922922
&net,
923923
fast_peers.clone(),
924-
&[hashes[1], hashes[6], hashes[10], hashes[17], hashes[24]],
924+
&[hashes[1], hashes[6], hashes[10], hashes[17], hashes[23]],
925925
&[1, 5, 10, 15, 20],
926926
)
927927
.await;
@@ -941,12 +941,12 @@ async fn on_demand_beefy_justification_sync() {
941941
// freshly spun up Dave now needs to listen for gossip to figure out the state of their peers.
942942

943943
// Have the other peers do some gossip so Dave finds out about their progress.
944-
finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25]], &[25]).await;
944+
finalize_block_and_wait_for_beefy(&net, fast_peers, &[hashes[25], hashes[29]], &[25, 29]).await;
945945

946946
// Now verify Dave successfully finalized #1 (through on-demand justification request).
947947
wait_for_best_beefy_blocks(dave_best_blocks, &net, &[1]).await;
948948

949-
// Give Dave all tasks some cpu cycles to burn through their events queues,
949+
// Give all tasks some cpu cycles to burn through their events queues,
950950
run_for(Duration::from_millis(100), &net).await;
951951
// then verify Dave catches up through on-demand justification requests.
952952
finalize_block_and_wait_for_beefy(
@@ -959,7 +959,7 @@ async fn on_demand_beefy_justification_sync() {
959959

960960
let all_peers = all_peers.into_iter().enumerate();
961961
// Now that Dave has caught up, sanity check voting works for all of them.
962-
finalize_block_and_wait_for_beefy(&net, all_peers, &[hashes[30]], &[30]).await;
962+
finalize_block_and_wait_for_beefy(&net, all_peers, &[hashes[30], hashes[34]], &[30]).await;
963963
}
964964

965965
#[tokio::test]

client/beefy/src/worker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,6 @@ where
555555
let block_number = vote.commitment.block_number;
556556
match rounds.add_vote(vote) {
557557
VoteImportResult::RoundConcluded(signed_commitment) => {
558-
self.gossip_validator.conclude_round(block_number);
559558
metric_set!(self, beefy_round_concluded, block_number);
560559

561560
let finality_proof = VersionedFinalityProof::V1(signed_commitment);
@@ -602,6 +601,7 @@ where
602601

603602
// Finalize inner round and update voting_oracle state.
604603
self.persisted_state.voting_oracle.finalize(block_num)?;
604+
self.gossip_validator.conclude_round(block_num);
605605

606606
if block_num > self.best_beefy_block() {
607607
// Set new best BEEFY block number.

0 commit comments

Comments
 (0)