<div dir="ltr"><div>Hi, Juga! <br><br>This is a review of the document from <a href="https://raw.githubusercontent.com/juga0/torspec/c7f06023dd1d5d47adad128de541f8eba2a13bfb/bandwidth-file-spec.txt">https://raw.githubusercontent.com/juga0/torspec/c7f06023dd1d5d47adad128de541f8eba2a13bfb/bandwidth-file-spec.txt</a> , which I *think* is the same as the document you have below.<br></div><div><br></div><div>I'm reviewing this as though it were a fully new format, since I'm not sure how much we already have locked-in based on existing code, and how much is new.  We might decide that backward compatibility is more important than consistency, and if so, we won't want to take all of my recommendations here.<br></div><div><div><br><br>>           Tor Bandwidth Measurements Document Format<br>>                             juga<br>>                             teor<br>><br>> 1. Scope and preliminaries<br>><br>>   This document describes the format of Tor's bandwidth measurements<br>>   document, version 1.0.0 and later.<br><br>Suggestion: Maybe explicitly say "1.0.0, 1.1.0, and later"?<br><br>>   Since Tor version 0.2.4.12-alpha the directory<br>>   authorities use the bandwidth measurements document called<br>>   "V3BandwidthsFile" and produced by Torflow [1]<br>>   (format described in README.spec.txt [2]).<br><br>Recommendation: "Format described in Torflow's README.spec.txt".<br><br>Explanation needed: Is this a new format, or a new specification of the<br>existing format?  Let's say so here.<br><br>Question: If this is a different format, and we're calling it version<br>1.0.0, what should we call the old one?  But later it seems that we're<br>introducing 1.1.0, and we're calling the old one 1.0.0.<br><br>Suggestion: let's be explicit that we're only describing the format<br>here, and *not* describing how bwauths generate their data.<br><br><br>>     The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL<br>>     NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and<br>>     "OPTIONAL" in this document are to be interpreted as described in<br>>     RFC 2119.<br>><br>> 1.2. Acknowledgements<br>><br>>   The original bandwidth measurement scanner (Torflow) and format was<br>>   created by mike. Teor suggested to write this specification while<br>>   contributing on pastly's new bandwidth scanner implementation.<br>><br>>   This specification was revised after feedback from:<br>><br>>     XXX<br>><br>> 1.3 Outline<br>><br>>   The bandwidth measurements mentioned in sections 3.4.1 and 3.4.2<br>>   of "Tor directory protocol" (dir-spec.txt) [3] are obtained<br>>   by bandwidth authorities, which generate a file storing information<br>>   on relays' measured bandwidth capacities.<br>><br>> 1.4. Format Versions<br>><br>>    1.0.0 - The legacy fallback bandwidth measurements document format<br>><br>>    1.1.0 - Adds key_value lines to the header, format version,<br>>            optional ones and section separator.<br><br>Information: Let's repeat in this section which versions of Tor can<br>consume these versions.<br><br>> 2. Format details<br>><br>>   Bandwidth measurements MUST contain the following sections:<br>>   - Header (exactly once)<br>>   - Relays measurements (zero or more times)<br><br>Grammar suggestion: "Relay measurements".<br><br><br><br>> 2.1. Definitions<br>><br>>   The following nonterminals are defined in dir-spec.txt, sections<br>>   1.2., 2.1.1., <a href="http://2.1.3.">2.1.3.</a>:<br>><br>>     Int<br>>     SP (space)<br>>     NL (newline)<br>>     Keyword<br>>     ArgumentChar<br>>     fingerprint (hexdigest)<br><br></div><div>Does this have to start with a "$" ?  I think it does.  Maybe we should be explicit about that.<br></div><div><br>>     nickname<br>><br>>   Nonterminals defined in "Tor Directory List Format" (dir-list-spec.txt),<br>>   section <a href="http://2.2.1.">2.2.1.</a>:<br>><br>>     version_number<br>><br>>   We define the following nonterminals:<br>><br>>     value ::= ArgumentChar+<br>>     key_value ::= Keyword "=" value<br>>     line ::= ArgumentChar* NL<br>>     timestamp ::= Int<br>>     bandwidth ::= Int<br>>     relay_line ::= key_value (SP key_value)* NL<br>><br>> 2.2. Header format<br>><br>> Some header lines MUST appear in specific positions, as documented below.<br>> All other lines can appear in any order.<br>><br>> There MUST NOT be multiple key_value header lines with the same key.<br><br>Maybe this line belongs below in the key_value section?<br><br>> It consists of:<br>><br>>   timestamp NL<br>><br>>     [At start, exactly once.]<br>><br>>     The Unix Epoch time in seconds when the file was created.<br><br>Question: Why no keyword and equal sign here?  Is this a legacy thing?<br><br>Also, wouldn't it be more standard to have it be in YYYY-MM-DDTHH:MM:SS<br>format?<br><br>>   "version=" version_number NL<br>><br>>     [In second position, zero or one time.]<br>><br>>     The specification document format version.<br>>     It uses semantic versioning [5].<br>><br>>     This line has been added in version 1.1.0 of this specification.<br>><br>>     Version 1.0.0 documents do not contain this line, and the<br>>     version_number is considered to be "1.0.0".<br><br>General concern: I question the use of = signs here in the headers.  If<br>we use "SP" instead, then we can reuse a lot of the same machinery tor<br>currently uses to parse other documents.<br><br>>   "software=" value NL<br>><br>>     [Zero or one time.]<br>><br>>     The name of the software that created the document.<br>><br>>     This line has been added in version 1.1.0 of this specification.<br>><br>>     Version 1.0.0 documents do not contain this line, and the software is<br>>     considered to be "torflow".<br>><br>>   "software_version=" value NL<br>><br>>     [Zero or one time.]<br>><br>>     The version of the software that created the document.<br>>     The version may be a version_number, a git commit, or some other<br>>     version scheme.<br>><br>>     This line has been added in version 1.1.0 of this specification.<br>><br>>   "scanner_started=" timestamp NL<br>><br>>     [Zero or one time.]<br>><br>>     The Unix Epoch time in seconds when the scanner that generates the<br>>     measurements document started.<br>><br>>     This line has been added in version 1.1.0 of this specification.<br><br>See note above about time format.  YYYY-MM-DDTHH:MM:SS is how we specify<br>times elsewhere in Tor.<br><br>>   "earliest_measurement=" timestamp NL<br>><br>>     [Zero or one time.]<br>><br>>     The Unix Epoch time in seconds when the first relay measurement<br>>     was obtained.<br>><br>>     This line has been added in version 1.1.0 of this specification.<br><br>See note above about time format.<br><br>>   key_value NL<br>><br>>     [Zero or more times.]<br>><br>>     Future format versions may include additional key_value header lines.<br>>     Additional header lines will be accompanied by a minor version increment.<br>><br>>     Implementations MAY add additional header lines as needed. This<br>>     specification SHOULD be updated to avoid conflicting meanings for the<br>>     same header keys.<br>><br>>     Parsers MUST NOT rely on the order of these additional lines.<br>><br>>     Additional header lines MUST NOT use any keywords specified in the<br>>     relay measurements format.<br>><br>>     If a header line does not conform to this format, the line SHOULD be<br>>     ignored by parsers.<br><br>Suggestion: say what recipients of this document should do with<br>unrecognized data.  In general, it's good for forward compatibility to<br>say something like, "Recipients MUST ignore key_value lines if they do<br>not recognize the keyword. Recipients MUST ignore any extra material in<br>a line that they do not recognize."<br><br>Also see suggestion above about using SP as our separator rather than<br>"=" for consistency with other documents Tor parses.<br><br>>   NL<br>><br>>     [Zero or one time.]<br>><br>>     The header ends.<br>><br>>     This line has been added in version 1.1.0 of this specification.<br>><br>>     For version 1.0.0 documents, the header ends when the first relay<br>>     measurement line is found conforming to the next section.<br><br>Suggestion: Replace this empty line with an explicit keyword, for<br>consistency with other documents.<br><br>> 2.3. Relay measurements format<br>><br>> It consists of zero or more relay_line with the measurement results<br>> of relays in arbitrary order.<br>><br>> There can be at most one relay_line per relay identity (fingerprint).<br>><br>> There MUST NOT be multiple key_value pairs with the same key in the same<br>> relay_line.<br>><br>> Each relay_line MUST include the following key_value in arbitrary order:<br><br>Do existing implementations accept arbitrary order here?<br><br>>   "node_id=" fingerprint<br>><br>>     [Exactly once.]<br>><br>>     The fingerprint of the relay being measured.<br><br>Suggestion: Add a field to hold the Ed25519 Identity of the relay being<br>measured.  Say that implementations SHOULD include both RSA fingerprint<br>and Ed25519 identity, and that implementations SHOULD accept lines that<br>contain at least one of them.<br><br>>   "bw=" bandwidth<br>><br>>     [Exactly once.]<br>><br>>     The measured bandwidth of this relay.<br>><br>>     Tor accepts zero bandwidths, but they trigger bugs in older Tor<br>>     implementations. Therefore, implementations SHOULD NOT produce zero<br>>     bandwidths. Instead, they SHOULD use one as their minimum bandwidth.<br>><br>>     Multiple measurements can be aggregated using an averaging scheme, such<br>>     as a mean, median, or decaying average.<br>><br>>     Torflow scales bandwidths to kilobytes per second. Other implementations<br>>     SHOULD use kilobytes per second for their initial bandwidth scaling.<br>><br>>     If different implementations or configurations are used in votes for the<br>>     same network, their measurements MAY need further scaling. See Appendix B<br>>     for information about scaling, and one possible scaling method.<br>><br>>   key_value<br>><br>>     [Zero or more times.]<br><br>Technically, this isn't a key_value, because a "value" is made of<br>ArgumentChar, and ArgumentChar can contain spaces.  So if we were<br>parsing<br>       "foo=abc bar=def"<br>we might be parsing either one key_value ("foo", "abc bar=def") or two<br>("foo", "abc"), ("bar, "def").<br><br>>     Future format versions may include additional key_value pairs on a relay_line.<br>>     Additional key_value pairs will be accompanied by a minor version increment.<br>><br>>     Implementations MAY add additional relay key_value pairs as needed. This<br>>     specification SHOULD be updated to avoid conflicting meanings for the<br>>     same relay keys.<br>><br>>     Parsers MUST NOT rely on the order of these additional key_value pairs.<br>><br>>     Additional key_value pairs MUST NOT use any keywords specified in the<br>>     header format.<br><br>As above, let's say that a parser should ignore key_value entries with<br>keywords that it doesn't recognize.<br><br>><br>>   If a relay line does not conform to this format, the line SHOULD be<br>>   ignored by parsers.<br>><br>> 2.4. Implementation notes<br>><br>> 2.4.1. Simple Bandwidth Scanner<br>><br>> Every relay measurement in sbws version 0.1.0 consists of:<br>><br>>   "node_id=" fingerprint SP<br>><br>>     As above.<br>><br>>   "bw=" bandwidth SP<br>><br>>     As above.<br>><br>>   "nick=" nickname SP<br>><br>>     [Exactly once.]<br>><br>>     The relay nickname.<br>><br>>   "rtt=" Int SP<br>><br>>     [Exactly once.]<br>><br>>     The Round Trip Time in milliseconds to obtain 1 byte of data.<br>><br>>   "time=" timestamp NL<br>><br>>     [Exactly once.]<br>><br>>     The Unix Epoch time in seconds when the last measurement was performed.<br>><br>> 2.4.2. Torflow<br>><br>> Torflow relay lines include node_id and bw, and other key_value pairs [2].<br>><br>> References:<br>><br>> 1. <a href="https://gitweb.torproject.org/torflow.git">https://gitweb.torproject.org/torflow.git</a><br>> 2. <a href="https://gitweb.torproject.org/torflow.git/tree/NetworkScanners/BwAuthority/README.spec.txt#n332">https://gitweb.torproject.org/torflow.git/tree/NetworkScanners/BwAuthority/README.spec.txt#n332</a><br>> 3. <a href="https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt">https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt</a><br>> 4. <a href="https://metrics.torproject.org/onionoo.html#details">https://metrics.torproject.org/onionoo.html#details</a><br>> 5. <a href="https://semver.org/">https://semver.org/</a><br>><br>> A. Sample data<br>><br>> The following has not been obtained from any real measurement.<br>><br>> A.1. Generated by Torflow<br>><br>> This an example version 1.0.0 document:<br>><br>> 1523911758<br>> node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=760 nick=Test measured_at=1523911725 updated_at=1523911725 pid_error=4.11374090719 pid_error_sum=4.11374090719 pid_bw=57136645 pid_delta=2.12168374577 circ_fail=0.2 scanner=/filepath<br>> node_id=$96C15995F30895689291F455587BD94CA427B6FC bw=189 nick=Test2 measured_at=1523911623 updated_at=1523911623 pid_error=3.96703337994 pid_error_sum=3.96703337994 pid_bw=47422125 pid_delta=2.65469736988 circ_fail=0.0 scanner=/filepath<br>><br>> A.2. Generated by sbws version 0.1.0<br>><br>> 1523911758<br>> version=1.1.0<br>> software=sbws<br>> software_version=0.1.0<br>> scanner_started=1523911756<br>> earliest_measurement=1523911757<br>><br>> node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=760 nick=Test rtt=380 time=1523911725<br>> node_id=$96C15995F30895689291F455587BD94CA427B6FC bw=189 nick=Test2 rtt=378 time=1523911623<br>><br>> B. Scaling bandwidths<br>><br>> B.1. Scaling requirements<br>><br>> Tor accepts zero bandwidths, but they trigger bugs in older Tor<br>> implementations. Therefore, scaling methods SHOULD perform the<br>> following checks:<br>>  * If the total bandwidth is zero, all relays should be given equal<br>>    bandwidths.<br>>  * If the scaled bandwidth is zero, it should be rounded up to one.<br>><br>> Initial experiments indicate that scaling may not be needed for<br>> torflow and sbws, because their measured bandwidths are similar<br>> enough already.<br>><br>> B.2. A linear scaling method<br>><br>> If scaling is required, here is a simple linear bandwith scaling<br>> method, which ensures that all bandwidth votes contain approximately<br>> the same total bandwidth:<br>><br>> 1. Calculate the relay quota by dividing the total measured bandwidth<br>>    in all votes, by the number of relays with measured bandwidth<br>>    votes. In the public tor network, this is approximately 7500 as of<br>>    April 2018. The quota should be a consensus parameter, so it can be<br>>    adjusted for all scanners on the network.<br>><br>> 2. Calculate a vote quota by multiplying the relay quota by the number<br>>    of relays this bandwidth authority has measured<br>>    bandwidths for.<br>><br>> 3. Calculate a scaling factor by dividing the vote quota by the<br>>    total unscaled measured bandwidth in this bandwidth<br>>    authority's upcoming vote.<br>><br>> 4. Multiply each unscaled measured bandwidth by the scaling<br>>    factor.<br>><br>> Now, the total scaled bandwidth in the upcoming vote is<br>> approximately equal to the quota.<br>><br>> B.3. Quota changes<br>><br>> If all scanners are using scaling, the quota can be gradually<br>> reduced or increased as needed. Smaller quotas decrease the size<br>> of uncompressed consensuses, and may decrease the size of<br>> consensus diffs and compressed consensuses. But if the relay<br>> quota is too small, some relays may be over- or under-weighted.<br><br></div></div></div>