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)
This commit is contained in:
Nik Bougalis
2020-03-08 19:10:39 -07:00
parent 381606aba2
commit 2827de4d63
6 changed files with 107 additions and 1 deletions

View File

@@ -38,6 +38,7 @@
#include <ripple/nodestore/DatabaseShard.h>
#include <ripple/overlay/Overlay.h>
#include <ripple/overlay/predicates.h>
#include <ripple/protocol/BuildInfo.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/digest.h>
@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -18,10 +18,11 @@
//==============================================================================
#include <ripple/basics/contract.h>
#include <ripple/beast/core/LexicalCast.h>
#include <ripple/beast/core/SemanticVersion.h>
#include <ripple/protocol/BuildInfo.h>
#include <boost/preprocessor/stringize.hpp>
#include <algorithm>
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<std::uint64_t>(v.majorVersion) << 40;
if (v.minorVersion >= 0 && v.minorVersion <= 255)
c |= static_cast<std::uint64_t>(v.minorVersion) << 32;
if (v.patchVersion >= 0 && v.patchVersion <= 255)
c |= static_cast<std::uint64_t>(v.patchVersion) << 24;
if (!v.isPreRelease())
c |= static_cast<std::uint64_t>(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<std::uint64_t>(x) << 16;
break;
}
}
}
}
return c;
}();
return cookie;
}
} // namespace BuildInfo
} // namespace ripple

View File

@@ -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");

View File

@@ -47,6 +47,7 @@ STValidation::validationFormat()
{sfConsensusHash, soeOPTIONAL},
{sfCookie, soeDEFAULT},
{sfValidatedHash, soeOPTIONAL},
{sfServerVersion, soeOPTIONAL},
};
return format;