mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-17 09:35:51 +00:00
Implement version upgrade warning:
If the 'HardenedValidations' amendment is enabled, this commit will track the version of the software that validators embed in their validations. If a server notices that at least 60% of the validators on its UNL are running a newer version than it is running, it will periodically print an informational message, reminding the operator to check for update.
This commit is contained in:
@@ -150,6 +150,7 @@ install (
|
|||||||
src/ripple/basics/IOUAmount.h
|
src/ripple/basics/IOUAmount.h
|
||||||
src/ripple/basics/LocalValue.h
|
src/ripple/basics/LocalValue.h
|
||||||
src/ripple/basics/Log.h
|
src/ripple/basics/Log.h
|
||||||
|
src/ripple/basics/MathUtilities.h
|
||||||
src/ripple/basics/safe_cast.h
|
src/ripple/basics/safe_cast.h
|
||||||
src/ripple/basics/Slice.h
|
src/ripple/basics/Slice.h
|
||||||
src/ripple/basics/StringUtilities.h
|
src/ripple/basics/StringUtilities.h
|
||||||
@@ -870,6 +871,7 @@ target_sources (rippled PRIVATE
|
|||||||
test sources:
|
test sources:
|
||||||
subdir: protocol
|
subdir: protocol
|
||||||
#]===============================]
|
#]===============================]
|
||||||
|
src/test/protocol/BuildInfo_test.cpp
|
||||||
src/test/protocol/InnerObjectFormats_test.cpp
|
src/test/protocol/InnerObjectFormats_test.cpp
|
||||||
src/test/protocol/Issue_test.cpp
|
src/test/protocol/Issue_test.cpp
|
||||||
src/test/protocol/PublicKey_test.cpp
|
src/test/protocol/PublicKey_test.cpp
|
||||||
|
|||||||
@@ -407,6 +407,9 @@ private:
|
|||||||
// without first wiping the database.
|
// without first wiping the database.
|
||||||
LedgerIndex const max_ledger_difference_{1000000};
|
LedgerIndex const max_ledger_difference_{1000000};
|
||||||
|
|
||||||
|
// Time that the previous upgrade warning was issued.
|
||||||
|
TimeKeeper::time_point upgradeWarningPrevTime_{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Stats
|
struct Stats
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include <ripple/app/paths/PathRequests.h>
|
#include <ripple/app/paths/PathRequests.h>
|
||||||
#include <ripple/app/tx/apply.h>
|
#include <ripple/app/tx/apply.h>
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
|
#include <ripple/basics/MathUtilities.h>
|
||||||
#include <ripple/basics/TaggedCache.h>
|
#include <ripple/basics/TaggedCache.h>
|
||||||
#include <ripple/basics/UptimeClock.h>
|
#include <ripple/basics/UptimeClock.h>
|
||||||
#include <ripple/basics/contract.h>
|
#include <ripple/basics/contract.h>
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
#include <ripple/nodestore/DatabaseShard.h>
|
#include <ripple/nodestore/DatabaseShard.h>
|
||||||
#include <ripple/overlay/Overlay.h>
|
#include <ripple/overlay/Overlay.h>
|
||||||
#include <ripple/overlay/Peer.h>
|
#include <ripple/overlay/Peer.h>
|
||||||
|
#include <ripple/protocol/BuildInfo.h>
|
||||||
#include <ripple/protocol/HashPrefix.h>
|
#include <ripple/protocol/HashPrefix.h>
|
||||||
#include <ripple/protocol/digest.h>
|
#include <ripple/protocol/digest.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
@@ -1049,6 +1051,78 @@ LedgerMaster::checkAccept(std::shared_ptr<Ledger const> const& ledger)
|
|||||||
app_.getFeeTrack().setRemoteFee(fee);
|
app_.getFeeTrack().setRemoteFee(fee);
|
||||||
|
|
||||||
tryAdvance();
|
tryAdvance();
|
||||||
|
|
||||||
|
if (ledger->seq() % 256 == 0)
|
||||||
|
{
|
||||||
|
// Check if the majority of validators run a higher version rippled
|
||||||
|
// software. If so print a warning.
|
||||||
|
//
|
||||||
|
// Once the HardenedValidations amendment is enabled, validators include
|
||||||
|
// their rippled software version in the validation messages of every
|
||||||
|
// (flag - 1) ledger. We wait for one ledger time before checking the
|
||||||
|
// version information to accumulate more validation messages.
|
||||||
|
|
||||||
|
auto currentTime = app_.timeKeeper().now();
|
||||||
|
bool needPrint = false;
|
||||||
|
|
||||||
|
// The variable upgradeWarningPrevTime_ will be set when and only when
|
||||||
|
// the warning is printed.
|
||||||
|
if (upgradeWarningPrevTime_ == TimeKeeper::time_point())
|
||||||
|
{
|
||||||
|
// Have not printed the warning before, check if need to print.
|
||||||
|
auto const vals = app_.getValidations().getTrustedForLedger(
|
||||||
|
ledger->info().parentHash);
|
||||||
|
std::size_t higherVersionCount = 0;
|
||||||
|
std::size_t rippledCount = 0;
|
||||||
|
for (auto const& v : vals)
|
||||||
|
{
|
||||||
|
if (v->isFieldPresent(sfServerVersion))
|
||||||
|
{
|
||||||
|
auto version = v->getFieldU64(sfServerVersion);
|
||||||
|
higherVersionCount +=
|
||||||
|
BuildInfo::isNewerVersion(version) ? 1 : 0;
|
||||||
|
rippledCount +=
|
||||||
|
BuildInfo::isRippledVersion(version) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We report only if (1) we have accumulated validation messages
|
||||||
|
// from 90% validators from the UNL, (2) 60% of validators
|
||||||
|
// running the rippled implementation have higher version numbers,
|
||||||
|
// and (3) the calculation won't cause divide-by-zero.
|
||||||
|
if (higherVersionCount > 0 && rippledCount > 0)
|
||||||
|
{
|
||||||
|
constexpr std::size_t reportingPercent = 90;
|
||||||
|
constexpr std::size_t cutoffPercent = 60;
|
||||||
|
auto const unlSize{
|
||||||
|
app_.validators().getQuorumKeys().second.size()};
|
||||||
|
needPrint = unlSize > 0 &&
|
||||||
|
calculatePercent(vals.size(), unlSize) >=
|
||||||
|
reportingPercent &&
|
||||||
|
calculatePercent(higherVersionCount, rippledCount) >=
|
||||||
|
cutoffPercent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// To throttle the warning messages, instead of printing a warning
|
||||||
|
// every flag ledger, we print every week.
|
||||||
|
else if (currentTime - upgradeWarningPrevTime_ >= weeks{1})
|
||||||
|
{
|
||||||
|
// Printed the warning before, and assuming most validators
|
||||||
|
// do not downgrade, we keep printing the warning
|
||||||
|
// until the local server is restarted.
|
||||||
|
needPrint = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needPrint)
|
||||||
|
{
|
||||||
|
upgradeWarningPrevTime_ = currentTime;
|
||||||
|
auto const upgradeMsg =
|
||||||
|
"Check for upgrade: "
|
||||||
|
"A majority of trusted validators are "
|
||||||
|
"running a newer version.";
|
||||||
|
std::cerr << upgradeMsg << std::endl;
|
||||||
|
JLOG(m_journal.error()) << upgradeMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Report that the consensus process built a particular ledger */
|
/** Report that the consensus process built a particular ledger */
|
||||||
|
|||||||
68
src/ripple/basics/MathUtilities.h
Normal file
68
src/ripple/basics/MathUtilities.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2020 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_MATHUTILITIES_H_INCLUDED
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** Calculate one number divided by another number in percentage.
|
||||||
|
* The result is rounded up to the next integer, and capped in the range [0,100]
|
||||||
|
* E.g. calculatePercent(1, 100) = 1 because 1/100 = 0.010000
|
||||||
|
* calculatePercent(1, 99) = 2 because 1/99 = 0.010101
|
||||||
|
* calculatePercent(0, 100) = 0
|
||||||
|
* calculatePercent(100, 100) = 100
|
||||||
|
* calculatePercent(200, 100) = 100 because the result is capped to 100
|
||||||
|
*
|
||||||
|
* @param count dividend
|
||||||
|
* @param total divisor
|
||||||
|
* @return the percentage, in [0, 100]
|
||||||
|
*
|
||||||
|
* @note total cannot be zero.
|
||||||
|
* */
|
||||||
|
constexpr std::size_t
|
||||||
|
calculatePercent(std::size_t count, std::size_t total)
|
||||||
|
{
|
||||||
|
assert(total != 0);
|
||||||
|
return ((std::min(count, total) * 100) + total - 1) / total;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unit tests
|
||||||
|
static_assert(calculatePercent(1, 2) == 50);
|
||||||
|
static_assert(calculatePercent(0, 100) == 0);
|
||||||
|
static_assert(calculatePercent(100, 100) == 100);
|
||||||
|
static_assert(calculatePercent(200, 100) == 100);
|
||||||
|
static_assert(calculatePercent(1, 100) == 1);
|
||||||
|
static_assert(calculatePercent(1, 99) == 2);
|
||||||
|
static_assert(calculatePercent(6, 14) == 43);
|
||||||
|
static_assert(calculatePercent(29, 33) == 88);
|
||||||
|
static_assert(calculatePercent(1, 64) == 2);
|
||||||
|
static_assert(calculatePercent(0, 100'000'000) == 0);
|
||||||
|
static_assert(calculatePercent(1, 100'000'000) == 1);
|
||||||
|
static_assert(calculatePercent(50'000'000, 100'000'000) == 50);
|
||||||
|
static_assert(calculatePercent(50'000'001, 100'000'000) == 51);
|
||||||
|
static_assert(calculatePercent(99'999'999, 100'000'000) == 100);
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -43,7 +43,7 @@ getVersionString();
|
|||||||
std::string const&
|
std::string const&
|
||||||
getFullVersionString();
|
getFullVersionString();
|
||||||
|
|
||||||
/** Returns the server version packed in a 64-bit integer.
|
/** Encode an arbitrary server software version in a 64-bit integer.
|
||||||
|
|
||||||
The general format is:
|
The general format is:
|
||||||
|
|
||||||
@@ -64,10 +64,38 @@ getFullVersionString();
|
|||||||
10 if an RC
|
10 if an RC
|
||||||
01 if a beta
|
01 if a beta
|
||||||
N: 6-bit rc/beta number (1-63)
|
N: 6-bit rc/beta number (1-63)
|
||||||
|
|
||||||
|
@param the version string
|
||||||
|
@return the encoded version in a 64-bit integer
|
||||||
*/
|
*/
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
|
encodeSoftwareVersion(char const* const versionStr);
|
||||||
|
|
||||||
|
/** Returns this server's version packed in a 64-bit integer. */
|
||||||
|
std::uint64_t
|
||||||
getEncodedVersion();
|
getEncodedVersion();
|
||||||
|
|
||||||
|
/** Check if the encoded software version is a rippled software version.
|
||||||
|
|
||||||
|
@param version another node's encoded software version
|
||||||
|
@return true if the version is a rippled software version, false otherwise
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isRippledVersion(std::uint64_t version);
|
||||||
|
|
||||||
|
/** Check if the version is newer than the local node's rippled software
|
||||||
|
version.
|
||||||
|
|
||||||
|
@param version another node's encoded software version
|
||||||
|
@return true if the version is newer than the local node's rippled software
|
||||||
|
version, false otherwise.
|
||||||
|
|
||||||
|
@note This function only understands version numbers that are generated by
|
||||||
|
rippled. Please see the encodeSoftwareVersion() function for detail.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isNewerVersion(std::uint64_t version);
|
||||||
|
|
||||||
} // namespace BuildInfo
|
} // namespace BuildInfo
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -77,77 +77,98 @@ getFullVersionString()
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr std::uint64_t implementationVersionIdentifier =
|
||||||
|
0x183B'0000'0000'0000LLU;
|
||||||
|
static constexpr std::uint64_t implementationVersionIdentifierMask =
|
||||||
|
0xFFFF'0000'0000'0000LLU;
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
getEncodedVersion()
|
encodeSoftwareVersion(char const* const versionStr)
|
||||||
{
|
{
|
||||||
static std::uint64_t const cookie = []() {
|
std::uint64_t c = implementationVersionIdentifier;
|
||||||
std::uint64_t c = 0x183B000000000000;
|
|
||||||
|
|
||||||
beast::SemanticVersion v;
|
beast::SemanticVersion v;
|
||||||
|
|
||||||
if (v.parse(versionString))
|
if (v.parse(std::string(versionStr)))
|
||||||
|
{
|
||||||
|
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())
|
||||||
{
|
{
|
||||||
if (v.majorVersion >= 0 && v.majorVersion <= 255)
|
std::uint8_t x = 0;
|
||||||
c |= static_cast<std::uint64_t>(v.majorVersion) << 40;
|
|
||||||
|
|
||||||
if (v.minorVersion >= 0 && v.minorVersion <= 255)
|
for (auto id : v.preReleaseIdentifiers)
|
||||||
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;
|
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;
|
||||||
|
|
||||||
for (auto id : v.preReleaseIdentifiers)
|
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)
|
||||||
{
|
{
|
||||||
auto parsePreRelease =
|
c |= static_cast<std::uint64_t>(x) << 16;
|
||||||
[](std::string_view identifier,
|
break;
|
||||||
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 c;
|
||||||
}();
|
}
|
||||||
|
|
||||||
|
std::uint64_t
|
||||||
|
getEncodedVersion()
|
||||||
|
{
|
||||||
|
static std::uint64_t const cookie = {encodeSoftwareVersion(versionString)};
|
||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isRippledVersion(std::uint64_t version)
|
||||||
|
{
|
||||||
|
return (version & implementationVersionIdentifierMask) ==
|
||||||
|
implementationVersionIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isNewerVersion(std::uint64_t version)
|
||||||
|
{
|
||||||
|
if (isRippledVersion(version))
|
||||||
|
return version > getEncodedVersion();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace BuildInfo
|
} // namespace BuildInfo
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
118
src/test/protocol/BuildInfo_test.cpp
Normal file
118
src/test/protocol/BuildInfo_test.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2020 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/beast/unit_test.h>
|
||||||
|
#include <ripple/protocol/BuildInfo.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
class BuildInfo_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
testEncodeSoftwareVersion()
|
||||||
|
{
|
||||||
|
testcase("EncodeSoftwareVersion");
|
||||||
|
|
||||||
|
auto encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b7");
|
||||||
|
|
||||||
|
// the first two bytes identify the particular implementation, 0x183B
|
||||||
|
BEAST_EXPECT(
|
||||||
|
(encodedVersion & 0xFFFF'0000'0000'0000LLU) ==
|
||||||
|
0x183B'0000'0000'0000LLU);
|
||||||
|
|
||||||
|
// the next three bytes: major version, minor version, patch version,
|
||||||
|
// 0x010203
|
||||||
|
BEAST_EXPECT(
|
||||||
|
(encodedVersion & 0x0000'FFFF'FF00'0000LLU) ==
|
||||||
|
0x0000'0102'0300'0000LLU);
|
||||||
|
|
||||||
|
// the next two bits:
|
||||||
|
{
|
||||||
|
// 01 if a beta
|
||||||
|
BEAST_EXPECT(
|
||||||
|
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b01);
|
||||||
|
// 10 if an RC
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.4-rc7");
|
||||||
|
BEAST_EXPECT(
|
||||||
|
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b10);
|
||||||
|
// 11 if neither an RC nor a beta
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.5");
|
||||||
|
BEAST_EXPECT(
|
||||||
|
(encodedVersion & 0x0000'0000'00C0'0000LLU) >> 22 == 0b11);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the next six bits: rc/beta number (1-63)
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6-b63");
|
||||||
|
BEAST_EXPECT((encodedVersion & 0x0000'0000'003F'0000LLU) >> 16 == 63);
|
||||||
|
|
||||||
|
// the last two bytes are zeros
|
||||||
|
BEAST_EXPECT((encodedVersion & 0x0000'0000'0000'FFFFLLU) == 0);
|
||||||
|
|
||||||
|
// Test some version strings with wrong formats:
|
||||||
|
// no rc/beta number
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b");
|
||||||
|
BEAST_EXPECT((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
||||||
|
// rc/beta number out of range
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.3-b64");
|
||||||
|
BEAST_EXPECT((encodedVersion & 0x0000'0000'00FF'0000LLU) == 0);
|
||||||
|
|
||||||
|
// Check that the rc/beta number of a release is 0:
|
||||||
|
encodedVersion = BuildInfo::encodeSoftwareVersion("1.2.6");
|
||||||
|
BEAST_EXPECT((encodedVersion & 0x0000'0000'003F'0000LLU) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testIsRippledVersion()
|
||||||
|
{
|
||||||
|
testcase("IsRippledVersion");
|
||||||
|
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
||||||
|
BEAST_EXPECT(!BuildInfo::isRippledVersion(vFF));
|
||||||
|
auto vRippled = 0x183B'0000'0000'0000LLU;
|
||||||
|
BEAST_EXPECT(BuildInfo::isRippledVersion(vRippled));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testIsNewerVersion()
|
||||||
|
{
|
||||||
|
testcase("IsNewerVersion");
|
||||||
|
auto vFF = 0xFFFF'FFFF'FFFF'FFFFLLU;
|
||||||
|
BEAST_EXPECT(!BuildInfo::isNewerVersion(vFF));
|
||||||
|
|
||||||
|
auto v159 = BuildInfo::encodeSoftwareVersion("1.5.9");
|
||||||
|
BEAST_EXPECT(!BuildInfo::isNewerVersion(v159));
|
||||||
|
|
||||||
|
auto vCurrent = BuildInfo::getEncodedVersion();
|
||||||
|
BEAST_EXPECT(!BuildInfo::isNewerVersion(vCurrent));
|
||||||
|
|
||||||
|
auto vMax = BuildInfo::encodeSoftwareVersion("255.255.255");
|
||||||
|
BEAST_EXPECT(BuildInfo::isNewerVersion(vMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
testEncodeSoftwareVersion();
|
||||||
|
testIsRippledVersion();
|
||||||
|
testIsNewerVersion();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(BuildInfo, protocol, ripple);
|
||||||
|
} // namespace ripple
|
||||||
Reference in New Issue
Block a user