Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9316f24
[WIP] Toying with the idea of VL exchange
ximinez Jan 21, 2021
eca1267
Merge branch 'develop' into unlsync
ximinez Nov 12, 2025
4dc8ab4
Merge branch 'develop' into unlsync
ximinez Nov 13, 2025
b21b93c
Merge branch 'develop' into unlsync
ximinez Nov 15, 2025
454e060
Merge branch 'develop' into unlsync
ximinez Nov 19, 2025
5463f3d
Merge branch 'develop' into unlsync
ximinez Nov 21, 2025
6a8071a
Merge branch 'develop' into unlsync
ximinez Nov 25, 2025
a749c81
Merge branch 'develop' into unlsync
ximinez Nov 28, 2025
95c03ee
Merge branch 'develop' into unlsync
ximinez Dec 1, 2025
81f1f5c
Merge branch 'develop' into unlsync
ximinez Dec 3, 2025
db9aa06
Merge branch 'develop' into unlsync
ximinez Dec 6, 2025
ca19741
Merge branch 'develop' into unlsync
ximinez Dec 13, 2025
1523729
Merge branch 'develop' into unlsync
ximinez Dec 19, 2025
2ab1c05
Merge branch 'develop' into unlsync
ximinez Dec 22, 2025
c428538
Merge branch 'develop' into unlsync
ximinez Jan 6, 2026
4c9e8a6
Merge branch 'develop' into unlsync
ximinez Jan 8, 2026
53920ed
Merge branch 'develop' into unlsync
ximinez Jan 8, 2026
dfa281e
Merge branch 'develop' into unlsync
ximinez Jan 11, 2026
d11f577
Merge branch 'develop' into unlsync
ximinez Jan 12, 2026
a59bc90
Merge branch 'develop' into unlsync
ximinez Jan 13, 2026
dd273b9
Merge branch 'develop' into unlsync
ximinez Jan 15, 2026
2901e12
Merge commit '92046785d1fea5f9efe5a770d636792ea6cab78b' into unlsync
ximinez Jan 28, 2026
371d5ca
Merge commit '5f638f55536def0d88b970d1018a465a238e55f4' into unlsync
ximinez Jan 28, 2026
fdd295e
Merge branch 'develop' into unlsync
ximinez Jan 28, 2026
4152d2e
Fix formatting
ximinez Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/xrpld/app/misc/ValidatorList.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ class ValidatorList
static std::vector<ValidatorBlobInfo>
parseBlobs(protocol::TMValidatorListCollection const& body);

static void
static std::optional<std::string>
sendValidatorList(
Peer& peer,
std::uint64_t peerSequence,
Expand All @@ -349,6 +349,14 @@ class ValidatorList
HashRouter& hashRouter,
beast::Journal j);

std::tuple<std::string, std::uint32_t, std::map<std::size_t, ValidatorBlobInfo>, uint256>
sendLatestValidatorLists(
Peer& peer,
std::uint64_t peerSequence,
PublicKey const& publisherKey,
HashRouter& hashRouter,
beast::Journal j) const;

[[nodiscard]] static std::pair<std::size_t, std::size_t>
buildValidatorListMessages(
std::size_t messageVersion,
Expand Down Expand Up @@ -783,7 +791,7 @@ class ValidatorList
HashRouter& hashRouter,
beast::Journal j);

static void
static std::optional<std::string>
sendValidatorList(
Peer& peer,
std::uint64_t peerSequence,
Expand Down
62 changes: 57 additions & 5 deletions src/xrpld/app/misc/detail/ValidatorList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,8 +661,55 @@ ValidatorList::buildValidatorListMessages(
return {0, 0};
}

std::tuple<std::string, std::uint32_t, std::map<std::size_t, ValidatorBlobInfo>, uint256>
ValidatorList::sendLatestValidatorLists(
Peer& peer,
std::uint64_t peerSequence,
PublicKey const& publisherKey,
HashRouter& hashRouter,
beast::Journal j) const
{
std::vector<ValidatorList::MessageWithHash> messages;
std::map<std::size_t, ValidatorBlobInfo> blobInfos;

if (publisherLists_.count(publisherKey) == 0)
return {};
ValidatorList::PublisherListCollection const& lists = publisherLists_.at(publisherKey);

auto const maxSequence = lists.current.sequence;
ASSERT(
lists.current.sequence == maxSequence || lists.remaining.count(maxSequence) == 1,
"ripple::ValidatorList::sendLatestValidatorLists : valid sequence");

if (peerSequence < maxSequence)
{
buildBlobInfos(blobInfos, lists);
sendValidatorList(
peer,
peerSequence,
publisherKey,
maxSequence,
lists.rawVersion,
lists.rawManifest,
blobInfos,
messages,
hashRouter,
j);

// Suppress the messages so they'll be ignored next time.
uint256 lasthash;
for (auto const& m : messages)
{
lasthash = m.hash;
hashRouter.addSuppressionPeer(lasthash, peer.id());
}
return std::make_tuple(lists.rawManifest, lists.rawVersion, blobInfos, lasthash);
}
return {};
}

// static
void
std::optional<std::string>
ValidatorList::sendValidatorList(
Peer& peer,
std::uint64_t peerSequence,
Expand All @@ -679,7 +726,7 @@ ValidatorList::sendValidatorList(
: peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1
: 0;
if (!messageVersion)
return;
return {};
auto const [newPeerSequence, numVLs] = buildValidatorListMessages(
messageVersion, peerSequence, maxSequence, rawVersion, rawManifest, blobInfos, messages);
if (newPeerSequence)
Expand Down Expand Up @@ -707,9 +754,12 @@ ValidatorList::sendValidatorList(
if (sent)
{
if (messageVersion > 1)
{
JLOG(j.debug()) << "Sent " << messages.size() << " validator list collection(s) containing " << numVLs
<< " validator list(s) for " << strHex(publisherKey) << " with sequence range "
<< peerSequence << ", " << newPeerSequence << " to " << peer.fingerprint();
return "ValidatorListCollection";
}
else
{
XRPL_ASSERT(
Expand All @@ -718,13 +768,15 @@ ValidatorList::sendValidatorList(
"list");
JLOG(j.debug()) << "Sent validator list for " << strHex(publisherKey) << " with sequence "
<< newPeerSequence << " to " << peer.fingerprint();
return "ValidatorList";
}
}
}
return {};
}

// static
void
std::optional<std::string>
ValidatorList::sendValidatorList(
Peer& peer,
std::uint64_t peerSequence,
Expand All @@ -737,7 +789,7 @@ ValidatorList::sendValidatorList(
beast::Journal j)
{
std::vector<ValidatorList::MessageWithHash> messages;
sendValidatorList(
return sendValidatorList(
peer, peerSequence, publisherKey, maxSequence, rawVersion, rawManifest, blobInfos, messages, hashRouter, j);
}

Expand Down Expand Up @@ -796,7 +848,7 @@ ValidatorList::broadcastBlobs(
std::map<std::size_t, ValidatorBlobInfo> blobInfos;

XRPL_ASSERT(
lists.current.sequence == maxSequence || lists.remaining.count(maxSequence) == 1,
lists.current.sequence <= maxSequence || lists.remaining.count(maxSequence) == 1,
"xrpl::ValidatorList::broadcastBlobs : valid sequence");
// Can't use overlay.foreach here because we need to modify
// the peer, and foreach provides a const&
Expand Down
61 changes: 59 additions & 2 deletions src/xrpld/overlay/detail/PeerImp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,37 @@ PeerImp::domain() const

// Protocol logic

void
logVLBlob(beast::Journal j, ValidatorBlobInfo const& blob, std::size_t count)
{
auto const stream = j.trace();
JLOG(stream) << "Blob " << count << " Signature: " << blob.signature;
JLOG(stream) << "Blob " << count << " blob: " << base64_decode(blob.blob);
JLOG(stream) << "Blob " << count << " manifest: " << (blob.manifest ? base64_decode(*blob.manifest) : "NONE");
}

void
logVLBlob(beast::Journal j, std::pair<std::size_t, ValidatorBlobInfo> const& blob, std::size_t count)
{
logVLBlob(j, blob.second, count);
}

template <class TBlobs>
void
logVL(beast::Journal j, std::string const& manifest, std::uint32_t version, TBlobs const& blobs, uint256 const& hash)
{
auto const stream = j.trace();
JLOG(stream) << "Manifest: " << manifest;
JLOG(stream) << "Version: " << version;
JLOG(stream) << "Hash: " << hash;
std::size_t count = 1;
for (auto const& blob : blobs)
{
logVLBlob(j, blob, count);
++count;
}
}

void
PeerImp::doProtocolStart()
{
Expand Down Expand Up @@ -1964,6 +1995,8 @@ PeerImp::onValidatorListMessage(
return;
}

logVL(p_journal_, manifest, version, blobs, hash);

auto const applyResult = app_.validators().applyListsAndBroadcast(
manifest,
version,
Expand Down Expand Up @@ -2002,7 +2035,8 @@ PeerImp::onValidatorListMessage(
iter->second < applyResult.sequence, "xrpl::PeerImp::onValidatorListMessage : lower sequence");
}
#endif
publisherListSequences_[pubKey] = applyResult.sequence;
if (publisherListSequences_[pubKey] < applyResult.sequence)
publisherListSequences_[pubKey] = applyResult.sequence;
}
break;
case ListDisposition::same_sequence:
Expand All @@ -2020,8 +2054,31 @@ PeerImp::onValidatorListMessage(
}
#endif // !NDEBUG

[[fallthrough]];
case ListDisposition::stale: {
auto const [pubKey, currentPeerSeq] = [&]() {
std::lock_guard<std::mutex> sl(recentLock_);
ASSERT(
applyResult.sequence && applyResult.publisherKey,
"ripple::PeerImp::onValidatorListMessage : (stale) nonzero "
"sequence");
auto const& pubKey = *applyResult.publisherKey;
auto const& current = publisherListSequences_[pubKey];
ASSERT(
current <= applyResult.sequence,
"ripple::PeerImp::onValidatorListMessage : (stale) valid "
"sequence");
return std::make_pair(pubKey, current ? current : applyResult.sequence);
}();
if (currentPeerSeq <= applyResult.sequence)
{
auto const [sentmanifest, sentversion, sentblobs, senthash] =
app_.validators().sendLatestValidatorLists(
*this, currentPeerSeq, pubKey, app_.getHashRouter(), p_journal_);
logVL(p_journal_, sentmanifest, sentversion, sentblobs, senthash);
}
}
break;
case ListDisposition::stale:
case ListDisposition::untrusted:
case ListDisposition::invalid:
case ListDisposition::unsupported_version:
Expand Down