diff --git a/src/lib_gossipsub/gossipsub_intf.ml b/src/lib_gossipsub/gossipsub_intf.ml index 350af6ec385f57ae33601352a6898218f1710e50..3612c9b97a4e7eb9a33176c0b092afaf54a89c80 100644 --- a/src/lib_gossipsub/gossipsub_intf.ml +++ b/src/lib_gossipsub/gossipsub_intf.ml @@ -409,6 +409,13 @@ module type SCORE = sig include PRINTABLE with type t := t val pp_value : Format.formatter -> value -> unit + + module Internal_for_tests : sig + val get_topic_params : + ('topic, 'span) score_parameters -> + 'topic -> + 'span per_topic_score_parameters + end end module type AUTOMATON = sig diff --git a/src/lib_gossipsub/peers_score.ml b/src/lib_gossipsub/peers_score.ml index 6ad3e338a803f5af86c0ad4e1ee2d41427aa503f..3f4906d0875a9601c129b4f66795ac6411f7fbaa 100644 --- a/src/lib_gossipsub/peers_score.ml +++ b/src/lib_gossipsub/peers_score.ml @@ -522,4 +522,8 @@ struct ] let pp_value = Fmt.float + + module Internal_for_tests = struct + let get_topic_params = get_topic_params + end end diff --git a/src/lib_gossipsub/test/test_gossipsub_shared.ml b/src/lib_gossipsub/test/test_gossipsub_shared.ml index 4a75519721f06bef06e878dfba53e573d1218b0b..0c7f21a3544632c564280d1c7ec9a601d2dbe826 100644 --- a/src/lib_gossipsub/test/test_gossipsub_shared.ml +++ b/src/lib_gossipsub/test/test_gossipsub_shared.ml @@ -36,6 +36,8 @@ module Milliseconds = struct let of_int_s n = {ms = n * 1000} + let to_int_ms {ms} = ms + let zero = {ms = 0} let add m1 m2 = of_int_ms (m1.ms + m2.ms) @@ -63,6 +65,8 @@ module Milliseconds = struct let to_int_s = to_int_s + let to_int_ms = to_int_ms + let to_float_s = to_float_s let of_int_s = of_int_s @@ -94,9 +98,9 @@ module Time = struct let now () = !t - let elapse s = - assert (s >= 0) ; - t := Milliseconds.add !t (Milliseconds.of_int_s s) + let elapse ms = + assert (Milliseconds.(ms >= zero)) ; + t := Milliseconds.add !t ms let set now = t := now diff --git a/src/lib_gossipsub/test/test_unit.ml b/src/lib_gossipsub/test/test_unit.ml index 47ca42fcb4d0a92045346d0e16fecf72cb86cd24..7fd637b1d0c813250bdadb007aa8fabf04d9efd3 100644 --- a/src/lib_gossipsub/test/test_unit.ml +++ b/src/lib_gossipsub/test/test_unit.ml @@ -946,7 +946,7 @@ let test_do_not_graft_within_backoff_period rng limits parameters = |> WithExceptions.Result.get_ok ~loc:__LOC__ |> List.fold_left (fun state i -> - Time.elapse 1 ; + Time.elapse @@ Milliseconds.of_int_s 1 ; Log.info "%d time tick(s) elapsed..." i ; let state, Heartbeat {to_graft; _} = GS.heartbeat state in let grafts = Peer.Map.bindings to_graft in @@ -960,7 +960,7 @@ let test_do_not_graft_within_backoff_period rng limits parameters = in (* After elapsing one more second, the backoff should be cleared and the graft should be emitted. *) - Time.elapse 1 ; + Time.elapse @@ Milliseconds.of_int_s 1 ; let _state, Heartbeat {to_graft; _} = GS.heartbeat state in let grafts = Peer.Map.bindings to_graft in Check.((List.length grafts = 1) int ~error_msg:"Expected %R, got %L" ~__LOC__) ; @@ -978,20 +978,40 @@ let test_unsubscribe_backoff rng limits parameters = ~tags:["gossipsub"; "heartbeat"; "join"; "leave"] @@ fun () -> let topic = "topic" in + let per_topic_score_parameters = + GS.Score.Internal_for_tests.get_topic_params limits.score_parameters topic + in + let mesh_message_deliveries_activation = + per_topic_score_parameters.mesh_message_deliveries_activation + in (* Only one peer => mesh too small and will try to regraft as early as possible *) let peers = make_peers ~number:1 in + (* Number of ticks until the unsubscribe backoff expires. *) + let backoff_ticks = 5 in + (* We must set [heartbeat_interval] so that + number_of_heartbeats_in_the_test * [heartbeat_interval] < [mesh_message_deliveries_activation] + holds. This prevents surpassing [mesh_message_deliveries_activation] within the test, + thus avoiding the activation of p3 penalty. Since number_of_heartbeats_in_the_test + is [backoff_ticks + 2], we set [heartbeat_interval] as the following.*) + let heartbeat_interval = + (Milliseconds.to_int_ms mesh_message_deliveries_activation - 1) + / (backoff_ticks + 2) + |> Milliseconds.of_int_ms + in + (* Time required until unsubscribe backoff expires. *) + let unsubscribe_backoff = + Milliseconds.(of_int_ms @@ (backoff_ticks * to_int_ms heartbeat_interval)) + in let state = init_state ~rng ~limits: { limits with + heartbeat_interval; (* Run backoff clearing on every heartbeat tick. *) backoff_cleanup_ticks = 1; - (* We will run the heartbeat tick on each time tick to simplify the test. *) - heartbeat_interval = Milliseconds.of_int_s 1; - (* Set unsubscribe backoff to 5. *) - unsubscribe_backoff = Milliseconds.of_int_s 5; + unsubscribe_backoff; } ~parameters ~peers @@ -1002,14 +1022,14 @@ let test_unsubscribe_backoff rng limits parameters = (* Peer unsubscribes then subscribes from topic. *) let state, _ = GS.leave {topic} state in let state, _ = GS.join {topic} state in - (* No graft should be emitted until 7 time ticks pass. - The additional 2 time ticks from the backoff is due to the "backoff slack". *) + (* No graft should be emitted until [(backoff_ticks + 2) * heartbeat_interval] elapse. + The additional 2 [heartbeat_interval] is due to the "backoff slack". *) let state = - List.init ~when_negative_length:() 6 (fun i -> i + 1) + List.init ~when_negative_length:() (backoff_ticks + 1) (fun i -> i + 1) |> WithExceptions.Result.get_ok ~loc:__LOC__ |> List.fold_left (fun state i -> - Time.elapse 1 ; + Time.elapse @@ heartbeat_interval ; Log.info "%d time tick(s) elapsed..." i ; let state, Heartbeat {to_graft; _} = GS.heartbeat state in let grafts = Peer.Map.bindings to_graft in @@ -1021,9 +1041,9 @@ let test_unsubscribe_backoff rng limits parameters = state) state in - (* After elapsing one more second, + (* After elapsing one more [heartbeat_interval], the backoff should be cleared and the graft should be emitted. *) - Time.elapse 1 ; + Time.elapse @@ heartbeat_interval ; let _state, Heartbeat {to_graft; _} = GS.heartbeat state in let grafts = Peer.Map.bindings to_graft in Check.((List.length grafts = 1) int ~error_msg:"Expected %R, got %L" ~__LOC__) ; diff --git a/src/lib_gossipsub/tezos_gossipsub.ml b/src/lib_gossipsub/tezos_gossipsub.ml index 2ece1d7a37808513e00b6f00346807c9cbd597a4..34b4f907a5f55995b4d00b3a76700f16c0fa7329 100644 --- a/src/lib_gossipsub/tezos_gossipsub.ml +++ b/src/lib_gossipsub/tezos_gossipsub.ml @@ -1110,6 +1110,15 @@ module Make (C : AUTOMATON_CONFIG) : in return (Peer.Set.union more_peers valid_fanout_peers) in + (* Notify scoring about the graft. *) + let scores = + Peer.Set.fold + (fun peer scores -> + update_scores_score peer (fun s -> Score.graft s topic) scores) + peers + scores + in + let* () = set_scores scores in let* () = set_mesh_topic topic peers in let* () = delete_fanout topic in Joining_topic {to_graft = peers} |> return @@ -1608,6 +1617,16 @@ module Make (C : AUTOMATON_CONFIG) : backoff |> set_backoff in + (* Notify scoring about the grafts. *) + let scores = + Peer.Map.fold + (fun peer -> + Topic.Set.fold (fun topic -> + update_scores_score peer (fun s -> Score.graft s topic))) + to_graft + scores + in + let* () = set_scores scores in (* Update mesh for grafted and pruned peers *) let* () = update_mesh mesh ~to_graft ~to_prune in return (to_graft, to_prune, noPX_peers)