voting_schedule.c (6090B)
1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file voting_schedule.c 6 * \brief Compute information about our voting schedule as a directory 7 * authority. 8 **/ 9 10 #include "feature/dirauth/voting_schedule.h" 11 12 #include "core/or/or.h" 13 #include "app/config/config.h" 14 #include "feature/nodelist/networkstatus.h" 15 16 #include "feature/nodelist/networkstatus_st.h" 17 18 /* ===== 19 * Vote scheduling 20 * ===== */ 21 22 /* Populate and return a new voting_schedule_t that can be used to schedule 23 * voting. The object is allocated on the heap and it's the responsibility of 24 * the caller to free it. Can't fail. */ 25 static voting_schedule_t * 26 create_voting_schedule(const or_options_t *options, time_t now, int severity) 27 { 28 int interval, vote_delay, dist_delay; 29 time_t start; 30 time_t end; 31 networkstatus_t *consensus; 32 voting_schedule_t *new_voting_schedule; 33 34 new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t)); 35 36 consensus = networkstatus_get_live_consensus(now); 37 38 if (consensus) { 39 interval = (int)( consensus->fresh_until - consensus->valid_after ); 40 vote_delay = consensus->vote_seconds; 41 dist_delay = consensus->dist_seconds; 42 43 /* Note down the consensus valid after, so that we detect outdated voting 44 * schedules in case of skewed clocks etc. */ 45 new_voting_schedule->live_consensus_valid_after = consensus->valid_after; 46 } else { 47 interval = options->TestingV3AuthInitialVotingInterval; 48 vote_delay = options->TestingV3AuthInitialVoteDelay; 49 dist_delay = options->TestingV3AuthInitialDistDelay; 50 } 51 52 tor_assert(interval > 0); 53 new_voting_schedule->interval = interval; 54 55 if (vote_delay + dist_delay > interval/2) 56 vote_delay = dist_delay = interval / 4; 57 58 start = new_voting_schedule->interval_starts = 59 voting_sched_get_start_of_interval_after(now,interval, 60 options->TestingV3AuthVotingStartOffset); 61 end = voting_sched_get_start_of_interval_after(start+1, interval, 62 options->TestingV3AuthVotingStartOffset); 63 64 tor_assert(end > start); 65 66 new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2); 67 new_voting_schedule->voting_ends = start - dist_delay; 68 new_voting_schedule->fetch_missing_votes = 69 start - dist_delay - (vote_delay/2); 70 new_voting_schedule->voting_starts = start - dist_delay - vote_delay; 71 72 { 73 char tbuf[ISO_TIME_LEN+1]; 74 format_iso_time(tbuf, new_voting_schedule->interval_starts); 75 tor_log(severity, LD_DIR,"Choosing expected valid-after time as %s: " 76 "consensus_set=%d, interval=%d", 77 tbuf, consensus?1:0, interval); 78 } 79 80 return new_voting_schedule; 81 } 82 83 #define voting_schedule_free(s) \ 84 FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s)) 85 86 /** Frees a voting_schedule_t. This should be used instead of the generic 87 * tor_free. */ 88 static void 89 voting_schedule_free_(voting_schedule_t *voting_schedule_to_free) 90 { 91 if (!voting_schedule_to_free) 92 return; 93 tor_free(voting_schedule_to_free); 94 } 95 96 voting_schedule_t voting_schedule; 97 98 /** 99 * Return the current voting schedule, recreating it if necessary. 100 * 101 * Dirauth only. 102 **/ 103 static const voting_schedule_t * 104 dirauth_get_voting_schedule(void) 105 { 106 time_t now = approx_time(); 107 bool need_to_recalculate_voting_schedule = false; 108 109 /* This is a safe guard in order to make sure that the voting schedule 110 * static object is at least initialized. Using this function with a zeroed 111 * voting schedule can lead to bugs. */ 112 if (fast_mem_is_zero((const char *) &voting_schedule, 113 sizeof(voting_schedule))) { 114 need_to_recalculate_voting_schedule = true; 115 goto done; /* no need for next check if we have to recalculate anyway */ 116 } 117 118 /* Also make sure we are not using an outdated voting schedule. If we have a 119 * newer consensus, make sure we recalculate the voting schedule. */ 120 const networkstatus_t *ns = networkstatus_get_live_consensus(now); 121 if (ns && ns->valid_after != voting_schedule.live_consensus_valid_after) { 122 log_info(LD_DIR, "Voting schedule is outdated: recalculating (%d/%d)", 123 (int) ns->valid_after, 124 (int) voting_schedule.live_consensus_valid_after); 125 need_to_recalculate_voting_schedule = true; 126 } 127 128 done: 129 if (need_to_recalculate_voting_schedule) { 130 dirauth_sched_recalculate_timing(get_options(), approx_time()); 131 voting_schedule.created_on_demand = 1; 132 } 133 134 return &voting_schedule; 135 } 136 137 /** Return the next voting valid-after time. 138 * 139 * Dirauth only. */ 140 time_t 141 dirauth_sched_get_next_valid_after_time(void) 142 { 143 return dirauth_get_voting_schedule()->interval_starts; 144 } 145 146 /** 147 * Return our best idea of what the valid-after time for the _current_ 148 * consensus, whether we have one or not. 149 * 150 * Dirauth only. 151 **/ 152 time_t 153 dirauth_sched_get_cur_valid_after_time(void) 154 { 155 const voting_schedule_t *sched = dirauth_get_voting_schedule(); 156 time_t next_start = sched->interval_starts; 157 int interval = sched->interval; 158 int offset = get_options()->TestingV3AuthVotingStartOffset; 159 return voting_sched_get_start_of_interval_after(next_start - interval - 1, 160 interval, 161 offset); 162 } 163 164 /** Return the voting interval that we are configured to use. 165 * 166 * Dirauth only. */ 167 int 168 dirauth_sched_get_configured_interval(void) 169 { 170 return get_options()->V3AuthVotingInterval; 171 } 172 173 /** Set voting_schedule to hold the timing for the next vote we should be 174 * doing. All type of tor do that because HS subsystem needs the timing as 175 * well to function properly. */ 176 void 177 dirauth_sched_recalculate_timing(const or_options_t *options, time_t now) 178 { 179 voting_schedule_t *new_voting_schedule; 180 181 /* get the new voting schedule */ 182 new_voting_schedule = create_voting_schedule(options, now, LOG_INFO); 183 tor_assert(new_voting_schedule); 184 185 /* Fill in the global static struct now */ 186 memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); 187 voting_schedule_free(new_voting_schedule); 188 }