Line data Source code
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 105 : create_voting_schedule(const or_options_t *options, time_t now, int severity) 27 : { 28 105 : int interval, vote_delay, dist_delay; 29 105 : time_t start; 30 105 : time_t end; 31 105 : networkstatus_t *consensus; 32 105 : voting_schedule_t *new_voting_schedule; 33 : 34 105 : new_voting_schedule = tor_malloc_zero(sizeof(voting_schedule_t)); 35 : 36 105 : consensus = networkstatus_get_live_consensus(now); 37 : 38 105 : if (consensus) { 39 23 : interval = (int)( consensus->fresh_until - consensus->valid_after ); 40 23 : vote_delay = consensus->vote_seconds; 41 23 : 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 23 : new_voting_schedule->live_consensus_valid_after = consensus->valid_after; 46 : } else { 47 82 : interval = options->TestingV3AuthInitialVotingInterval; 48 82 : vote_delay = options->TestingV3AuthInitialVoteDelay; 49 82 : dist_delay = options->TestingV3AuthInitialDistDelay; 50 : } 51 : 52 105 : tor_assert(interval > 0); 53 105 : new_voting_schedule->interval = interval; 54 : 55 105 : if (vote_delay + dist_delay > interval/2) 56 5 : vote_delay = dist_delay = interval / 4; 57 : 58 210 : start = new_voting_schedule->interval_starts = 59 105 : voting_sched_get_start_of_interval_after(now,interval, 60 105 : options->TestingV3AuthVotingStartOffset); 61 210 : end = voting_sched_get_start_of_interval_after(start+1, interval, 62 105 : options->TestingV3AuthVotingStartOffset); 63 : 64 105 : tor_assert(end > start); 65 : 66 105 : new_voting_schedule->fetch_missing_signatures = start - (dist_delay/2); 67 105 : new_voting_schedule->voting_ends = start - dist_delay; 68 105 : new_voting_schedule->fetch_missing_votes = 69 105 : start - dist_delay - (vote_delay/2); 70 105 : new_voting_schedule->voting_starts = start - dist_delay - vote_delay; 71 : 72 : { 73 105 : char tbuf[ISO_TIME_LEN+1]; 74 105 : format_iso_time(tbuf, new_voting_schedule->interval_starts); 75 105 : 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 105 : 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 105 : voting_schedule_free_(voting_schedule_t *voting_schedule_to_free) 90 : { 91 105 : if (!voting_schedule_to_free) 92 : return; 93 105 : 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 81 : dirauth_get_voting_schedule(void) 105 : { 106 81 : time_t now = approx_time(); 107 81 : 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 81 : if (fast_mem_is_zero((const char *) &voting_schedule, 113 : sizeof(voting_schedule))) { 114 16 : need_to_recalculate_voting_schedule = true; 115 16 : 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 65 : const networkstatus_t *ns = networkstatus_get_live_consensus(now); 121 65 : if (ns && ns->valid_after != voting_schedule.live_consensus_valid_after) { 122 0 : 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 0 : need_to_recalculate_voting_schedule = true; 126 : } 127 : 128 65 : done: 129 16 : if (need_to_recalculate_voting_schedule) { 130 16 : dirauth_sched_recalculate_timing(get_options(), approx_time()); 131 16 : voting_schedule.created_on_demand = 1; 132 : } 133 : 134 81 : return &voting_schedule; 135 : } 136 : 137 : /** Return the next voting valid-after time. 138 : * 139 : * Dirauth only. */ 140 : time_t 141 18 : dirauth_sched_get_next_valid_after_time(void) 142 : { 143 18 : 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 63 : dirauth_sched_get_cur_valid_after_time(void) 154 : { 155 63 : const voting_schedule_t *sched = dirauth_get_voting_schedule(); 156 63 : time_t next_start = sched->interval_starts; 157 63 : int interval = sched->interval; 158 63 : int offset = get_options()->TestingV3AuthVotingStartOffset; 159 63 : 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 218 : dirauth_sched_get_configured_interval(void) 169 : { 170 218 : 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 105 : dirauth_sched_recalculate_timing(const or_options_t *options, time_t now) 178 : { 179 105 : voting_schedule_t *new_voting_schedule; 180 : 181 : /* get the new voting schedule */ 182 105 : new_voting_schedule = create_voting_schedule(options, now, LOG_INFO); 183 105 : tor_assert(new_voting_schedule); 184 : 185 : /* Fill in the global static struct now */ 186 105 : memcpy(&voting_schedule, new_voting_schedule, sizeof(voting_schedule)); 187 105 : voting_schedule_free(new_voting_schedule); 188 105 : }