From 5359206aae3412ec92a29f7aa6c4dc40b34cecfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <andre.beat@gmail.com> Date: Thu, 22 Aug 2019 10:35:45 +0200 Subject: [PATCH] grandpa: validate honest out of scope catch ups are for the previous set (#3453) --- .../src/communication/gossip.rs | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/substrate/core/finality-grandpa/src/communication/gossip.rs b/substrate/core/finality-grandpa/src/communication/gossip.rs index 20a629b6ae3..5fd09620e92 100644 --- a/substrate/core/finality-grandpa/src/communication/gossip.rs +++ b/substrate/core/finality-grandpa/src/communication/gossip.rs @@ -729,7 +729,9 @@ impl<Block: BlockT> Inner<Block> { // race where the peer sent us the request before it observed that // we had transitioned to a new set. In this case we charge a lower // cost. - if local_view.round.0.saturating_sub(CATCH_UP_THRESHOLD) == 0 { + if request.set_id.0.saturating_add(1) == local_view.set_id.0 && + local_view.round.0.saturating_sub(CATCH_UP_THRESHOLD) == 0 + { return (None, Action::Discard(cost::HONEST_OUT_OF_SCOPE_CATCH_UP)); } @@ -1600,4 +1602,84 @@ mod tests { _ => panic!("expected catch up message"), }; } + + #[test] + fn detects_honest_out_of_scope_catch_requests() { + let set_state = voter_set_state(); + let (val, _) = GossipValidator::<Block>::new( + config(), + set_state.clone(), + ); + + // the validator starts at set id 2 + val.note_set(SetId(2), Vec::new(), |_, _| {}); + + // add the peer making the request to the validator, + // otherwise it is discarded + let peer = PeerId::random(); + val.inner.write().peers.new_peer(peer.clone()); + + let send_request = |set_id, round| { + let mut inner = val.inner.write(); + inner.handle_catch_up_request( + &peer, + CatchUpRequestMessage { + set_id: SetId(set_id), + round: Round(round), + }, + &set_state, + ) + }; + + let assert_res = |res: (Option<_>, Action<_>), honest| { + assert!(res.0.is_none()); + assert_eq!( + res.1, + if honest { + Action::Discard(cost::HONEST_OUT_OF_SCOPE_CATCH_UP) + } else { + Action::Discard(Misbehavior::OutOfScopeMessage.cost()) + }, + ); + }; + + // the validator is at set id 2 and round 0. requests for set id 1 + // should not be answered but they should be considered an honest + // mistake + assert_res( + send_request(1, 1), + true, + ); + + assert_res( + send_request(1, 10), + true, + ); + + // requests for set id 0 should be considered out of scope + assert_res( + send_request(0, 1), + false, + ); + + assert_res( + send_request(0, 10), + false, + ); + + // after the validator progresses further than CATCH_UP_THRESHOLD in set + // id 2, any request for set id 1 should no longer be considered an + // honest mistake. + val.note_round(Round(3), |_, _| {}); + + assert_res( + send_request(1, 1), + false, + ); + + assert_res( + send_request(1, 2), + false, + ); + } } -- GitLab