20#include <xrpld/app/misc/HashRouter.h> 
   21#include <xrpld/app/misc/NetworkOPs.h> 
   22#include <xrpld/app/misc/ValidatorList.h> 
   23#include <xrpld/overlay/Overlay.h> 
   25#include <xrpl/basics/FileUtilities.h> 
   26#include <xrpl/basics/Slice.h> 
   27#include <xrpl/basics/StringUtilities.h> 
   28#include <xrpl/basics/base64.h> 
   29#include <xrpl/json/json_reader.h> 
   30#include <xrpl/protocol/PublicKey.h> 
   31#include <xrpl/protocol/STValidation.h> 
   32#include <xrpl/protocol/digest.h> 
   33#include <xrpl/protocol/jss.h> 
   34#include <xrpl/protocol/messages.h> 
   36#include <boost/regex.hpp> 
   54            return "same_sequence";
 
   58            return "known_sequence";
 
   60            return "unsupported_version";
 
 
   81    : publisherKey(key), status(stat), sequence(seq)
 
 
   90                                : dispositions.begin()->first;
 
 
   97                                : dispositions.rbegin()->first;
 
 
  106        dispositions[disp] += 
count;
 
 
  114    : message(message_), hash(hash_), numVLs(num_)
 
 
  132    , 
quorum_(minimumQuorum.value_or(1))  
 
 
  145    static boost::regex 
const re(
 
  160        << 
"Loading configured trusted validator list publisher keys";
 
  163    for (
auto key : publisherKeys)
 
  165        JLOG(
j_.
trace()) << 
"Processing '" << key << 
"'";
 
  171            JLOG(
j_.
error()) << 
"Invalid validator list publisher key: " << key;
 
  181                << 
"Configured validator list publisher key is revoked: " 
  189                << 
"Duplicate validator list publisher key: " << key;
 
  203            "ripple::ValidatorList::load : list threshold inside range");
 
  204        JLOG(
j_.
debug()) << 
"Validator list threshold set in configuration to " 
  213        JLOG(
j_.
debug()) << 
"Validator list threshold computed as " 
  227        auto const [_, inserted] =
 
  231            JLOG(
j_.
debug()) << 
"Added own master key " 
  236    JLOG(
j_.
debug()) << 
"Loading configured validator keys";
 
  239    for (
auto const& n : configKeys)
 
  241        JLOG(
j_.
trace()) << 
"Processing '" << n << 
"'";
 
  245        if (!boost::regex_match(n, 
match, re))
 
  247            JLOG(
j_.
error()) << 
"Malformed entry: '" << n << 
"'";
 
  256            JLOG(
j_.
error()) << 
"Invalid node identity: " << 
match[1];
 
  267            JLOG(
j_.
warn()) << 
"Duplicate node identity: " << 
match[1];
 
 
  285boost::filesystem::path
 
  315        "ripple::ValidatorList::buildFileData : valid publisher list input");
 
  316    auto const effectiveVersion =
 
  317        forceVersion ? *forceVersion : pubCollection.
rawVersion;
 
  320    value[jss::version] = effectiveVersion;
 
  321    value[jss::public_key] = pubKey;
 
  323    switch (effectiveVersion)
 
  327            value[jss::blob] = 
current.rawBlob;
 
  328            value[jss::signature] = 
current.rawSignature;
 
  333                value[jss::manifest] = *
current.rawManifest;
 
  339            auto add = [&blobs, &outerManifest = pubCollection.
rawManifest](
 
  342                blob[jss::blob] = pubList.rawBlob;
 
  343                blob[jss::signature] = pubList.rawSignature;
 
  344                if (pubList.rawManifest &&
 
  345                    *pubList.rawManifest != outerManifest)
 
  346                    blob[jss::manifest] = *pubList.rawManifest;
 
  356            value[jss::blobs_v2] = std::move(blobs);
 
  361                << 
"Invalid VL version provided: " << effectiveVersion;
 
 
  378    boost::system::error_code ec;
 
  386    value[jss::refresh_interval] = 24 * 60;
 
  393        JLOG(
j_.
error()) << 
"Problem writing " << filename << 
" " << ec.value()
 
  394                         << 
": " << ec.message();
 
 
  417                "ripple::ValidatorList::parseBlobs : single element result");
 
  426            if (!body.
isMember(jss::blobs_v2) ||
 
  427                !body[jss::blobs_v2].
isArray() ||
 
  432            auto const& blobs = body[jss::blobs_v2];
 
  434            for (
auto const& blobInfo : blobs)
 
  436                if (!blobInfo.isObject() ||
 
  437                    !blobInfo.isMember(jss::signature) ||
 
  438                    !blobInfo[jss::signature].isString() ||
 
  439                    !blobInfo.isMember(jss::blob) ||
 
  440                    !blobInfo[jss::blob].isString())
 
  443                info.
blob = blobInfo[jss::blob].asString();
 
  444                info.
signature = blobInfo[jss::signature].asString();
 
  445                if (blobInfo.isMember(jss::manifest))
 
  447                    if (!blobInfo[jss::manifest].isString())
 
  449                    info.
manifest = blobInfo[jss::manifest].asString();
 
  453                result.
size() == blobs.size(),
 
  454                "ripple::ValidatorList::parseBlobs(version, Jason::Value) : " 
  455                "result size matches");
 
 
  465    return {{body.blob(), body.signature(), {}}};
 
 
  475    result.
reserve(body.blobs_size());
 
  476    for (
auto const& blob : body.blobs())
 
  479        info.
blob = blob.blob();
 
  481        if (blob.has_manifest())
 
  487        result.
size() == body.blobs_size(),
 
  488        "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size " 
 
  496    protocol::TMValidatorListCollection 
const& largeMsg,
 
  504    protocol::TMValidatorListCollection 
const& largeMsg,
 
  509    if (begin == 0 && end == 0)
 
  510        end = largeMsg.blobs_size();
 
  511    XRPL_ASSERT(begin < end, 
"ripple::splitMessage : valid inputs");
 
  515    auto mid = (begin + end) / 2;
 
 
  525    protocol::TMValidatorListCollection 
const& largeMsg,
 
  532    if (end - begin == 1)
 
  534        protocol::TMValidatorList smallMsg;
 
  535        smallMsg.set_version(1);
 
  536        smallMsg.set_manifest(largeMsg.manifest());
 
  538        auto const& blob = largeMsg.blobs(begin);
 
  539        smallMsg.set_blob(blob.blob());
 
  540        smallMsg.set_signature(blob.signature());
 
  542        if (blob.has_manifest())
 
  543            smallMsg.set_manifest(blob.manifest());
 
  547            "ripple::splitMessageParts : maximum message size");
 
  553        return messages.
back().numVLs;
 
  559        smallMsg->set_version(largeMsg.version());
 
  560        smallMsg->set_manifest(largeMsg.manifest());
 
  564            *smallMsg->add_blobs() = largeMsg.blobs(i);
 
  571            return splitMessage(messages, largeMsg, maxSize, begin, end);
 
  577                    *smallMsg, protocol::mtVALIDATORLISTCOLLECTION),
 
  579                smallMsg->blobs_size());
 
  580            return messages.
back().numVLs;
 
 
  597        "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages " 
  599    protocol::TMValidatorList msg;
 
  602    auto const version = 1;
 
  604    msg.set_blob(currentBlob.
blob);
 
  605    msg.set_signature(currentBlob.
signature);
 
  607    msg.set_version(version);
 
  611        "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum " 
 
  633        "ripple::buildValidatorListMessage(std::map<std::size_t, " 
  634        "ValidatorBlobInfo>) : empty messages input");
 
  635    protocol::TMValidatorListCollection msg;
 
  636    auto const version = rawVersion < 2 ? 2 : rawVersion;
 
  637    msg.set_version(version);
 
  638    msg.set_manifest(rawManifest);
 
  640    for (
auto const& [sequence, blobInfo] : blobInfos)
 
  642        if (sequence <= peerSequence)
 
  644        protocol::ValidatorBlobInfo& blob = *msg.add_blobs();
 
  645        blob.set_blob(blobInfo.blob);
 
  646        blob.set_signature(blobInfo.signature);
 
  647        if (blobInfo.manifest)
 
  648            blob.set_manifest(*blobInfo.manifest);
 
  651        msg.blobs_size() > 0,
 
  652        "ripple::buildValidatorListMessage(std::map<std::size_t, " 
  653        "ValidatorBlobInfo>) : minimum message blobs");
 
  665        return messages.
back().numVLs;
 
 
  684        "ripple::ValidatorList::buildValidatorListMessages : empty messages " 
  686    auto const& [currentSeq, currentBlob] = *blobInfos.
begin();
 
  692            return total + m.numVLs;
 
  694    if (messageVersion == 2 && peerSequence < maxSequence)
 
  697        if (messages.
empty())
 
  706            if (messages.
empty())
 
  713        return {maxSequence, numVLs};
 
  715    else if (messageVersion == 1 && peerSequence < currentSeq)
 
  718        if (messages.
empty())
 
  723                currentBlob.manifest ? *currentBlob.manifest : rawManifest,
 
  726            if (messages.
empty())
 
  733        return {currentSeq, numVLs};
 
 
  770            "ripple::ValidatorList::sendValidatorList : non-empty messages " 
  776        for (
auto const& message : messages)
 
  780                peer.
send(message.message);
 
  788            sent || messages.
size() == 1,
 
  789            "ripple::ValidatorList::sendValidatorList : sent or one message");
 
  792            if (messageVersion > 1)
 
  794                    << 
"Sent " << messages.
size()
 
  795                    << 
" validator list collection(s) containing " << numVLs
 
  796                    << 
" validator list(s) for " << 
strHex(publisherKey)
 
  797                    << 
" with sequence range " << peerSequence << 
", " 
  798                    << newPeerSequence << 
" to " << peer.
fingerprint();
 
  803                    "ripple::ValidatorList::sendValidatorList : one validator " 
  806                    << 
"Sent validator list for " << 
strHex(publisherKey)
 
  807                    << 
" with sequence " << newPeerSequence << 
" to " 
 
  849    blobInfos[
current.sequence] = {
 
  851    for (
auto const& [sequence, vl] : remaining)
 
  853        blobInfos[sequence] = {vl.rawBlob, vl.rawSignature, vl.rawManifest};
 
 
  901            "ripple::ValidatorList::broadcastBlobs : valid sequence");
 
  906            if (toSkip->count(peer->id()) == 0)
 
  908                auto const peerSequence =
 
  909                    peer->publisherListSequence(publisherKey).value_or(0);
 
  910                if (peerSequence < maxSequence)
 
  912                    if (blobInfos.
empty())
 
  914                    auto const v2 = peer->supportsFeature(
 
  924                        v2 ? messages2[peerSequence] : messages1,
 
  929                    hashRouter.addSuppressionPeer(hash, peer->id());
 
 
  949    auto const disposition = result.bestDisposition();
 
  976        result.publisherKey &&
 
  982            *result.publisherKey,
 
  984            *pubCollection.maxSequence,
 
 
 1011    for (
auto const& blobInfo : blobs)
 
 1027            stats.mergeDispositions(result);
 
 1028            result = std::move(stats);
 
 1040        auto& remaining = pubCollection.remaining;
 
 1041        auto const& 
current = pubCollection.current;
 
 1042        for (
auto iter = remaining.begin(); iter != remaining.end();)
 
 1046                next == remaining.end() || next->first > iter->first,
 
 1047                "ripple::ValidatorList::applyLists : next is valid");
 
 1048            if (iter->first <= 
current.sequence ||
 
 1049                (next != remaining.end() &&
 
 1050                 next->second.validFrom <= iter->second.validFrom))
 
 1052                iter = remaining.erase(iter);
 
 1062        pubCollection.fullHash = 
sha512Half(pubCollection);
 
 1064        result.
sequence = *pubCollection.maxSequence;
 
 
 1080    auto iNew = publisherList.
begin();
 
 1081    auto iOld = oldList.
begin();
 
 1082    while (iNew != publisherList.
end() || iOld != oldList.
end())
 
 1084        if (iOld == oldList.
end() ||
 
 1085            (iNew != publisherList.
end() && *iNew < *iOld))
 
 1092            iNew == publisherList.
end() ||
 
 1093            (iOld != oldList.
end() && *iOld < *iNew))
 
 1109    if (publisherList.
empty())
 
 1111        JLOG(
j_.
warn()) << 
"No validator keys included in valid list";
 
 1114    for (
auto const& valManifest : manifests)
 
 1121                            << 
" contained untrusted validator manifest";
 
 1129                            << 
" contained invalid validator manifest";
 
 
 1145    using namespace std::string_literals;
 
 1148    auto const& 
manifest = localManifest ? *localManifest : globalManifest;
 
 1152        JLOG(
j_.
warn()) << 
"UNL manifest cannot be deserialized";
 
 1156    auto [result, pubKeyOpt] =
 
 1157        verify(lock, list, std::move(*m), blob, signature);
 
 1162            << 
"UNL manifest is signed with an unrecognized master public key";
 
 1174            "ripple::ValidatorList::applyList : invalid public key type");
 
 1185            if (pubCollection.maxSequence &&
 
 1194                    pubCollection.status,
 
 1195                    *pubCollection.maxSequence};
 
 1203    auto const sequence = list[jss::sequence].
asUInt();
 
 1212    pubCollection.rawManifest = globalManifest;
 
 1213    if (!pubCollection.maxSequence || sequence > *pubCollection.maxSequence)
 
 1214        pubCollection.maxSequence = sequence;
 
 1216    Json::Value const& newList = list[jss::validators];
 
 1218    if (
accepted && pubCollection.remaining.count(sequence) != 0)
 
 1225        auto& publisher = pubCollection.current;
 
 1227        oldList = std::move(pubCollection.current.list);
 
 1229        publisher = std::move(pubCollection.remaining[sequence]);
 
 1231        pubCollection.remaining.erase(sequence);
 
 1234            publisher.sequence == sequence,
 
 1235            "ripple::ValidatorList::applyList : publisher sequence match");
 
 1239        auto& publisher = 
accepted ? pubCollection.current
 
 1240                                   : pubCollection.remaining[sequence];
 
 1241        publisher.sequence = sequence;
 
 1243            list.
isMember(jss::effective) ? list[jss::effective].
asUInt() : 0}};
 
 1246        publisher.siteUri = std::move(siteUri);
 
 1247        publisher.rawBlob = blob;
 
 1248        publisher.rawSignature = signature;
 
 1249        publisher.rawManifest = localManifest;
 
 1251            publisher.hash = *hash;
 
 1257        oldList = std::move(publisherList);
 
 1259        publisherList.
clear();
 
 1261        for (
auto const& val : newList)
 
 1263            if (val.isObject() && val.isMember(jss::validation_public_key) &&
 
 1264                val[jss::validation_public_key].isString())
 
 1267                    strUnHex(val[jss::validation_public_key].asString());
 
 1272                        << 
"Invalid node identity: " 
 1273                        << val[jss::validation_public_key].asString();
 
 1281                if (val.isMember(jss::manifest) &&
 
 1282                    val[jss::manifest].isString())
 
 1283                    manifests.
push_back(val[jss::manifest].asString());
 
 1292    pubCollection.rawVersion = 
std::max(pubCollection.rawVersion, version);
 
 1293    if (!pubCollection.remaining.empty())
 
 1297        pubCollection.rawVersion = 
std::max(pubCollection.rawVersion, 2u);
 
 1301        result, pubKey, pubCollection.status, *pubCollection.maxSequence};
 
 
 1314    using namespace std::string_literals;
 
 1315    using namespace boost::filesystem;
 
 1316    using namespace boost::system::errc;
 
 1324        boost::system::error_code ec;
 
 1331        auto const fullPath{
canonical(filename, ec)};
 
 1335        auto size = file_size(fullPath, ec);
 
 1348                return fullPath.root_path() == 
"/"s ? 
"file://" : 
"file:///";
 
 
 1394    auto const sig = 
strUnHex(signature);
 
 1400    if (!r.
parse(data, list))
 
 1403    if (list.
isMember(jss::sequence) && list[jss::sequence].
isInt() &&
 
 1404        list.
isMember(jss::expiration) && list[jss::expiration].
isInt() &&
 
 1405        (!list.
isMember(jss::effective) || list[jss::effective].
isInt()) &&
 
 1408        auto const sequence = list[jss::sequence].
asUInt();
 
 1410            list.
isMember(jss::effective) ? list[jss::effective].
asUInt() : 0}};
 
 1415        if (validUntil <= validFrom)
 
 1417        else if (sequence < listCollection.current.sequence)
 
 1419        else if (sequence == listCollection.current.sequence)
 
 1421        else if (validUntil <= now)
 
 1423        else if (validFrom > now)
 
 1434            return !listCollection.maxSequence ||
 
 1435                    sequence > *listCollection.maxSequence ||
 
 1436                    (listCollection.remaining.count(sequence) == 0 &&
 
 1437                     validFrom < listCollection.remaining
 
 1438                                     .at(*listCollection.maxSequence)
 
 
 1473    return trusted(read_lock, identity);
 
 
 1530        "ripple::ValidatorList::removePublisherList : valid reason input");
 
 1535    JLOG(
j_.
debug()) << 
"Removing validator list for publisher " 
 1538    for (
auto const& val : iList->second.current.list)
 
 1544        if (iVal->second <= 1)
 
 1550    iList->second.current.list.clear();
 
 1551    iList->second.status = reason;
 
 
 1566    return count(read_lock);
 
 
 1576        auto const& 
current = collection.current;
 
 1585        auto chainedExpiration = 
current.validUntil;
 
 1586        for (
auto const& [sequence, check] : collection.remaining)
 
 1589            if (check.validFrom <= chainedExpiration)
 
 1590                chainedExpiration = check.validUntil;
 
 1596        if (!res || chainedExpiration < *res)
 
 1598            res = chainedExpiration;
 
 1602    if (localPublisherList.list.size() > 0)
 
 1604        PublisherList collection = localPublisherList;
 
 1606        auto const& 
current = collection;
 
 1607        auto chainedExpiration = 
current.validUntil;
 
 1610        if (!res || chainedExpiration < *res)
 
 1612            res = chainedExpiration;
 
 
 1619ValidatorList::expires()
 const 
 1622    return expires(read_lock);
 
 
 1626ValidatorList::getJson()
 const 
 1632    res[jss::validation_quorum] = 
static_cast<Json::UInt>(quorum_);
 
 1637        x[jss::count] = 
static_cast<Json::UInt>(count(read_lock));
 
 1639        if (
auto when = expires(read_lock))
 
 1641            if (*when == TimeKeeper::time_point::max())
 
 1643                x[jss::expiration] = 
"never";
 
 1644                x[jss::status] = 
"active";
 
 1648                x[jss::expiration] = to_string(*when);
 
 1650                if (*when > timeKeeper_.now())
 
 1651                    x[jss::status] = 
"active";
 
 1653                    x[jss::status] = 
"expired";
 
 1658            x[jss::status] = 
"unknown";
 
 1659            x[jss::expiration] = 
"unknown";
 
 1662        x[jss::validator_list_threshold] = 
Json::UInt(listThreshold_);
 
 1669    for (
auto const& key : localPublisherList.list)
 
 1675    for (
auto const& [publicKey, pubCollection] : publisherLists_)
 
 1678        curr[jss::pubkey_publisher] = 
strHex(publicKey);
 
 1679        curr[jss::available] =
 
 1680            pubCollection.status == PublisherStatus::available;
 
 1684            target[jss::uri] = publisherList.
siteUri;
 
 1689                target[jss::expiration] = to_string(publisherList.
validUntil);
 
 1692                target[jss::effective] = to_string(publisherList.
validFrom);
 
 1694            for (
auto const& key : publisherList.
list)
 
 1700            auto const& 
current = pubCollection.current;
 
 1704                curr[jss::version] = pubCollection.rawVersion;
 
 1709        for (
auto const& [sequence, future] : pubCollection.remaining)
 
 1711            using namespace std::chrono_literals;
 
 1715            appendList(future, r);
 
 1718                future.validFrom > timeKeeper_.now() + 600s,
 
 1719                "ripple::ValidatorList::getJson : minimum valid from");
 
 1721        if (remaining.
size())
 
 1722            curr[jss::remaining] = std::move(remaining);
 
 1728    for (
auto const& k : trustedMasterKeys_)
 
 1735    validatorManifests_.for_each_manifest([&jSigningKeys,
 
 1736                                           this](Manifest 
const& manifest) {
 
 1737        auto it = keyListings_.find(manifest.masterKey);
 
 1738        if (it != keyListings_.end() && manifest.signingKey)
 
 1740            jSigningKeys[toBase58(TokenType::NodePublic, manifest.masterKey)] =
 
 1741                toBase58(TokenType::NodePublic, *manifest.signingKey);
 
 1746    if (!negativeUNL_.empty())
 
 1749        for (
auto const& k : negativeUNL_)
 
 
 1759ValidatorList::for_each_listed(
 
 1764    for (
auto const& v : keyListings_)
 
 1765        func(v.first, trusted(read_lock, v.first));
 
 
 1769ValidatorList::for_each_available(
 
 1776        uint256 const& hash)> func)
 const 
 1780    for (
auto const& [key, plCollection] : publisherLists_)
 
 1782        if (plCollection.status != PublisherStatus::available)
 
 1785            plCollection.maxSequence != 0,
 
 1786            "ripple::ValidatorList::for_each_available : nonzero maxSequence");
 
 1788            plCollection.rawManifest,
 
 1789            plCollection.rawVersion,
 
 1790            buildBlobInfos(plCollection),
 
 1792            plCollection.maxSequence.value_or(0),
 
 1793            plCollection.fullHash);
 
 
 1798ValidatorList::getAvailable(
 
 1808        JLOG(j_.
warn()) << 
"Invalid requested validator list publisher key: " 
 1815    auto const iter = publisherLists_.find(
id);
 
 1817    if (iter == publisherLists_.end() ||
 
 1818        iter->second.status != PublisherStatus::available)
 
 1822        buildFileData(
std::string{pubKey}, iter->second, forceVersion, j_);
 
 
 1828ValidatorList::calculateQuorum(
 
 1834    if (minimumQuorum_ > 0)
 
 1836        JLOG(j_.
warn()) << 
"Using potentially unsafe quorum of " 
 1838                        << 
" as specified on the command line";
 
 1839        return *minimumQuorum_;
 
 1842    if (!publisherLists_.empty())
 
 1847        for (
auto const& list : publisherLists_)
 
 1849            if (list.second.status != PublisherStatus::available)
 
 1871        auto const errorThreshold = 
std::min(
 
 1873            publisherLists_.size() - listThreshold_ + 1);
 
 1876            "ripple::ValidatorList::calculateQuorum : nonzero error threshold");
 
 
 1920ValidatorList::updateTrusted(
 
 1927    using namespace std::chrono_literals;
 
 1928    if (timeKeeper_.now() > closeTime + 30s)
 
 1929        closeTime = timeKeeper_.now();
 
 1938    for (
auto& [pubKey, collection] : publisherLists_)
 
 1941            auto& remaining = collection.remaining;
 
 1942            auto const firstIter = remaining.begin();
 
 1943            auto iter = firstIter;
 
 1944            if (iter != remaining.end() && iter->second.validFrom <= closeTime)
 
 1947                for (
auto next = 
std::next(iter); next != remaining.end() &&
 
 1948                     next->second.validFrom <= closeTime;
 
 1953                        "ripple::ValidatorList::updateTrusted : sequential " 
 1957                    iter != remaining.end(),
 
 1958                    "ripple::ValidatorList::updateTrusted : non-end of " 
 1962                auto sequence = iter->first;
 
 1963                auto& candidate = iter->second;
 
 1964                auto& 
current = collection.current;
 
 1966                    candidate.validFrom <= closeTime,
 
 1967                    "ripple::ValidatorList::updateTrusted : maximum time");
 
 1969                auto const oldList = 
current.list;
 
 1970                current = std::move(candidate);
 
 1971                if (collection.status != PublisherStatus::available)
 
 1972                    collection.status = PublisherStatus::available;
 
 1975                    "ripple::ValidatorList::updateTrusted : sequence match");
 
 1979                if (
current.validUntil <= closeTime)
 
 1982                updatePublisherList(pubKey, 
current, oldList, lock);
 
 1999                remaining.erase(firstIter, 
std::next(iter));
 
 2005        if (collection.status == PublisherStatus::available &&
 
 2006            collection.current.validUntil <= closeTime)
 
 2008            removePublisherList(lock, pubKey, PublisherStatus::expired);
 
 2011        if (collection.status != PublisherStatus::available)
 
 2019    auto it = trustedMasterKeys_.cbegin();
 
 2020    while (it != trustedMasterKeys_.cend())
 
 2022        auto const kit = keyListings_.find(*it);
 
 2023        if (kit == keyListings_.end() ||     
 
 2024            kit->second < listThreshold_ ||  
 
 2025            validatorManifests_.revoked(*it))
 
 2028            it = trustedMasterKeys_.erase(it);
 
 2033                kit->second >= listThreshold_,
 
 2034                "ripple::ValidatorList::updateTrusted : count meets threshold");
 
 2039    for (
auto const& val : keyListings_)
 
 2041        if (val.second >= listThreshold_ &&
 
 2042            !validatorManifests_.revoked(val.first) &&
 
 2043            trustedMasterKeys_.emplace(val.first).second)
 
 2049    if (!trustChanges.
added.empty() || !trustChanges.
removed.empty())
 
 2051        trustedSigningKeys_.clear();
 
 2055        for (
auto const& k : trustedMasterKeys_)
 
 2058                validatorManifests_.getSigningKey(k);
 
 2061                "ripple::ValidatorList::updateTrusted : found signing key");
 
 2062            trustedSigningKeys_.insert(*signingKey);
 
 2067        << trustedMasterKeys_.size() << 
"  of " << keyListings_.size()
 
 2068        << 
" listed validators eligible for inclusion in the trusted set";
 
 2070    auto const unlSize = trustedMasterKeys_.size();
 
 2071    auto effectiveUnlSize = unlSize;
 
 2072    auto seenSize = seenValidators.
size();
 
 2073    if (!negativeUNL_.empty())
 
 2075        for (
auto const& k : trustedMasterKeys_)
 
 2077            if (negativeUNL_.count(k))
 
 2081        for (
auto const& k : negativeUNL_)
 
 2085        for (
auto const& nid : seenValidators)
 
 2087            if (negUnlNodeIDs.
count(nid))
 
 2091    quorum_ = calculateQuorum(unlSize, effectiveUnlSize, seenSize);
 
 2093    JLOG(j_.
debug()) << 
"Using quorum of " << quorum_ << 
" for new set of " 
 2094                     << unlSize << 
" trusted validators (" 
 2095                     << trustChanges.
added.size() << 
" added, " 
 2096                     << trustChanges.
removed.size() << 
" removed)";
 
 2098    if (unlSize < quorum_)
 
 2100        JLOG(j_.
warn()) << 
"New quorum of " << quorum_
 
 2101                        << 
" exceeds the number of trusted validators (" 
 2105    if ((publisherLists_.size() || localPublisherList.list.size()) &&
 
 2112    return trustChanges;
 
 
 2116ValidatorList::getTrustedMasterKeys()
 const 
 2119    return trustedMasterKeys_;
 
 
 2123ValidatorList::getListThreshold()
 const 
 2126    return listThreshold_;
 
 
 2130ValidatorList::getNegativeUNL()
 const 
 2133    return negativeUNL_;
 
 
 2140    negativeUNL_ = negUnl;
 
 
 2144ValidatorList::negativeUNLFilter(
 
 2148    auto ret = std::move(validations);
 
 2151    if (!negativeUNL_.empty())
 
 2157                [&](
auto const& v) -> 
bool {
 
 2158                    if (auto const masterKey =
 
 2159                            getTrustedKey(read_lock, v->getSignerPublic());
 
 2162                        return negativeUNL_.count(*masterKey);
 
 
Unserialize a JSON document into a Value.
 
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
 
Value & append(Value const &value)
Append value to array at the end.
 
UInt size() const
Number of values in array or object.
 
std::string toStyledString() const
 
std::string asString() const
Returns the unquoted string value.
 
bool isMember(char const *key) const
Return true if the object has a member named key.
 
A generic endpoint for log messages.
 
Stream trace() const
Severity stream access functions.
 
typename Clock::time_point time_point
 
typename Clock::duration duration
 
Routing table for objects identified by hash.
 
std::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
 
bool addSuppressionPeer(uint256 const &key, PeerShortID peer)
 
Remembers manifests with the highest sequence number.
 
std::optional< PublicKey > getSigningKey(PublicKey const &pk) const
Returns master key's current signing key.
 
bool revoked(PublicKey const &pk) const
Returns true if master key has been revoked in a manifest.
 
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
 
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
 
static std::size_t totalSize(::google::protobuf::Message const &message)
 
Provides server functionality for clients.
 
virtual void setUNLBlocked()=0
 
virtual void clearUNLBlocked()=0
 
Manages the set of connected peers.
 
virtual PeerSequence getActivePeers() const =0
Returns a sequence representing the current list of peers.
 
Represents a peer connection in the overlay.
 
virtual bool supportsFeature(ProtocolFeature f) const =0
 
virtual std::string const & fingerprint() const =0
 
virtual void send(std::shared_ptr< Message > const &m)=0
 
virtual void setPublisherListSequence(PublicKey const &, std::size_t const)=0
 
virtual id_t id() const =0
 
std::size_t size() const noexcept
 
const_iterator end() const noexcept
 
An immutable linear range of bytes.
 
Manages various times used by the server.
 
time_point now() const override
Returns the current time, using the server's clock.
 
std::size_t count() const
Return the number of configured validator list sites.
 
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
 
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
 
static void broadcastBlobs(PublicKey const &publisherKey, PublisherListCollection const &lists, std::size_t maxSequence, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, beast::Journal j)
 
boost::filesystem::path getCacheFileName(lock_guard const &, PublicKey const &pubKey) const
Get the filename used for caching UNLs.
 
std::vector< std::string > loadLists()
 
PublisherList localPublisherList
 
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
 
ManifestCache & validatorManifests_
 
std::atomic< std::size_t > quorum_
 
void updatePublisherList(PublicKey const &pubKey, PublisherList const ¤t, std::vector< PublicKey > const &oldList, lock_guard const &)
 
static Json::Value buildFileData(std::string const &pubKey, PublisherListCollection const &pubCollection, beast::Journal j)
Build a Json representation of the collection, suitable for writing to a cache file,...
 
static void buildBlobInfos(std::map< std::size_t, ValidatorBlobInfo > &blobInfos, PublisherListCollection const &lists)
 
hash_map< PublicKey, std::size_t > keyListings_
 
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
 
std::size_t listThreshold_
 
void cacheValidatorFile(lock_guard const &lock, PublicKey const &pubKey) const
Write a JSON UNL to a cache file.
 
hash_set< PublicKey > trustedMasterKeys_
 
PublisherListStats applyList(std::string const &globalManifest, std::optional< std::string > const &localManifest, std::string const &blob, std::string const &signature, std::uint32_t version, std::string siteUri, std::optional< uint256 > const &hash, lock_guard const &)
Apply published list of public keys.
 
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
 
PublisherListStats applyListsAndBroadcast(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, uint256 const &hash, Overlay &overlay, HashRouter &hashRouter, NetworkOPs &networkOPs)
Apply multiple published lists of public keys, then broadcast it to all peers that have not seen it o...
 
bool trustedPublisher(PublicKey const &identity) const
Returns true if public key is a trusted publisher.
 
std::optional< PublicKey > getListedKey(PublicKey const &identity) const
Returns listed master public if public key is included on any lists.
 
boost::filesystem::path const dataPath_
 
bool removePublisherList(lock_guard const &, PublicKey const &publisherKey, PublisherStatus reason)
Stop trusting publisher's list of keys.
 
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
 
static constexpr std::size_t maxSupportedBlobs
 
ValidatorList(ManifestCache &validatorManifests, ManifestCache &publisherManifests, TimeKeeper &timeKeeper, std::string const &databasePath, beast::Journal j, std::optional< std::size_t > minimumQuorum=std::nullopt)
 
std::optional< PublicKey > localPubKey_
 
bool load(std::optional< PublicKey > const &localSigningKey, std::vector< std::string > const &configKeys, std::vector< std::string > const &publisherKeys, std::optional< std::size_t > listThreshold={})
Load configured trusted keys.
 
std::optional< std::size_t > minimumQuorum_
 
std::pair< ListDisposition, std::optional< PublicKey > > verify(lock_guard const &, Json::Value &list, Manifest manifest, std::string const &blob, std::string const &signature)
Check response for trusted valid published list.
 
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, Json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
 
static std::string const filePrefix_
 
hash_map< PublicKey, PublisherListCollection > publisherLists_
 
PublisherListStats applyLists(std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs, std::string siteUri, std::optional< uint256 > const &hash={})
Apply multiple published lists of public keys.
 
static std::pair< std::size_t, std::size_t > buildValidatorListMessages(std::size_t messageVersion, std::uint64_t peerSequence, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, std::vector< MessageWithHash > &messages, std::size_t maxSize=maximiumMessageSize)
 
ManifestCache & publisherManifests_
 
static constexpr std::uint32_t supportedListVersions[]
 
T emplace_back(T... args)
 
@ arrayValue
array value (ordered list)
 
@ objectValue
object value (collection of name/value pairs).
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
 
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
 
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
 
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical=true) noexcept
Verify a signature on a message.
 
@ ValidatorListPropagation
 
@ ValidatorList2Propagation
 
std::string base64_decode(std::string_view data)
 
std::size_t splitMessage(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin=0, std::size_t end=0)
 
std::size_t splitMessageParts(std::vector< ValidatorList::MessageWithHash > &messages, protocol::TMValidatorListCollection const &largeMsg, std::size_t maxSize, std::size_t begin, std::size_t end)
 
@ current
This was a new validation and was added.
 
@ unsupported_version
List version is not supported.
 
@ stale
Trusted publisher key, but seq is too old.
 
@ untrusted
List signed by untrusted publisher key.
 
@ same_sequence
Same sequence as current list.
 
@ pending
List will be valid in the future.
 
@ known_sequence
Future sequence already seen.
 
@ expired
List is expired, but has the largest non-pending sequence seen so far.
 
@ invalid
Invalid format or signature.
 
std::error_code make_error_code(ripple::TokenCodecErrc e)
 
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
 
std::string strHex(FwdIt begin, FwdIt end)
 
@ accepted
Manifest is valid.
 
@ invalid
Timely, but invalid signature.
 
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
 
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
 
std::optional< Blob > strViewUnHex(std::string_view strSrc)
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
constexpr std::size_t maximiumMessageSize
 
void writeFileContents(boost::system::error_code &ec, boost::filesystem::path const &destPath, std::string const &contents)
 
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
 
std::size_t buildValidatorListMessage(std::vector< ValidatorList::MessageWithHash > &messages, std::uint32_t rawVersion, std::string const &rawManifest, ValidatorBlobInfo const ¤tBlob, std::size_t maxSize)
 
Changes in trusted nodes after updating validator list.
 
hash_set< NodeID > removed
 
Used to represent the information stored in the blobs_v2 Json array.
 
std::optional< std::string > manifest
 
MessageWithHash()=default
 
std::map< std::size_t, PublisherList > remaining
 
Describes the result of processing a Validator List (UNL), including some of the information from the...
 
void mergeDispositions(PublisherListStats const &src)
 
ListDisposition bestDisposition() const
 
PublisherListStats()=default
 
ListDisposition worstDisposition() const
 
std::map< ListDisposition, std::size_t > dispositions
 
std::optional< PublicKey > publisherKey
 
std::vector< PublicKey > list
 
TimeKeeper::time_point validUntil
 
TimeKeeper::time_point validFrom