diff --git a/src/xrpld/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h index ff5aa8c71fa..ef04c9461b0 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 1951c657b07..e9e3645fe74 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -676,8 +676,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; + 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, @@ -700,7 +747,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) @@ -736,6 +783,7 @@ ValidatorList::sendValidatorList( << " validator list(s) for " << strHex(publisherKey) << " with sequence range " << peerSequence << ", " << newPeerSequence << " to " << peer.fingerprint(); + return "ValidatorListCollection"; } else { @@ -746,13 +794,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, @@ -765,7 +815,7 @@ ValidatorList::sendValidatorList( beast::Journal j) { std::vector messages; - sendValidatorList( + return sendValidatorList( peer, peerSequence, publisherKey, @@ -833,7 +883,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 13fe0c571cf..2fc41d845eb 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -893,6 +893,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: " << base64_decode(blob.blob); + JLOG(stream) << "Blob " << count + << " manifest: " << (blob.manifest ? base64_decode(*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() { @@ -2157,6 +2197,8 @@ PeerImp::onValidatorListMessage( return; } + logVL(p_journal_, manifest, version, blobs, hash); + auto const applyResult = app_.getValidators().applyListsAndBroadcast( manifest, version, @@ -2197,7 +2239,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::same_sequence: @@ -2215,8 +2258,31 @@ PeerImp::onValidatorListMessage( } #endif // !NDEBUG + [[fallthrough]]; + case ListDisposition::stale: { + auto const [pubKey, currentPeerSeq] = [&]() { + std::lock_guard 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: