diff --git a/.clang-tidy b/.clang-tidy index 5971b5dd14..26c7995631 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -24,6 +24,7 @@ Checks: "-*, bugprone-misplaced-operator-in-strlen-in-alloc, bugprone-misplaced-pointer-arithmetic-in-alloc, bugprone-misplaced-widening-cast, + bugprone-move-forwarding-reference, bugprone-multi-level-implicit-pointer-conversion, bugprone-multiple-new-in-one-expression, bugprone-multiple-statement-macro, @@ -32,10 +33,12 @@ Checks: "-*, bugprone-parent-virtual-call, bugprone-posix-return, bugprone-redundant-branch-condition, + bugprone-return-const-ref-from-parameter, bugprone-shared-ptr-array-mismatch, bugprone-signal-handler, bugprone-signed-char-misuse, bugprone-sizeof-container, + bugprone-sizeof-expression, bugprone-spuriously-wake-up-functions, bugprone-standalone-empty, bugprone-string-constructor, @@ -82,16 +85,14 @@ Checks: "-*, performance-trivially-destructible " # --- -# checks that have some issues that need to be resolved: +# more checks that have some issues that need to be resolved: # # bugprone-crtp-constructor-accessibility, # bugprone-inc-dec-in-conditions, # bugprone-reserved-identifier, # bugprone-move-forwarding-reference, # bugprone-unused-local-non-trivial-variable, -# bugprone-return-const-ref-from-parameter, # bugprone-switch-missing-default-case, -# bugprone-sizeof-expression, # bugprone-suspicious-stringview-data-usage, # bugprone-suspicious-missing-comma, # bugprone-pointer-arithmetic-on-polymorphic-object, diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index acde57fd91..c4fc2e65ee 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -49,6 +49,11 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Prepare runner + uses: XRPLF/actions/prepare-runner@2cbf481018d930656e9276fcc20dc0e3a0be5b6d + with: + enable_ccache: false + - name: Get number of processors uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf id: nproc diff --git a/CMakeLists.txt b/CMakeLists.txt index 764e917498..f0d8519327 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,26 +36,6 @@ endif () # Enable ccache to speed up builds. include(Ccache) -# make GIT_COMMIT_HASH define available to all sources -find_package(Git) -if (Git_FOUND) - execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse - HEAD OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch) - if (gch) - set(GIT_COMMIT_HASH "${gch}") - message(STATUS gch: ${GIT_COMMIT_HASH}) - add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") - endif () - - execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse - --abbrev-ref HEAD OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb) - if (gb) - set(GIT_BRANCH "${gb}") - message(STATUS gb: ${GIT_BRANCH}) - add_definitions(-DGIT_BRANCH="${GIT_BRANCH}") - endif () -endif () # git - if (thread_safety_analysis) add_compile_options(-Wthread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -DXRPL_ENABLE_THREAD_SAFETY_ANNOTATIONS) diff --git a/cmake/GitInfo.cmake b/cmake/GitInfo.cmake new file mode 100644 index 0000000000..1281182977 --- /dev/null +++ b/cmake/GitInfo.cmake @@ -0,0 +1,21 @@ +include_guard() + +set(GIT_BUILD_BRANCH "") +set(GIT_COMMIT_HASH "") + +find_package(Git) +if (NOT Git_FOUND) + message(WARNING "Git not found. Git branch and commit hash will be empty.") + return() +endif () + +set(GIT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/.git) + +execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${GIT_DIRECTORY} rev-parse --abbrev-ref HEAD + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GIT_BUILD_BRANCH) + +execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${GIT_DIRECTORY} rev-parse HEAD + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GIT_COMMIT_HASH) + +message(STATUS "Git branch: ${GIT_BUILD_BRANCH}") +message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}") diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index e54dd09953..cd44f29df9 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -58,6 +58,12 @@ include(target_link_modules) add_module(xrpl beast) target_link_libraries(xrpl.libxrpl.beast PUBLIC xrpl.imports.main) +include(GitInfo) +add_module(xrpl git) +target_compile_definitions(xrpl.libxrpl.git PRIVATE GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" + GIT_BUILD_BRANCH="${GIT_BUILD_BRANCH}") +target_link_libraries(xrpl.libxrpl.git PUBLIC xrpl.imports.main) + # Level 02 add_module(xrpl basics) target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast) @@ -71,7 +77,8 @@ target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics) # Level 04 add_module(xrpl protocol) -target_link_libraries(xrpl.libxrpl.protocol PUBLIC xrpl.libxrpl.crypto xrpl.libxrpl.json) +target_link_libraries(xrpl.libxrpl.protocol PUBLIC xrpl.libxrpl.crypto xrpl.libxrpl.git + xrpl.libxrpl.json) # Level 05 add_module(xrpl core) @@ -135,6 +142,7 @@ target_link_modules( conditions core crypto + git json ledger net diff --git a/cmake/XrplInstall.cmake b/cmake/XrplInstall.cmake index 4cbf381f87..666fc0712f 100644 --- a/cmake/XrplInstall.cmake +++ b/cmake/XrplInstall.cmake @@ -23,6 +23,7 @@ install(TARGETS common xrpl.libxrpl.conditions xrpl.libxrpl.core xrpl.libxrpl.crypto + xrpl.libxrpl.git xrpl.libxrpl.json xrpl.libxrpl.rdb xrpl.libxrpl.ledger diff --git a/include/xrpl/beast/core/SemanticVersion.h b/include/xrpl/beast/core/SemanticVersion.h index 1d3525de25..f839ef8c53 100644 --- a/include/xrpl/beast/core/SemanticVersion.h +++ b/include/xrpl/beast/core/SemanticVersion.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace beast { @@ -26,14 +27,14 @@ public: SemanticVersion(); - SemanticVersion(std::string const& version); + SemanticVersion(std::string_view version); /** Parse a semantic version string. The parsing is as strict as possible. @return `true` if the string was parsed. */ bool - parse(std::string const& input); + parse(std::string_view input); /** Produce a string from semantic version components. */ std::string diff --git a/include/xrpl/git/Git.h b/include/xrpl/git/Git.h new file mode 100644 index 0000000000..001c09aea7 --- /dev/null +++ b/include/xrpl/git/Git.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace xrpl::git { + +std::string const& +getCommitHash(); + +std::string const& +getBuildBranch(); + +} // namespace xrpl::git diff --git a/include/xrpl/protocol/BuildInfo.h b/include/xrpl/protocol/BuildInfo.h index 3c42a4323f..cc7633cfe1 100644 --- a/include/xrpl/protocol/BuildInfo.h +++ b/include/xrpl/protocol/BuildInfo.h @@ -49,7 +49,7 @@ getFullVersionString(); @return the encoded version in a 64-bit integer */ std::uint64_t -encodeSoftwareVersion(char const* const versionStr); +encodeSoftwareVersion(std::string_view versionStr); /** Returns this server's version packed in a 64-bit integer. */ std::uint64_t diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index b18043d5f0..06cd622722 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -138,14 +138,14 @@ SemanticVersion::SemanticVersion() : majorVersion(0), minorVersion(0), patchVers { } -SemanticVersion::SemanticVersion(std::string const& version) : SemanticVersion() +SemanticVersion::SemanticVersion(std::string_view version) : SemanticVersion() { if (!parse(version)) throw std::invalid_argument("invalid version string"); } bool -SemanticVersion::parse(std::string const& input) +SemanticVersion::parse(std::string_view input) { // May not have leading or trailing whitespace auto left_iter = std::find_if_not(input.begin(), input.end(), [](std::string::value_type c) { diff --git a/src/libxrpl/git/Git.cpp b/src/libxrpl/git/Git.cpp new file mode 100644 index 0000000000..2992852632 --- /dev/null +++ b/src/libxrpl/git/Git.cpp @@ -0,0 +1,31 @@ +#include "xrpl/git/Git.h" + +#include + +#ifndef GIT_COMMIT_HASH +#error "GIT_COMMIT_HASH must be defined" +#endif +#ifndef GIT_BUILD_BRANCH +#error "GIT_BUILD_BRANCH must be defined" +#endif + +namespace xrpl::git { + +static constexpr char kGIT_COMMIT_HASH[] = GIT_COMMIT_HASH; +static constexpr char kGIT_BUILD_BRANCH[] = GIT_BUILD_BRANCH; + +std::string const& +getCommitHash() +{ + static std::string const kVALUE = kGIT_COMMIT_HASH; + return kVALUE; +} + +std::string const& +getBuildBranch() +{ + static std::string const kVALUE = kGIT_BUILD_BRANCH; + return kVALUE; +} + +} // namespace xrpl::git diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 32b3431798..c7531f8376 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -14,44 +15,60 @@ namespace xrpl { namespace BuildInfo { +namespace { + //-------------------------------------------------------------------------- // The build version number. You must edit this for each release // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off char const* const versionString = "3.2.0-b0" -// clang-format on - -#if defined(DEBUG) || defined(SANITIZERS) - "+" -#ifdef GIT_COMMIT_HASH - GIT_COMMIT_HASH - "." -#endif -#ifdef DEBUG - "DEBUG" -#ifdef SANITIZERS - "." -#endif -#endif - -#ifdef SANITIZERS - BOOST_PP_STRINGIZE(SANITIZERS) // cspell: disable-line -#endif -#endif - - //-------------------------------------------------------------------------- + // clang-format on ; // // Don't touch anything below this line // +std::string +buildVersionString() +{ + std::string version = versionString; + +#if defined(DEBUG) || defined(SANITIZERS) + std::string metadata; + + std::string const& commitHash = xrpl::git::getCommitHash(); + if (!commitHash.empty()) + metadata += commitHash + "."; + +#ifdef DEBUG + metadata += "DEBUG"; +#endif + +#if defined(DEBUG) && defined(SANITIZERS) + metadata += "."; +#endif + +#ifdef SANITIZERS + metadata += BOOST_PP_STRINGIZE(SANITIZERS); // cspell: disable-line +#endif + + if (!metadata.empty()) + version += "+" + metadata; +#endif + + return version; +} + +} // namespace + std::string const& getVersionString() { static std::string const value = [] { - std::string const s = versionString; + std::string const s = buildVersionString(); + beast::SemanticVersion v; if (!v.parse(s) || v.print() != s) LogicError(s + ": Bad server version string"); @@ -71,13 +88,13 @@ static constexpr std::uint64_t implementationVersionIdentifier = 0x183B'0000'000 static constexpr std::uint64_t implementationVersionIdentifierMask = 0xFFFF'0000'0000'0000LLU; std::uint64_t -encodeSoftwareVersion(char const* const versionStr) +encodeSoftwareVersion(std::string_view versionStr) { std::uint64_t c = implementationVersionIdentifier; beast::SemanticVersion v; - if (v.parse(std::string(versionStr))) + if (v.parse(versionStr)) { if (v.majorVersion >= 0 && v.majorVersion <= 255) c |= static_cast(v.majorVersion) << 40; @@ -137,7 +154,7 @@ encodeSoftwareVersion(char const* const versionStr) std::uint64_t getEncodedVersion() { - static std::uint64_t const cookie = {encodeSoftwareVersion(versionString)}; + static std::uint64_t const cookie = {encodeSoftwareVersion(getVersionString())}; return cookie; } diff --git a/src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainDelete.cpp b/src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainDelete.cpp index e013bd8d2b..861bb934be 100644 --- a/src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainDelete.cpp +++ b/src/libxrpl/tx/transactors/PermissionedDomain/PermissionedDomainDelete.cpp @@ -18,7 +18,7 @@ TER PermissionedDomainDelete::preclaim(PreclaimContext const& ctx) { auto const domain = ctx.tx.getFieldH256(sfDomainID); - auto const sleDomain = ctx.view.read({ltPERMISSIONED_DOMAIN, domain}); + auto const sleDomain = ctx.view.read(keylet::permissionedDomain(domain)); if (!sleDomain) return tecNO_ENTRY; @@ -40,7 +40,7 @@ PermissionedDomainDelete::doApply() ctx_.tx.isFieldPresent(sfDomainID), "xrpl::PermissionedDomainDelete::doApply : required field present"); - auto const slePd = view().peek({ltPERMISSIONED_DOMAIN, ctx_.tx.at(sfDomainID)}); + auto const slePd = view().peek(keylet::permissionedDomain(ctx_.tx.at(sfDomainID))); auto const page = (*slePd)[sfOwnerNode]; if (!view().dirRemove(keylet::ownerDir(account_), page, slePd->key(), true)) diff --git a/src/test/beast/aged_associative_container_test.cpp b/src/test/beast/aged_associative_container_test.cpp index 19927c2d35..690f03cd49 100644 --- a/src/test/beast/aged_associative_container_test.cpp +++ b/src/test/beast/aged_associative_container_test.cpp @@ -227,7 +227,7 @@ public: static typename Base::Key const& extract(Value const& value) { - return value; + return value; // NOLINT(bugprone-return-const-ref-from-parameter) } static Values diff --git a/src/test/protocol/MultiApiJson_test.cpp b/src/test/protocol/MultiApiJson_test.cpp index ccf719e349..bbd6ec1a07 100644 --- a/src/test/protocol/MultiApiJson_test.cpp +++ b/src/test/protocol/MultiApiJson_test.cpp @@ -556,7 +556,7 @@ struct MultiApiJson_test : beast::unit_test::suite static_assert([](auto&& v) { return !requires { v.visitor( - std::move(v), // cannot bind rvalue + decltype(v){}, // cannot bind rvalue 1, [](Json::Value&, auto) {}); }; diff --git a/src/test/rpc/GatewayBalances_test.cpp b/src/test/rpc/GatewayBalances_test.cpp index 6415f6a51f..0deb1fc627 100644 --- a/src/test/rpc/GatewayBalances_test.cpp +++ b/src/test/rpc/GatewayBalances_test.cpp @@ -223,6 +223,45 @@ public: expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText()); } + void + testGWBWithMPT() + { + testcase("Gateway Balances with MPT Escrow"); + using namespace std::chrono_literals; + using namespace jtx; + + // Ensure MPT is enabled + FeatureBitset features = testable_amendments() | featureMPTokensV1; + Env env(*this, features); + + Account const alice{"alice"}; + Account const bob{"bob"}; + + env.fund(XRP(10000), alice, bob); + env.close(); + + // Create MPT issuance (Alice) with Escrow capability + MPTTester mpt(env, alice, {.holders = {bob}, .fund = false}); + mpt.create({.flags = tfMPTCanEscrow}); + + // Authorize Bob and fund him + mpt.authorize({.account = bob, .holderCount = 1}); + mpt.pay(alice, bob, 1000); + + // Bob creates an escrow of MPT to Alice. + auto const MPT = mpt["MPT"]; + env(escrow::create(bob, alice, MPT(100)), escrow::finish_time(env.now() + 10s)); + env.close(); + + // Query gateway_balances for Bob. + auto wsc = makeWSClient(env.app().config()); + Json::Value qry; + qry[jss::account] = bob.human(); + + auto jv = wsc->invoke("gateway_balances", qry); + expect(jv[jss::status] == "success"); + } + void run() override { @@ -233,7 +272,7 @@ public: testGWB(feature); testGWBApiVersions(feature); } - + testGWBWithMPT(); testGWBOverflow(); } }; diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 83bdb51ec1..32d246f493 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -476,12 +477,8 @@ run(int argc, char** argv) if (vm.count("version")) { std::cout << "rippled version " << BuildInfo::getVersionString() << std::endl; -#ifdef GIT_COMMIT_HASH - std::cout << "Git commit hash: " << GIT_COMMIT_HASH << std::endl; -#endif -#ifdef GIT_BRANCH - std::cout << "Git build branch: " << GIT_BRANCH << std::endl; -#endif + std::cout << "Git commit hash: " << xrpl::git::getCommitHash() << std::endl; + std::cout << "Git build branch: " << xrpl::git::getBuildBranch() << std::endl; return 0; } diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 8178611c61..b8663a76fb 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -2593,17 +2594,14 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) } } -#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH) + if (!xrpl::git::getCommitHash().empty() || !xrpl::git::getBuildBranch().empty()) { auto& x = (info[jss::git] = Json::objectValue); -#ifdef GIT_COMMIT_HASH - x[jss::hash] = GIT_COMMIT_HASH; -#endif -#ifdef GIT_BRANCH - x[jss::branch] = GIT_BRANCH; -#endif + if (!xrpl::git::getCommitHash().empty()) + x[jss::hash] = xrpl::git::getCommitHash(); + if (!xrpl::git::getBuildBranch().empty()) + x[jss::branch] = xrpl::git::getBuildBranch(); } -#endif } info[jss::io_latency_ms] = static_cast(registry_.app().getIOLatency().count()); diff --git a/src/xrpld/rpc/handlers/GatewayBalances.cpp b/src/xrpld/rpc/handlers/GatewayBalances.cpp index e5e95d6835..a2176ab388 100644 --- a/src/xrpld/rpc/handlers/GatewayBalances.cpp +++ b/src/xrpld/rpc/handlers/GatewayBalances.cpp @@ -131,6 +131,10 @@ doGatewayBalances(RPC::JsonContext& context) if (sle->getType() == ltESCROW) { auto const& escrow = sle->getFieldAmount(sfAmount); + // Gateway Balance should not include MPTs + if (escrow.holds()) + return; + auto& bal = locked[escrow.getCurrency()]; if (bal == beast::zero) {