From 2827de4d63d5f591addb1a16b87c1ecc23d102ba Mon Sep 17 00:00:00 2001 From: Nik Bougalis Date: Sun, 8 Mar 2020 19:10:39 -0700 Subject: [PATCH] Report the server version in published validations: Currently there is no mechanism for a validator to report the version of the software it is currently running. Such reports can be useful for those who are developing network monitoring dashboards and server operators in general. This commit, if merged, defines an encoding scheme to encode a version string into a 64-bit unsigned integer and adds an additional optional field to validations. This commit piggybacks on "HardenedValidations" amendment to determine whether version information should be propagated or not. The general encoding scheme is: XXXXXXXX-XXXXXXXX-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY X: 16 bits identifying the particular implementation Y: 48 bits of data specific to the implementation The rippled-specific format (implementation ID is: 0x18 0x3B) is: 00011000-00111011-MMMMMMMM-mmmmmmmm-pppppppp-TTNNNNNN-00000000-00000000 M: 8-bit major version (0-255) m: 8-bit minor version (0-255) p: 8-bit patch version (0-255) T: 11 if neither an RC nor a beta 10 if an RC 01 if a beta N: 6-bit rc/beta number (1-63) --- src/ripple/app/consensus/RCLConsensus.cpp | 6 ++ src/ripple/protocol/BuildInfo.h | 25 ++++++++ src/ripple/protocol/SField.h | 1 + src/ripple/protocol/impl/BuildInfo.cpp | 74 ++++++++++++++++++++++- src/ripple/protocol/impl/SField.cpp | 1 + src/ripple/protocol/impl/STValidation.cpp | 1 + 6 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index 2c3c6a1e71..a742941f96 100644 --- a/src/ripple/app/consensus/RCLConsensus.cpp +++ b/src/ripple/app/consensus/RCLConsensus.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -790,6 +791,11 @@ RCLConsensus::Adaptor::validate( v.setFieldH256(sfValidatedHash, vl->info().hash); v.setFieldU64(sfCookie, valCookie_); + + // Report our server version every flag ledger: + if ((ledger.seq() + 1) % 256 == 0) + v.setFieldU64( + sfServerVersion, BuildInfo::getEncodedVersion()); } // Report our load diff --git a/src/ripple/protocol/BuildInfo.h b/src/ripple/protocol/BuildInfo.h index 7f81131911..84a8331345 100644 --- a/src/ripple/protocol/BuildInfo.h +++ b/src/ripple/protocol/BuildInfo.h @@ -43,6 +43,31 @@ getVersionString(); std::string const& getFullVersionString(); +/** Returns the server version packed in a 64-bit integer. + + The general format is: + + ........-........-........-........-........-........-........-........ + XXXXXXXX-XXXXXXXX-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY-YYYYYYYY + + X: 16 bits identifying the particular implementation + Y: 48 bits of data specific to the implementation + + The rippled-specific format (implementation ID is: 0x18 0x3B) is: + + 00011000-00111011-MMMMMMMM-mmmmmmmm-pppppppp-TTNNNNNN-00000000-00000000 + + M: 8-bit major version (0-255) + m: 8-bit minor version (0-255) + p: 8-bit patch version (0-255) + T: 11 if neither an RC nor a beta + 10 if an RC + 01 if a beta + N: 6-bit rc/beta number (1-63) +*/ +std::uint64_t +getEncodedVersion(); + } // namespace BuildInfo } // namespace ripple diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index 38628f852a..abf7037e7d 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -401,6 +401,7 @@ extern SF_U64 const sfLowNode; extern SF_U64 const sfHighNode; extern SF_U64 const sfDestinationNode; extern SF_U64 const sfCookie; +extern SF_U64 const sfServerVersion; // 128-bit extern SF_U128 const sfEmailHash; diff --git a/src/ripple/protocol/impl/BuildInfo.cpp b/src/ripple/protocol/impl/BuildInfo.cpp index 47595e8929..55f9fe6c34 100644 --- a/src/ripple/protocol/impl/BuildInfo.cpp +++ b/src/ripple/protocol/impl/BuildInfo.cpp @@ -18,10 +18,11 @@ //============================================================================== #include +#include #include #include - #include +#include namespace ripple { @@ -76,6 +77,77 @@ getFullVersionString() return value; } +std::uint64_t +getEncodedVersion() +{ + static std::uint64_t const cookie = []() { + std::uint64_t c = 0x183B000000000000; + + beast::SemanticVersion v; + + if (v.parse(versionString)) + { + if (v.majorVersion >= 0 && v.majorVersion <= 255) + c |= static_cast(v.majorVersion) << 40; + + if (v.minorVersion >= 0 && v.minorVersion <= 255) + c |= static_cast(v.minorVersion) << 32; + + if (v.patchVersion >= 0 && v.patchVersion <= 255) + c |= static_cast(v.patchVersion) << 24; + + if (!v.isPreRelease()) + c |= static_cast(0xC00000); + + if (v.isPreRelease()) + { + std::uint8_t x = 0; + + for (auto id : v.preReleaseIdentifiers) + { + auto parsePreRelease = + [](std::string_view identifier, + std::string_view prefix, + std::uint8_t key, + std::uint8_t lok, + std::uint8_t hik) -> std::uint8_t { + std::uint8_t ret = 0; + + if (prefix != identifier.substr(0, prefix.length())) + return 0; + + if (!beast::lexicalCastChecked( + ret, + std::string( + identifier.substr(prefix.length())))) + return 0; + + if (std::clamp(ret, lok, hik) != ret) + return 0; + + return ret + key; + }; + + x = parsePreRelease(id, "rc", 0x80, 0, 63); + + if (x == 0) + x = parsePreRelease(id, "b", 0x40, 0, 63); + + if (x & 0xC0) + { + c |= static_cast(x) << 16; + break; + } + } + } + } + + return c; + }(); + + return cookie; +} + } // namespace BuildInfo } // namespace ripple diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 06a85ca6bc..4784d2de99 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -131,6 +131,7 @@ SF_U64 const sfLowNode(access, STI_UINT64, 7, "LowNode"); SF_U64 const sfHighNode(access, STI_UINT64, 8, "HighNode"); SF_U64 const sfDestinationNode(access, STI_UINT64, 9, "DestinationNode"); SF_U64 const sfCookie(access, STI_UINT64, 10, "Cookie"); +SF_U64 const sfServerVersion(access, STI_UINT64, 11, "ServerVersion"); // 128-bit SF_U128 const sfEmailHash(access, STI_HASH128, 1, "EmailHash"); diff --git a/src/ripple/protocol/impl/STValidation.cpp b/src/ripple/protocol/impl/STValidation.cpp index 4612baf691..458b601bf7 100644 --- a/src/ripple/protocol/impl/STValidation.cpp +++ b/src/ripple/protocol/impl/STValidation.cpp @@ -47,6 +47,7 @@ STValidation::validationFormat() {sfConsensusHash, soeOPTIONAL}, {sfCookie, soeDEFAULT}, {sfValidatedHash, soeOPTIONAL}, + {sfServerVersion, soeOPTIONAL}, }; return format;