From 117c7249761e6b8437d8544d84af4cd87494203b 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 | 5 ++ 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, 106 insertions(+), 1 deletion(-) diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index 2c3c6a1e71e..c98e5da8b05 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,10 @@ 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 7f81131911d..84a83313452 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 38628f852a2..abf7037e7de 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 47595e89295..55f9fe6c344 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 06a85ca6bc0..4784d2de99c 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 672cad17079..7aaf0f93cad 100644 --- a/src/ripple/protocol/impl/STValidation.cpp +++ b/src/ripple/protocol/impl/STValidation.cpp @@ -41,6 +41,7 @@ SOTemplate const STValidation::validationFormat{ {sfConsensusHash, soeOPTIONAL}, {sfCookie, soeDEFAULT}, {sfValidatedHash, soeOPTIONAL}, + {sfServerVersion, soeOPTIONAL}, }; uint256