xls: 45 title: Prepublish Validator Lists description: Future activation date and improved expiration handling of UNLs author: Ed Hennisdiscussion-from: https://github.com/XRPLF/XRPL-Standards/pull/124 status: Final category: System created: 2020-06-17
Abstract¶
Each XRPL server (node) must be configured with a UNL (Unique Node List), which lists the validating nodes that the server considers trusted. A validator list includes the public key of the list publisher, a manifest, a signature, a version, and a base64-encoded blob that contains a UNL.
This document defines version 2 of the VL (Validator List) spec. Compared to version 1, it adds a future effective date so that nodes in the peer-to-peer network can switch to a new UNL simultaneously. It also supports publishing multiple UNLs in one file, allowing future UNLs to be included alongside a current UNL.
This spec also defines the enforcement of the UNL expiration date so that a server will act similarly to being amendment-blocked if it has no active valid UNL.
This spec was finalized and implemented in rippled version
1.7.0-b10 on January 11, 2021. The
original pull request was titled "Support UNLs with future effective dates:
(UNL v2)". The purpose of this XLS
is to make the specification of these changes widely accessible so that related
tooling can be updated. Any further improvements to the VL format should be
defined in a new spec and implemented in rippled with a new pull request. Most
of the following content is written from the perspective of rippled before
these changes were merged.
Motivation¶
Right now, UNLs are very time sensitive. They contain an expiration date, after which the node will act like it doesn't have any validators configured. The node will be unable to fully validate any ledger until it gets an updated VL.
When a new UNL is published, it becomes live immediately. This introduces the possibility of different nodes using different UNLs until everybody "catches up". The protocol broadcast functionality helps mitigate this issue by getting the UNL propagated faster, but it's still not synchronous, and could still cause problems if the network topology is "unfriendly". It also requires publishers to time the release of new UNLs carefully so the old one doesn't expire first.
Specification¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Overview of changes¶
- Add functionality to the UNL to include a future effective date. Change the published file format to allow multiple UNLs to be returned. (Limit number of future UNLs to mitigate some potential attacks.) All nodes will start using the new UNL after the first validated ledger with an earlier close time (falling back to the wall clock if necessary, such as when the node is not synced).
- Add enforcement of the expiration date by changing rippled's behavior to something similar to being amendment blocked (reuse that code as much as possible).
Data format¶
Glossary¶
| Term or acronym | Definition |
|---|---|
| VL | Validator List. Also known as the "UNL", this is the list of validators that a server trusts not to collude. |
| UNL | Unique Node List. Also known as the "VL", this is the list of validators that a server trusts not to collude. |
| UNL file (or VL file) | A file containing a publisher's manifest, public key, etc., and one or more UNLs. |
Current format¶
The current format of the VL file (e.g. as downloaded from https://vl.ripple.com/) is
{
"public_key" : string representing the publisher's hex-encoded master
public key,
"manifest" : string representing the base-64 or hex-encoded manifest
containing the publisher's master and signing public keys,
"version": unsigned integer representing the VL format version. Currently
only 1 is valid,
"signature": string representing the hex-encoded signature of the blob
using the publisher's signing key,
"blob": string representing base-64 encoded JSON containing the actual list.
See below
}
The blob format is
{
"sequence" : Unsigned integer sequence of this VL. The sequence number
must increase monotonically. More specifically, validator lists with
sequences less than the current are ignored. The special sequence
UInt(-1) indicates that the master key is revoked,
"expiration" : Unsigned integer representing the ripple time point when
this list will no longer be valid,
"validators" : [
{
"validation_public_key" : hex-encoded master public key,
"manifest" : (optional) base64 or hex-encoded validator manifest
},
...Optionally repeats...
]
}
"ripple time" is the number of seconds since the "Ripple Epoch" of January 1, 2000 (00:00 UTC). This is similar to how the Unix epoch works, except the Ripple Epoch is 946,684,800 seconds after the Unix Epoch. Do not convert Ripple Epoch times to Unix Epoch times in 32-bit variables, as this could lead to integer overflows.
Future format¶
The blob v2 format adds a single field to the v1 format:
"effective" : Unsigned integer representing the ripple time point when the
list will become valid
So the full blob v2 format will be:
{
"sequence" : Unsigned integer sequence of this VL. The sequence number
must increase monotonically. More specifically, validator lists with
sequences less than the current are ignored. The special sequence
UInt(-1) indicates that the master key is revoked,
"effective" : Unsigned integer representing the ripple
time point when the list will become valid,
"expiration" : Unsigned integer representing the ripple time point when
this list will no longer be valid,
"validators" : [
{
"validation_public_key" : hex-encoded master public key,
"manifest" : (optional) base64 or hex-encoded validator manifest
},
...Optionally repeats...
]
}
Using this blob v2 format, the VL v2 file format will remove blob
and signature and add:
"blobs-v2" : [
{
"manifest" : OPTIONAL string representing the base-64 or hex-encoded
manifest containing the publisher's master and signing public keys,
"signature": string representing the hex-encoded signature of the blob
using the publisher's signing key,
"blob" : string representing the base64-encoded json representation of
the blob
},
...Optionally repeats...
]
So the full VL v2 format will be:
{
"public_key" : string representing the publisher's hex-encoded master
public key,
"manifest" : string representing the base-64 or hex-encoded manifest
containing the publisher's master and signing public keys,
"version": unsigned integer representing the VL format version. Both
1 and 2 will be valid, with 1 signfiying the old format, and
2 signifying the new.
"blobs-v2" : [
{
"manifest" : OPTIONAL string representing the base-64 or
hex-encoded manifest containing the publisher's master and signing
public keys,
"signature": string representing the hex-encoded signature of the blob
using the publisher's signing key,
"blob" : string representing the base64-encoded json representation of
the blob
},
...Optionally repeats...
]
}
If the expiration of a blob is not greater than effective, the
blob will be considered malformed. Clients MAY process the other
blobs in the file as if the blob with that sequence were not present.
If the manifest is not present in a blobs-v2 array entry, then the
top-level manifest will be used when checking the signature. This allows
a publisher to keep any old, blobs and their signatures if they ever need
to update their manifest. Most publishers will only need to use this field
very rarely. (Currently, if the VL processing sees a stale manifest, where
the public key hasn't been completely revoked, it will be used without a
problem. I'm not sure this behavior is correct. Consider treating a
stale manifest as an untrusted list.)
Pros of the new format:
- By signing each
blobseparately, the VL file can be modified to move theblobs around in theblobs-v2array as olderblobs expire and newblobs are added without requiring any extra signing. - The objects in the
blobs-v2array don't necessarily need to be in order, but it will simplify maintenance if they are. - Old
blobs can be left in theblobs-v2array without causing any harm, as long as a more recent blob has already been added. In other words, old data can be cleaned up when it's convenient.
Cons:
- Each
blobwill need to be signed separately, even if they are all built at once.
Migration strategy¶
Don't implement any migration strategy in code
This is the simplest option. Don't do anything with the files, don't modify the URLs. Leave the decision of when and how to migrate to publishers. If they want to publish both versions simultaneously, then they will need to communicate different URLs to operators. If not, then they can wait until an appropriate time (e.g. when enough nodes have upgraded, or if they want to pressure nodes to upgrade), and then make a single clean switchover from v1 to v2.
In terms of the code, if the file version is 1, then rippled will follow the v1 rules, and if it's 2, rippled will follow the v2 rules.
Pros:
- Keeps rippled code simple
- If a publisher chooses to publish a v2 UNL file while there are still nodes on the network that won't understand it, newer peers will communicate the "current" UNL to older peers, if they're connected sufficiently.
Cons:
- Adoption will probably be delayed until some other "limiting event" or synchronization point happens which forces all nodes to upgrade. This will most likely be when an amendment is enabled that no v1-only nodes support.
See the appendix for descriptions of some other migration strategies that were considered and rejected.
:bangbang: Support for XLS-45 has been fully deployed across all XRPL Mainnet nodes.
This is because, after the "UNLv2" implementation was included in a release, amendments from that release (or later) have been enabled. For details, see Amendment Blocked Servers.
Rippled changes¶
Overview¶
When rippled downloads a v2 VL file from a URL (web or file) or receives an updated network protocol message with more than one VL, it will store all valid and potentially valid current and future VLs internally. This may include VLs already in memory in addition to the ones downloaded (this is particularly relevant if a peer splits a single file into multiple messages). The automatic cache files will always be written as v2 for simplicity.
As with current behavior, after processing new VLs, rippled will broadcast them to peers. If the peer supports a protocol version which supports v2 VLs, rippled will broadcast the same set of VLs that it is storing. If not, it will only send the currently active VL. As now, rippled will avoid transmitting VLs that it believes the peer already has.
Before starting a new consensus round, in addition to checking the expiration date of the current VL, also check the effective date of the next VL, based on the previous ledger close time if reasonable or the wall clock if not. Rotate to the next VL if it becomes effective, and broadcast to peers that don't understand the v2 format. If the current VL has expired without a replacement, rippled will go into a state similar to being amendment blocked. Unlike being amendment blocked, rippled will be able to resume normal operations if it downloads or receives a valid active VL.
Any RPC method that reports the amendment blocked state will also report the expired VL state as appropriate.
The /vl/ peer endpoint will be modified to support returning a v2 list via a version number embedded in the path, which, similar to broadcast messages, will be built using the stored current and future VLs.
Data structures¶
The ValidatorList currently defines a member to hold the published VLs
and look them up by the public key of the publisher:
// Published lists stored by publisher master public key
hash_map<PublicKey, PublisherList> publisherLists_;
First, PublisherList will need to be modified to add a
TimeKeeper::time_point validFrom; member to store the effective date.
This member will not be optional.
Instead, if an older VL is encountered which does not contain an effective
field, this member will be assigned as if it was 0, i.e. the start of the
ripple epoch. The existing TimeKeeper::time_point expires field will be renamed to
validUntil.
Then, the publisherLists_ member will be modified to hold a collection of
PublisherList as the value type.
Without going into too much implementation detail, define a new
structure to hold the VLs, and use it for the publisherLists_:
struct PublisherListCollection
{
PublisherList current;
std::vector<PublisherList> remaining;
};
// Published lists stored by publisher master public key
hash_map<PublicKey, PublisherListCollection> publisherLists_;
The current VL will be defined as the one which
- Has the largest sequence number that
- Has ever been effective (the
effectivedate is absent or in the past). - If this VL has expired, all VLs with previous sequence numbers will also be considered expired, and thus there will be no valid VL until one with a larger sequence number becomes effective. This is to prevent erroneous or intentional "funny business" allowing old VLs to reactivate.
- This maps to the current expiration behavior.
The remaining list will hold any relevant VLs which have a larger sequence
number than current. By definition they will all have an effective
date in the future. Relevancy will be determined by sorting the VLs by
sequence number, then iterating over the list and removing any VLs for
which the following VL (ignoring gaps) has the same or earlier
effective date.
If a series of VLs is created such that the expiration date of one
is later than the effective date of the following VL, then that contiguous
series of VLs won't expire until the expiration date of the last
VL of the chain, regardless of any gaps in their sequence numbers.
A "well-behaved" publisher is expected to maintain their VL file to reduce
the need for rippled to drop any VLs. Their VLs will be published such
that VL sequence n will be effective before VL sequence n+1. If
pending VL sequence n needs to be replaced, it may be replaced with
n+1 with an earlier effective date, but sequence n should be
removed from the published site.
File processing.¶
File download code will not need any changes.
The ValidatorSite::parseJsonResponse function will need to be modified to
deal with the new top level blobs-v2 field, and pass an array of
blob/signature/manifest tuples (where the manifest is only provided if it
overrides) to ValidatorList::applyListAndBroadcast. For the remainder
of this document, these tuples will be referred to as BlobInfo, though
they may not have that name in the implementation.
The top-level BlobInfo can be added to that array.
Additionally, applyListAndBroadcast will need to add a NetworkOPs
const& parameter so that
clearUNLBlocked
can be called when a new VL is accepted.
In the initial release, to prevent potential abuse and attacks, any VL collection with more than 5 entries will be considered malformed.
ValidatorList::applyListAndBroadcast will need to be rewritten to send each
BlobInfo individually to ValidatorList::applyList and process the
collective results (both in memory and in the file). Both applyList and
verify in ValidatorList will only need to be modified to handle the
effective date, and update the new PublisherListCollection::current
if appropriate. It may be possible for more than one VL from a list to be
assigned to current as the list is processed - that's OK, because any
older versions will be
overwritten. However, the mutex lock will need to be moved up to
applyListAndBroadcast (or a new intermediate wrapper function),
applyList will need to be made private, and some tests will need to be
updated. Finally, the list will need to be filtered before broadcasting,
to only send those which are worth keeping (it would make the most sense
to build the PublisherListCollection first, then build the v2 message
from that), and to send an appropriate message to peers which understand
the older and newer protocols (see below for protocol
changes).
As a last step, applyListAndBroadcast (or the new intermediate wrapper
function) will iterate over all of the known publishers in
publisherLists_. If all of them are valid and up to date, it will call
NetworkOPs::clearUNLBlocked.
This is the only mechanism that will allow node to resume normal
operation if a VL expires without a replacement and
setUNLBlocked is called.
In applyList and verify, all blobs will be validated independently.
New ListDisposition values, pending and known_sequence will be added
for VLs which have not yet reached their effective date. pending will
be returned for VLs with future effective dates and sequence numbers
larger than the max VL sequence in PublisherListCollection.
known_sequence will be returned for VLs with a future effective date,
and a sequence not greater than the max VL sequence in
PublisherListCollection - though not necessarily in the
PublisherListCollection.
A VL which gets a pending result will always be treated as new (because
it is), while a known_sequence result will always be treated as if it
is held in the PublisherListCollection members, even if it is not. This
is to prevent a publisher from "rewriting the future" by replacing an
already published sequence number or trying to fill in a gap. Publishers
should always use a new sequence when publishing a new list, even if
it's not yet effective.
The intention of pending and known_sequence are to correspond
to accepted and same_sequence, respectively, in both the way the
decision is made, and in the way the VL is treated.
verify will be modified to reject any applyManifest result that
isn't ManifestDisposition::accepted. Any VL files that use the
blobs-v2 object manifest entry should be processed before any that
don't, and will be cached in memory until rippled restarts. This will be
important to test. However, it is important to document that best
practice when incrementing the Manifest sequence number is to resign all
valid blobs, publish them with their new signatures, and never
populate the manifest field in BlobInfo. (Is this worth supporting
right out of the gate? Is the benefit of not needing to resign blobs in
this rare situation worth the extra complexity and data field?)
The processor can safely ignore any older VLs, including any that are
expired, or which have a lower sequence number than the current.
Reading and writing cache files¶
Reading cache files (e.g.
cache.ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734
written to the [node_db] directory) will not require any extra
changes, because the same code path is used for processing files as
http(s) URLs.
The only change needed is to write the files out in the v2 format. The
CacheValidatorFile function will need to set up the JSON object to
populate blobs-v2 instead of blob/signature from current and
remaining. Always write the blobs in sequence order. Also add a field
to write out the publisher's public
key. Change the JSON
construction to use jss parameters instead of strings.
Refactor the construction code used to build the JSON in
CacheValidatorFile and getAvailable to call a common function so we
can avoid inconsistencies.
Protocol changes for V2 UNL broadcasts¶
A new entry will need to be added to suppportedProtocolList, incrementing
the current maximum version.
We could reuse the TMValidatorList message for sending VL collections,
but that will waste a lot of bandwidth because of duplicated data, such
as the manifest. Instead, create two new message types that will
mimic the v2 file format:
message TMValidatorListV2
{
optional bytes manifest;
required bytes blob;
required bytes signature;
}
message TMValidatorListCollection
{
required uint32 version;
required bytes manifest;
repeated TMValidatorListV2 blobs;
}
Peers that do not support the incremented protocol version will be sent
a single TMValidatorList containing the current VL. Those that do
will be sent one or more TMValidatorListCollections.
The TMValidatorListCollection will be built from the
PublisherListCollection, creating one TMValidatorListV2 for each
BlobInfo, then populating the blobs array in the
TMValidatorListCollection. Currently, the Peer object keeps track of
the latest sequence sent to that peer. When building the message for the peer,
continue to only send VLs the peer has not seen. For optimization, this may
require grouping peers by most recent sequence before building the message(s).
Before sending, check the message size, splitting it into multiple
messages if necessary. Use Message.getBuffer().size(). If the size is
larger than the message size limit (64Mb), split the array of
TMValidatorListV2s in half until it's small enough. If it gets down to
a single BlobInfo, send a TMValidatorList. If that is still larger
than the limit, don't send it at all.
Fortunately, because the messages are distinct, no conditional
processing needs to be done for the different messages. Processing of
the old TMValidatorList does not need to change at all (other than to
update for the changed API). The new TMValidatorListCollection should
be able to build the BlobInfo array directly from the blobs member
of the message and pass that to the updated
ValidatorList::applyListAndBroadcast.
Expiration and automatic rotation¶
There are two functions where the VL expiration is currently checked:
ValidatorList::expiresValidatorList::updateTrusted
ValidatorList::expires¶
For now, no changes will be made to expires to rotate VLs. When
computing the return value, starting with current and continuing into
remaining, find the last VL where the effective date overlaps with
the expiration date of the previous. Use that VL's expiration date
in the return value calculation.
ValidatorList::updateTrusted¶
updateTrusted will be modified to take the closeTime of the
validated ledger (this might available in the caller
NetworkOPsImp::beginConsensus as closingInfo.parentCloseTime, but
check the implementation to confirm, and get the correct value if not)
and a const& to the NetworkOPsImp calling object.
For all time comparisons, if the wall clock time is more than 30 seconds
ahead of the closeTime, it will be used instead.
- While iterating over the publisher lists, if the first entry in
remaininghas aneffectivedate before thecloseTime, then it will be moved tocurrent, and removed fromremaining. - Additionally, the
expirationwill be compared to thecloseTime. If thecurrentVL has expired and no replacement has been pulled out ofremaining, then in addition to callingremovePublisherList, callNetworkOPs::setUNLBlocked. (Note thatremovePublisherListis also called fromValidatorList::verify, but that removes the publisher entirely. As currently implemented, if there is another publisher configured, the node will not get stuck. Is this behavior correct?) - If at the end of
updateTrusted,unlSizeis 0, (orquorumis set to max), also callNetworkOPs::setUNLBlocked. This addresses the scenario where all the publisher manifests are revoked. - Finally, any updated
currentVLs will be broadcast to older peers (those that don't support the updated protocol version) so that they can get on the new VL as soon as possible.
Stopping and resuming operations on expiration¶
Define a new std::atomic<bool> unlBlocked_{false}; in
NetworkOPsImp. The set and clear functions will set and clear the flag
respectively. The set function will also set the operating mode to
TRACKING. Also define an isUNLBlocked that returns the
value of the new flag. This parallels the setAmendmentBlocked
function except that this flag can be cleared.
Define a new bool NetworkOPs::isBlocked() function that
returns isAmendmentBlocked() || isUNLBlocked(). Call this
function in place of isAmendmentBlocked at all of the non-reporting
call sites listed below and in
setMode where amendmentBlocked is checked directly . At the
reporting sites, call isUNLBlocked separately, and report
that result.
As described above,
setUNLBlocked is called when a VL expired.
clearUNLBlocked is called whenever a new downloaded VL is
accepted (in ValidatorList::applyList).
Reporting¶
There are two functions that return validator information for reporting purposes via the RPC interface:
NetworkOPsImp::getServerInfo- Will be left unchanged, since it only reports the number of sources
and the next expiration time via
expires. ValidatorList::getJson- This function loops over all the publishers, and includes information about
all of their VLs the JSON
publisher_listsarray of objects. - Keep the same format and fields for the
currentVL (seq, expiration, list). I don't think it's necessary to includeeffectivefor thecurrentVL because it's no longer relevant. - Add an array of objects for
remainingcontaining the same fields ascurrent, plus a new field foreffective.
Expand /vl/ URL handling¶
Currently a request sent on the peer port to /vl/{public key} will
return the current (and only) VL for the publisher with that public key
if that key is trusted ([validator_list_keys] in the config). This
behavior will remain unchanged, and thus will stay backward compatible.
To support V2, the URL format will be changed to
/vl[/{version}]/{public_key}, where version is optional and defaults
to 1. The ValidatorList::getAvailable function will be modified to
take the version number.
If version is 1, getAvailable will return a version 1 Json object in
the same format as returned now, using the values from current.
If version is 2, getAvailable returns a version 2 Json object as
described above, building the blobs-v2 array from current
and remaining. Don't forget to include public_key!
Any other value of version will return an unseated optional.
UNL-tool changes (signer)¶
Need to add handling of effective date in UI and resulting blob¶
When signing a UNL, the "unl-tool" prompts for the "sequence number" and
"validity in days". It then adds that "validity" value to the current
date to compute the expiration date, rounding (up or down?) to midnight
UTC. It then builds the blob JSON, stringifies it, base 64 encodes it,
and signs it.
To support version 2, the unl-tool will add a prompt for the effective date, and change the prompt for the expiration date. The workflow will be something like:
- Prompt "Sequence number:", read the unsigned int value.
- Prompt "Delay until effective in days:", read the unsigned int value.
- The
effectivetime value will be computed from today plus this value , and rounded down to midnight UTC, then converted to "ripple time". - If the value is 0, the
effectivefield will not be populated. - Prompt "Expiration after effective in days:", read the unsigned int value.
- The
expirationtime value will be computed from theeffectivetime plus this value. Rounding will not be necessary since the process adds whole days, and UTC doesn't have leap years. (Is this correct?) - A value of 0 will be invalid and cause an error or reprompt.
- Once the JSON is built, with or without the
effectivefield, the signing process can continue unmodified.
Backwards Compatibility¶
This spec was carefully designed and implemented to ensure that there are no backward compatibility issues.
Reference Implementation¶
As noted above, this has already be implemented in rippled in commit 4b9d3ca.
Security Considerations¶
Needs discussion.
Appendix¶
Roads not taken¶
Migration options¶
These options were considered, but rejected because the risk of a v1 node seeing and processing a v2 node before it's effective was deemed unacceptable.
1. Implement backward compatibility¶
The UNL file format will be allowed to have multiple versions
simultaneously. The v1 data will be in the top-level blob and signature
fields. The v2 data will be in a single new top-level blobs-v2 field,
described below.
The blob v2 format will only add fields to the v1 format,
which should be ignored by existing v1 parsers, and thus will be backward
compatible if allowed.
Older rippled nodes should be able to use the new format VL without any problems until they get upgraded or amendment blocked for another reason.
If version is 1, then blob and signature MUST be present, and will be
treated as if they are included in the blobs-v2 array, even if there is no
blobs-v2 array, or it's empty. This helps avoid data duplication and allows
for backward compatibility.
If version is 2, then blobs-v2 MUST be present, and the file will be
considered malformed if either blob or signature are present, though
clients MAY ignore them.
Pros:
- With
version1, the file is both forward and backward compatible. Since older clients will ignore theeffectivedate, the VL will be valid as long as it's not expired.
Cons:
- To maintain backward compatibility with
version1, the "next"blob(i.e. the first blob listed inblobs-v2) will have to be manually moved into the top levelblobandsignaturesometime between the new VL'seffectiveand the old VL'sexpiration. Until this is done, old clients will be using the outdated VL. This could be mitigated if newer nodes broadcast the updated VL to older nodes when they switch. - If an older node ever sees a v2-formatted blob, it will start using it
immediately, regardless of the
effectivedate. Because this information can be sent via protocol messages, a buggy or malicious peer could cause this to happen prematurely.
Once the network has moved on to the point that older versions of rippled can
not function (e.g. because they are amendment blocked), then publishers
can change their version number to 2, and stop populating the top-level
blob and signature fields.
2. Distinct versioning with optional URL migrations¶
Instead of handling the migration in the file and rippled code, this option allows the publisher to optionally publish two UNL files at separate URLs. For example: https://vl.ripple.com (for v1) and https://vl.ripple.com/v2 (for v2, obviously).
First, each version will be interpreted strictly - it's either v1 or v2,
though v1 interpreters will ignore the effective field in the blob if
it's present.
If the publisher chooses to publish multiple UNLs simultaneously, they will be responsible for manually moving the current UNL to the v1 file at the appropriate time.
To assist with migration of nodes, define a hard-coded path, /v2, and
for every URL defined in [validator_list_sites] that does not contain
that substring, add both the original URL and the URL with the path
appended to the list of UNL download sites. For example, if the config
file contains
[validator_list_sites]
https://vl.ripple.com
Then rippled will attempt to use both https://vl.ripple.com and https://vl.ripple.com/v2.
But if the config file contains
[validator_list_sites]
https://vl.ripple.com/v2
Then only https://vl.ripple.com/v2 will be used.
Add a boolean configuration option to the validators.txt processing
named [use_validator_site_suffix] that defaults to true, but can be
overridden by node operators to explicitly disable this behavior.
Pros:
- Simplifies rippled code and file processing because there's no need to worry about conditional processing.
Cons:
- If the publisher publishes both v1 and v2 UNLs simultaneously, and doesn't use the default suffix, operators using their v2 UNL will have to manually change their config file.
- Like with their "backward compatibility" option, to maintain backward
compatibility with
version1, the "next"blob(i.e. the first blob listed inblobs-v2) will have to be manually moved into the v1 file sometime between the new VL'seffectiveand the old VL'sexpiration. Until this is done, old clients will be using the outdated VL. This could be mitigated if newer nodes broadcast the updated VL to older nodes when they switch. - By default rippled will make twice as many requests to the publishers' websites. This isn't too bad, since requests are only made every 5 minutes, but this may still be significant enough to mention.
- If an older node ever sees a v2-formatted blob, it will start using it
immediately, regardless of the
effectivedate. Because this information can be sent via protocol messages, a buggy or malicious peer could cause this to happen prematurely.
References¶
Issues¶
Expiration call tree in current code¶
expirationis checkedValidatorList::expiresreturns the earliest date that any VL expires.NetworkOPsImp::getServerInfoRCLConsensus::Adaptor::preStartRoundValidatorList::getJson
-
ValidatorList::updateTrusted- All validators from expired lists are removed from the list of master public keys (keyListings). Also setsquorum_to maxint.NetworkOPsImp::beginConsensus
-
AmendmentTable::hasUnsupportedEnabled LedgerMaster::setValidLedgercallsNetworkOPs::setAmendmentBlockedamendmentBlocked_is checkedNetworkOPsImp::isAmendmentBlockedRCLConsensus::Adaptor::preStartRoundLedgerMaster::setValidLedgerApplicationImp::serverOkayNetworkOPsImp::getServerInforipple::RPC::conditionMet<T>
NetworkOPsImp::setMode