diff --git a/src/xrpld/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h index dcd7a24499c..cc086491930 100644 --- a/src/xrpld/app/misc/ValidatorList.h +++ b/src/xrpld/app/misc/ValidatorList.h @@ -339,7 +339,7 @@ class ValidatorList static std::vector parseBlobs(protocol::TMValidatorListCollection const& body); - static void + static std::optional sendValidatorList( Peer& peer, std::uint64_t peerSequence, @@ -351,6 +351,14 @@ class ValidatorList HashRouter& hashRouter, beast::Journal j); + std::tuple, uint256> + sendLatestValidatorLists( + Peer& peer, + std::uint64_t peerSequence, + PublicKey const& publisherKey, + HashRouter& hashRouter, + beast::Journal j) const; + [[nodiscard]] static std::pair buildValidatorListMessages( std::size_t messageVersion, @@ -788,7 +796,7 @@ class ValidatorList HashRouter& hashRouter, beast::Journal j); - static void + static std::optional sendValidatorList( Peer& peer, std::uint64_t peerSequence, diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 57b65814e1d..48c1b720123 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -713,8 +713,55 @@ ValidatorList::buildValidatorListMessages( return {0, 0}; } +std::tuple, uint256> +ValidatorList::sendLatestValidatorLists( + Peer& peer, + std::uint64_t peerSequence, + PublicKey const& publisherKey, + HashRouter& hashRouter, + beast::Journal j) const +{ + std::vector messages; + std::map blobInfos; + + if (publisherLists_.count(publisherKey) == 0) + return {}; + ValidatorList::PublisherListCollection const& lists = publisherLists_.at(publisherKey); + + auto const maxSequence = lists.current.sequence; + XRPL_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 ValidatorList::sendValidatorList( Peer& peer, std::uint64_t peerSequence, @@ -737,7 +784,7 @@ ValidatorList::sendValidatorList( messageVersion = 1; } if (messageVersion == 0u) - return; + return {}; auto const [newPeerSequence, numVLs] = buildValidatorListMessages( messageVersion, peerSequence, maxSequence, rawVersion, rawManifest, blobInfos, messages); if (newPeerSequence != 0u) @@ -773,6 +820,7 @@ ValidatorList::sendValidatorList( << " validator list(s) for " << strHex(publisherKey) << " with sequence range " << peerSequence << ", " << newPeerSequence << " to " << peer.fingerprint(); + return "ValidatorListCollection"; } else { @@ -783,13 +831,15 @@ ValidatorList::sendValidatorList( JLOG(j.debug()) << "Sent validator list for " << strHex(publisherKey) << " with sequence " << newPeerSequence << " to " << peer.fingerprint(); + return "ValidatorList"; } } } + return {}; } // static -void +std::optional ValidatorList::sendValidatorList( Peer& peer, std::uint64_t peerSequence, @@ -802,7 +852,7 @@ ValidatorList::sendValidatorList( beast::Journal j) { std::vector messages; - sendValidatorList( + return sendValidatorList( peer, peerSequence, publisherKey, @@ -874,7 +924,7 @@ ValidatorList::broadcastBlobs( std::map 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& diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 070f91c0bf0..ed357f50e28 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -960,6 +960,46 @@ 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: " << base64Decode(blob.blob); + JLOG(stream) << "Blob " << count + << " manifest: " << (blob.manifest ? base64Decode(*blob.manifest) : "NONE"); +} + +void +logVLBlob( + beast::Journal j, + std::pair const& blob, + std::size_t count) +{ + logVLBlob(j, blob.second, count); +} + +template +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() { @@ -2224,6 +2264,8 @@ PeerImp::onValidatorListMessage( return; } + logVL(pJournal_, manifest, version, blobs, hash); + auto const applyResult = app_.getValidators().applyListsAndBroadcast( manifest, version, @@ -2265,7 +2307,8 @@ PeerImp::onValidatorListMessage( "xrpl::PeerImp::onValidatorListMessage : lower sequence"); } #endif - publisherListSequences_[pubKey] = applyResult.sequence; + if (publisherListSequences_[pubKey] < applyResult.sequence) + publisherListSequences_[pubKey] = applyResult.sequence; } break; case ListDisposition::SameSequence: @@ -2283,8 +2326,31 @@ PeerImp::onValidatorListMessage( } #endif // !NDEBUG + [[fallthrough]]; + case ListDisposition::Stale: { + auto const [pubKey, currentPeerSeq] = [&]() { + std::lock_guard sl(recentLock_); + XRPL_ASSERT( + applyResult.sequence && applyResult.publisherKey, + "ripple::PeerImp::onValidatorListMessage : (stale) nonzero " + "sequence"); + auto const& pubKey = *applyResult.publisherKey; + auto const& current = publisherListSequences_[pubKey]; + XRPL_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_.getValidators().sendLatestValidatorLists( + *this, currentPeerSeq, pubKey, app_.getHashRouter(), pJournal_); + logVL(pJournal_, sentmanifest, sentversion, sentblobs, senthash); + } + } break; - case ListDisposition::Stale: case ListDisposition::Untrusted: case ListDisposition::Invalid: case ListDisposition::UnsupportedVersion: