tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 }