Rough sketch of structures and APIs for prop 271 implementation; see #19858 / #19877 and

 * Any new per-guard state prop 271 needs should go in the existing
 * entry_guard_t structure.  New structures for global guard-selection
 * state.

typedef struct {
   * old_entry_guards replaces the global smartlist_t *entry_guards of
   * entrynodes.c for purposes of ticket #19858.  We should maintain it
   * as part of the guard state as long as we want the ability to fall
   * back to the old pre-prop271 guard behavior.
   * NM: Recommendation: rename to legacy_entry_guards, to make it clear
   *   that this is for backward compat.
  smartlist_t *old_entry_guards;

   * List of entry_guard_t for known guards
   * This is updated on new consensus; since it is the current known
   * guard set, we don't need to save it to disk.  The sampled guard list
   * is used to store guard state we need to persist if a guard drops out
   * of the consensus.
  smartlist_t *guards;

   * List of sampled guards
   * NM: Do these alias "guards" ?  Guessing not, since we want this to be able to hold
   *   items that 'guards' doesn't hold, yeah?
  smartlist_t *sampled_guards;

   * TODO path bias state

   * List of filtered guards, derived from sampled_guards and path bias.
   * Update on updates to either of those inputs or influencing configuration.
   * NM: Do these alias "sampled guards" ?
  smartlist_t *filtered_guards.

   * Subset of filtered guards we think we can use.  Update on updates
   * filtered_guards, or to any of the state that influences the usability
   * decision.
   * NM: Q again re aliasing.
  smartlist_t *usable_filtered_guards.

   * Ordered list of confirmed guards; this should be reconstructible
   * from per-guard state in sampled_guards, so we shouldn't need to
   * store it separately on disk, but we do need to be sure entry_guard_t
   * gets extended with relevant ordering info.
   * NM: Q again re aliasing.
  smartlist_t *confirmed_guards;

   * Ordered list of primary guards derived from filtered guards and confirmed
   * guards; update whenever those sets change, do not need to store
   * separately on disk.
  smartlist_t *primary_gurads;
} guard_selection_t;

// NM Recommendation: make this structure mostly opaque; only provide const-list accessors.
// NM recommendation: whenever set A is always a subset of set B, we can just represent
//         A-membership with a flag that can be set on B members.  That might save us some
//         grief.
// NM recommendation: Give each guard_selection_t a name that indicates _which_ guard selection
//         it is, so we can log the name as needed, persist them correctly, etc.

/* API */

Global guard_selection_t state management functions should be able to load/
store guard state to disk, merge in info from new consensus.

We'll also need to store path bias state along with sampled_guards, since
that's independently upstream of filtered_guards.

Sampled guards will need load/store mechanism, ability to merge in new
guard from consensus.  This is also the primary repository of guard info;
other data structures are derived from it.  As such, they do not themselves
need to be loaded/stored on disk, but for efficiency of implementation we'll
end up storing them in memory.  The functions to derive those guard sets from
the upstream data structures should be well-defined and unit-testable, and
moreover this means we should introduce consistency-checking functions and
a debug mode to assert if the data structures manage to become inconsistent.
(cf. the CMUX_PARANOIA #define in circuitmux.c).

Two broad groups of API functions:

1.) Guard-selection state updating events: we'll need APIs for handling a new consensus, as well as for circuit failure/success notification (i.e., update path
bias state and guard reachability).

2.) Guard-selection queries.  Pick new guard for circuit, most prominently.

3.) /*NM*/ Accessors to get the right guard_selection_t for a given circuit/configuration.
Last modified 3 years ago Last modified on Sep 12, 2016, 3:56:08 PM