Tor accepts zero bandwidths, but they trigger bugs in older Tor implementations. Therefore, scaling methods SHOULD perform the following checks: * If the total bandwidth is zero, all relays should be given equal bandwidths. * If the scaled bandwidth is zero, it should be rounded up to one.
Initial experiments indicate that scaling may not be needed for torflow and sbws, because their measured bandwidths are similar enough already.
If scaling is required, here is a simple linear bandwidth scaling method, which ensures that all bandwidth votes contain approximately the same total bandwidth:
1. Calculate the relay quota by dividing the total measured bandwidth in all votes, by the number of relays with measured bandwidth votes. In the public tor network, this is approximately 7500 as of April 2018. The quota should be a consensus parameter, so it can be adjusted for all generators on the network. 2. Calculate a vote quota by multiplying the relay quota by the number of relays this bandwidth authority has measured bandwidths for. 3. Calculate a scaling factor by dividing the vote quota by the total unscaled measured bandwidth in this bandwidth authority's upcoming vote. 4. Multiply each unscaled measured bandwidth by the scaling factor.
Now, the total scaled bandwidth in the upcoming vote is approximately equal to the quota.
If all generators are using scaling, the quota can be gradually reduced or increased as needed. Smaller quotas decrease the size of uncompressed consensuses, and may decrease the size of consensus diffs and compressed consensuses. But if the relay quota is too small, some relays may be over- or under-weighted.
Torflow implements two methods to compute the bandwidth values from the (stream) bandwidth measurements: with and without PID control feedback. The method described here is without PID control (see Torflow specification, section 2.2).
In the following sections, the relays' measured bandwidth refer to the ones that this bandwidth authority has measured for the relays that would be included in the next bandwidth authority's upcoming vote.
1. Calculate the filtered bandwidth for each relay: - choose the relay's measurements (`bw_j`) that are equal or greater than the mean of the measurements for this relay - calculate the mean of those measurements In pseudocode: bw_filt_i = mean(max(mean(bw_j), bw_j)) 2. Calculate network averages: - calculate the filtered average by dividing the sum of all the relays' filtered bandwidth by the number of relays that have been measured (`n`), ie, calculate the mean average of the relays' filtered bandwidth. - calculate the stream average by dividing the sum of all the relays' measured bandwidth by the number of relays that have been measured (`n`), ie, calculate the mean average or the relays' measured bandwidth. In pseudocode: bw_avg_filt_ = bw_filt_i / n bw_avg_strm = bw_i / n 3. Calculate ratios for each relay: - calculate the filtered ratio by dividing each relay filtered bandwidth by the filtered average - calculate the stream ratio by dividing each relay measured bandwidth by the stream average In pseudocode:
r_filt_i = bw_filt_i / bw_avg_filt r_strm_i = bw_i / bw_avg_strm
4. Calculate the final ratio for each relay: The final ratio is the larger between the filtered bandwidth's and the stream bandwidth's ratio. In pseudocode: r_i = max(r_filt_i, r_strm_i) 5. Calculate the scaled bandwidth for each relay: The most recent descriptor observed bandwidth (`bw_obs_i`) is multiplied by the ratio In pseudocode: bw_new_i = r_i * bw_obs_i
<<In this way, the resulting network status consensus bandwidth values are effectively re-weighted proportional to how much faster the node was as compared to the rest of the network.>>