From d34aa37b3c9e7d2a3e71c15a009680fa7279c284 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 14 Aug 2026 13:49:08 +0000 Subject: [PATCH] refactor: Use std::format instead of boost::format where it fits (#7996) Co-authored-by: Timur Yalymov <36795566+tyalymov@users.noreply.github.com> Co-authored-by: Cursor Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com> Co-authored-by: Ayaz Salikhov --- include/xrpl/basics/StringUtilities.h | 1 - include/xrpl/net/HTTPClientSSLContext.h | 8 +- include/xrpl/rdb/DBInit.h | 29 +++- include/xrpl/server/Wallet.h | 4 + src/libxrpl/protocol/STLedgerEntry.cpp | 5 +- src/libxrpl/protocol/STTx.cpp | 17 +- src/libxrpl/protocol/STXChainBridge.cpp | 16 +- src/libxrpl/server/Vacuum.cpp | 4 +- src/libxrpl/server/Wallet.cpp | 11 +- src/test/app/AMMCalc_test.cpp | 4 +- src/test/core/Config_test.cpp | 63 ++++--- src/test/rpc/ServerInfo_test.cpp | 16 +- src/tests/libxrpl/protocol/STXChainBridge.cpp | 60 +++++++ src/xrpld/app/misc/Transaction.h | 4 + src/xrpld/app/misc/detail/WorkSSL.cpp | 4 +- src/xrpld/app/misc/detail/WorkSSL.h | 1 - src/xrpld/app/rdb/backend/detail/Node.cpp | 161 ++++++++++-------- src/xrpld/core/detail/Config.cpp | 11 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 9 +- .../rpc/handlers/account/AccountInfo.cpp | 5 +- .../rpc/handlers/orderbook/BookOffers.cpp | 35 ++-- 21 files changed, 286 insertions(+), 182 deletions(-) create mode 100644 src/tests/libxrpl/protocol/STXChainBridge.cpp diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h index d606613c65..e3b91c2f25 100644 --- a/include/xrpl/basics/StringUtilities.h +++ b/include/xrpl/basics/StringUtilities.h @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/include/xrpl/net/HTTPClientSSLContext.h b/include/xrpl/net/HTTPClientSSLContext.h index 51b50a084c..43467faa89 100644 --- a/include/xrpl/net/HTTPClientSSLContext.h +++ b/include/xrpl/net/HTTPClientSSLContext.h @@ -8,11 +8,11 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -38,8 +38,8 @@ public: if (ec && sslVerifyDir.empty()) { - Throw(boost::str( - boost::format("Failed to set_default_verify_paths: %s") % ec.message())); + Throw( + std::format("Failed to set_default_verify_paths: {}", ec.message())); } } else @@ -54,7 +54,7 @@ public: if (ec) { Throw( - boost::str(boost::format("Failed to add verify path: %s") % ec.message())); + std::format("Failed to add verify path: {}", ec.message())); } } } diff --git a/include/xrpl/rdb/DBInit.h b/include/xrpl/rdb/DBInit.h index 10b04905f2..e6e7e87b6b 100644 --- a/include/xrpl/rdb/DBInit.h +++ b/include/xrpl/rdb/DBInit.h @@ -2,6 +2,9 @@ #include #include +#include +#include +#include namespace xrpl { @@ -9,9 +12,29 @@ namespace xrpl { // These pragmas are built at startup and applied to all database // connections, unless otherwise noted. -inline constexpr char const* kCommonDbPragmaJournal{"PRAGMA journal_mode=%s;"}; -inline constexpr char const* kCommonDbPragmaSync{"PRAGMA synchronous=%s;"}; -inline constexpr char const* kCommonDbPragmaTemp{"PRAGMA temp_store=%s;"}; +// +// They are exposed as functions rather than as format-string constants so +// that the un-substituted template can never reach sqlite: an unrecognized +// pragma value is silently ignored, so forgetting to interpolate would +// leave the setting at its default instead of failing loudly. +[[nodiscard]] inline std::string +commonDbPragmaJournal(std::string_view journalMode) +{ + return std::format("PRAGMA journal_mode={};", journalMode); +} + +[[nodiscard]] inline std::string +commonDbPragmaSync(std::string_view synchronous) +{ + return std::format("PRAGMA synchronous={};", synchronous); +} + +[[nodiscard]] inline std::string +commonDbPragmaTemp(std::string_view tempStore) +{ + return std::format("PRAGMA temp_store={};", tempStore); +} + // A warning will be logged if any lower-safety sqlite tuning settings // are used and at least this much ledger history is configured. This // includes full history nodes. This is because such a large amount of diff --git a/include/xrpl/server/Wallet.h b/include/xrpl/server/Wallet.h index ed8378989f..95486cc468 100644 --- a/include/xrpl/server/Wallet.h +++ b/include/xrpl/server/Wallet.h @@ -10,6 +10,10 @@ #include #include +// boost::optional (not std::optional) appears in the declarations below, +// because SOCI's into()/use() bindings only support boost::optional. +#include + #include #include #include diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 8c5c5b5eae..9ee8d030ff 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -18,12 +18,11 @@ #include #include -#include - #include #include #include #include +#include #include #include #include @@ -111,7 +110,7 @@ STLedgerEntry::getSType() const std::string STLedgerEntry::getText() const { - return str(boost::format("{ %s, %s }") % to_string(key_) % STObject::getText()); + return std::format("{{ {}, {} }}", to_string(key_), STObject::getText()); } json::Value diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 7f1e19ea12..ce672b515d 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -33,13 +33,13 @@ #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -399,16 +399,21 @@ STTx::getMetaSQL( TxnSql status, std::string const& escapedMetaData) const { - static boost::format const kBfTrans("('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)"); std::string rTxn = sqlBlobLiteral(rawTxn.peekData()); auto format = TxFormats::getInstance().findByType(txType_); XRPL_ASSERT(format, "xrpl::STTx::getMetaSQL : non-null type format"); - return str( - boost::format(kBfTrans) % to_string(getTransactionID()) % format->getName() % - toBase58(getAccountID(sfAccount)) % getFieldU32(sfSequence) % inLedger % - safeCast(status) % rTxn % escapedMetaData); + return std::format( + "('{}', '{}', '{}', '{}', '{}', '{}', {}, {})", + to_string(getTransactionID()), + format->getName(), + toBase58(getAccountID(sfAccount)), + getFieldU32(sfSequence), + inLedger, + safeCast(status), + rTxn, + escapedMetaData); } static std::expected diff --git a/src/libxrpl/protocol/STXChainBridge.cpp b/src/libxrpl/protocol/STXChainBridge.cpp index 005c9ccbce..f9f1fd1dcc 100644 --- a/src/libxrpl/protocol/STXChainBridge.cpp +++ b/src/libxrpl/protocol/STXChainBridge.cpp @@ -11,9 +11,8 @@ #include #include -#include - #include +#include #include #include #include @@ -141,10 +140,15 @@ STXChainBridge::getJson(JsonOptions jo) const std::string STXChainBridge::getText() const { - return str( - boost::format("{ %s = %s, %s = %s, %s = %s, %s = %s }") % sfLockingChainDoor.getName() % - lockingChainDoor_.getText() % sfLockingChainIssue.getName() % lockingChainIssue_.getText() % - sfIssuingChainDoor.getName() % issuingChainDoor_.getText() % sfIssuingChainIssue.getName() % + return std::format( + "{{ {} = {}, {} = {}, {} = {}, {} = {} }}", + sfLockingChainDoor.getName(), + lockingChainDoor_.getText(), + sfLockingChainIssue.getName(), + lockingChainIssue_.getText(), + sfIssuingChainDoor.getName(), + issuingChainDoor_.getText(), + sfIssuingChainIssue.getName(), issuingChainIssue_.getText()); } diff --git a/src/libxrpl/server/Vacuum.cpp b/src/libxrpl/server/Vacuum.cpp index df768d509a..c952e722b8 100644 --- a/src/libxrpl/server/Vacuum.cpp +++ b/src/libxrpl/server/Vacuum.cpp @@ -5,8 +5,6 @@ #include #include -#include // IWYU pragma: keep - #include #include @@ -40,7 +38,7 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) // Only the most trivial databases will fit in memory on typical // (recommended) hardware. Force temp files to be written to disk // regardless of the config settings. - session << boost::format(kCommonDbPragmaTemp) % "file"; + session << commonDbPragmaTemp("file"); session << "PRAGMA page_size;", soci::into(pageSize); std::cout << "VACUUM beginning. page_size: " << pageSize << std::endl; diff --git a/src/libxrpl/server/Wallet.cpp b/src/libxrpl/server/Wallet.cpp index 42ac80ef3f..56d0db67d4 100644 --- a/src/libxrpl/server/Wallet.cpp +++ b/src/libxrpl/server/Wallet.cpp @@ -16,7 +16,6 @@ #include #include -#include #include // IWYU pragma: keep #include // IWYU pragma: keep @@ -30,6 +29,7 @@ #include #include +#include #include #include #include @@ -172,11 +172,10 @@ getNodeIdentity(soci::session& session) // If a valid identity wasn't found, we randomly generate a new one: auto [newpublicKey, newsecretKey] = randomKeyPair(KeyType::Secp256k1); - session << str( - boost::format( - "INSERT INTO NodeIdentity (PublicKey,PrivateKey) " - "VALUES ('%s','%s');") % - toBase58(TokenType::NodePublic, newpublicKey) % + session << std::format( + "INSERT INTO NodeIdentity (PublicKey,PrivateKey) " + "VALUES ('{}','{}');", + toBase58(TokenType::NodePublic, newpublicKey), toBase58(TokenType::NodePrivate, newsecretKey)); return {newpublicKey, newsecretKey}; diff --git a/src/test/app/AMMCalc_test.cpp b/src/test/app/AMMCalc_test.cpp index 74080e669c..23f251d57a 100644 --- a/src/test/app/AMMCalc_test.cpp +++ b/src/test/app/AMMCalc_test.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -188,8 +189,7 @@ class AMMCalc_test : public beast::unit_test::Suite static std::string toString(STAmount const& a) { - return (boost::format("%s/%s") % a.getText() % ::xrpl::to_string(a.get().currency)) - .str(); + return std::format("{}/{}", a.getText(), ::xrpl::to_string(a.get().currency)); } static STAmount diff --git a/src/test/core/Config_test.cpp b/src/test/core/Config_test.cpp index dec6393010..5ed5ef4049 100644 --- a/src/test/core/Config_test.cpp +++ b/src/test/core/Config_test.cpp @@ -10,8 +10,6 @@ #include // IWYU pragma: keep #include -#include // IWYU pragma: keep -#include #include #include @@ -20,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +35,7 @@ namespace detail { std::string configContents(std::string const& dbPath, std::string const& validatorsFile) { - static boost::format kConfigContentsTemplate(R"xrpldConfig( + static constexpr char const* kConfigContentsTemplate = R"xrpldConfig( [server] port_rpc port_peer @@ -83,9 +82,9 @@ cache_mb=256 file_size_mb=8 file_size_mult=2 -%1% +{} -%2% +{} # This needs to be an absolute directory reference, not a relative one. # Modify this value as required. @@ -106,7 +105,7 @@ r.ripple.com 51235 # Turn down default logging to save disk space in the long run. # Valid values here are trace, debug, info, warning, error, and fatal [rpc_startup] -{ "command": "log_level", "severity": "warning" } +{{ "command": "log_level", "severity": "warning" }} # Defaults to 1 ("yes") so that certificates will be validated. To allow the use # of self-signed certificates for development or internal use, set to 0 ("no"). @@ -115,12 +114,12 @@ r.ripple.com 51235 [sqdb] backend=sqlite -)xrpldConfig"); +)xrpldConfig"; std::string dbPathSection = dbPath.empty() ? "" : "[database_path]\n" + dbPath; std::string valFileSection = validatorsFile.empty() ? "" : "[validators_file]\n" + validatorsFile; - return boost::str(kConfigContentsTemplate % dbPathSection % valFileSection); + return std::format(kConfigContentsTemplate, dbPathSection, valFileSection); } /** @@ -427,7 +426,7 @@ port_wss_admin using namespace std::filesystem; { - boost::format cc("[database_path]\n%1%\n"); + constexpr char const* cc = "[database_path]\n{}\n"; auto const cwd = current_path(); path const dataDirRel("test_data_dir"); @@ -435,13 +434,13 @@ port_wss_admin { // Dummy test - do we get back what we put in Config c; - c.loadFromString(boost::str(cc % dataDirAbs.string())); + c.loadFromString(std::format(cc, dataDirAbs.string())); BEAST_EXPECT(c.legacy(Sections::kDatabasePath) == dataDirAbs.string()); } { // Rel paths should convert to abs paths Config c; - c.loadFromString(boost::str(cc % dataDirRel.string())); + c.loadFromString(std::format(cc, dataDirRel.string())); BEAST_EXPECT(c.legacy(Sections::kDatabasePath) == dataDirAbs.string()); } { @@ -508,20 +507,20 @@ port_wss_admin { Config c; - static boost::format kConfigTemplate(R"xrpldConfig( + static constexpr char const* kConfigTemplate = R"xrpldConfig( [validation_seed] -%1% +{} [validator_token] -%2% -)xrpldConfig"); +{} +)xrpldConfig"; std::string error; auto const expectedError = "Cannot have both [validation_seed] " "and [validator_token] config sections"; try { - c.loadFromString(boost::str(kConfigTemplate % validationSeed % token)); + c.loadFromString(std::format(kConfigTemplate, validationSeed, token)); } catch (std::runtime_error const& e) { @@ -604,7 +603,7 @@ main using namespace std::filesystem; { // load should throw for missing specified validators file - boost::format cc("[validators_file]\n%1%\n"); + constexpr char const* cc = "[validators_file]\n{}\n"; std::string error; std::string const missingPath = "/no/way/this/path/exists"; auto const expectedError = @@ -612,7 +611,7 @@ main try { Config c; - c.loadFromString(boost::str(cc % missingPath)); + c.loadFromString(std::format(cc, missingPath)); } catch (std::runtime_error const& e) { @@ -624,14 +623,14 @@ main // load should throw for invalid [validators_file] detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); path const invalidFile = current_path() / vtg.subdir(); - boost::format cc("[validators_file]\n%1%\n"); + constexpr char const* cc = "[validators_file]\n{}\n"; std::string error; auto const expectedError = "Invalid file specified in [validators_file]: " + invalidFile.string(); try { Config c; - c.loadFromString(boost::str(cc % invalidFile.string())); + c.loadFromString(std::format(cc, invalidFile.string())); } catch (std::runtime_error const& e) { @@ -829,8 +828,8 @@ trust-these-validators.gov detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); Config c; - boost::format cc("[validators_file]\n%1%\n"); - c.loadFromString(boost::str(cc % vtg.validatorsFile())); + constexpr char const* cc = "[validators_file]\n{}\n"; + c.loadFromString(std::format(cc, vtg.validatorsFile())); BEAST_EXPECT(c.legacy(Sections::kValidatorsFile) == vtg.validatorsFile()); BEAST_EXPECT(c.section(Sections::kValidators).values().size() == 8); BEAST_EXPECT(c.section(Sections::kValidatorListSites).values().size() == 2); @@ -909,9 +908,9 @@ trust-these-validators.gov { // load validators from both config and validators file - boost::format cc(R"xrpldConfig( + constexpr char const* cc = R"xrpldConfig( [validators_file] -%1% +{} [validators] n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 @@ -930,11 +929,11 @@ trust-these-validators.gov [validator_list_keys] 021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566 -)xrpldConfig"); +)xrpldConfig"; detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); Config c; - c.loadFromString(boost::str(cc % vtg.validatorsFile())); + c.loadFromString(std::format(cc, vtg.validatorsFile())); BEAST_EXPECT(c.legacy(Sections::kValidatorsFile) == vtg.validatorsFile()); BEAST_EXPECT(c.section(Sections::kValidators).values().size() == 15); BEAST_EXPECT(c.section(Sections::kValidatorListSites).values().size() == 4); @@ -945,13 +944,13 @@ trust-these-validators.gov { // load should throw if [validator_list_threshold] is present both // in xrpld.cfg and validators file - boost::format cc(R"xrpldConfig( + constexpr char const* cc = R"xrpldConfig( [validators_file] -%1% +{} [validator_list_threshold] 1 -)xrpldConfig"); +)xrpldConfig"; std::string error; detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); @@ -961,7 +960,7 @@ trust-these-validators.gov try { Config c; - c.loadFromString(boost::str(cc % vtg.validatorsFile())); + c.loadFromString(std::format(cc, vtg.validatorsFile())); fail(); } catch (std::runtime_error const& e) @@ -975,7 +974,7 @@ trust-these-validators.gov // [validator_list_keys] are missing from xrpld.cfg and // validators file Config const c; - boost::format cc("[validators_file]\n%1%\n"); + constexpr char const* cc = "[validators_file]\n{}\n"; std::string error; detail::ValidatorsTxtGuard const vtg(*this, "test_cfg", "validators.cfg"); BEAST_EXPECT(vtg.validatorsFileExists()); @@ -988,7 +987,7 @@ trust-these-validators.gov try { Config c2; - c2.loadFromString(boost::str(cc % vtg.validatorsFile())); + c2.loadFromString(std::format(cc, vtg.validatorsFile())); } catch (std::runtime_error const& e) { diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index 52a1e6cdb0..100ae0e49b 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -9,8 +9,7 @@ #include #include -#include - +#include #include namespace xrpl::test { @@ -36,12 +35,13 @@ public: makeValidatorConfig() { auto p = std::make_unique(); - boost::format toLoad(R"xrpldConfig( + auto const toLoad = std::format( + R"xrpldConfig( [validator_token] -%1% +{} [validators] -%2% +{} [port_grpc] ip = 0.0.0.0 @@ -52,9 +52,11 @@ ip = 0.0.0.0 port = 50052 protocol = wss2 admin = 127.0.0.1 -)xrpldConfig"); +)xrpldConfig", + validator_data::kToken, + validator_data::kPublicKey); - p->loadFromString(boost::str(toLoad % validator_data::kToken % validator_data::kPublicKey)); + p->loadFromString(toLoad); setupConfigForUnitTests(*p); diff --git a/src/tests/libxrpl/protocol/STXChainBridge.cpp b/src/tests/libxrpl/protocol/STXChainBridge.cpp new file mode 100644 index 0000000000..f4e6e60cc9 --- /dev/null +++ b/src/tests/libxrpl/protocol/STXChainBridge.cpp @@ -0,0 +1,60 @@ +#include + +#include +#include +#include + +#include + +#include +#include + +using namespace xrpl; + +namespace { + +// Built from raw bytes rather than base58 so the test does not depend on +// hand-computed checksums. +AccountID +account(std::string_view hex) +{ + AccountID id; + EXPECT_TRUE(id.parseHex(hex)); + return id; +} + +} // namespace + +// getText() builds its string from eight substitutions of the same type, so a +// transposed pair would still compile and still type check. Pin the output so +// the field/value pairing is actually verified. +TEST(STXChainBridge, getTextPairsEachFieldWithItsValue) +{ + auto const lockingDoor = account("0102030405060708090A0B0C0D0E0F1011121314"); + auto const issuingDoor = account("14131211100F0E0D0C0B0A090807060504030201"); + + auto const lockingIssue = xrpIssue(); + Issue const issuingIssue{toCurrency("USD"), issuingDoor}; + + STXChainBridge const bridge{lockingDoor, lockingIssue, issuingDoor, issuingIssue}; + + std::string const expected = "{ LockingChainDoor = " + toBase58(lockingDoor) + + ", LockingChainIssue = " + lockingIssue.getText() + + ", IssuingChainDoor = " + toBase58(issuingDoor) + + ", IssuingChainIssue = " + issuingIssue.getText() + " }"; + + EXPECT_EQ(bridge.getText(), expected); +} + +TEST(STXChainBridge, getTextOnADefaultBridge) +{ + STXChainBridge const bridge; + auto const text = bridge.getText(); + + // The outer braces are literal, and the four field names appear in + // declaration order regardless of the values. + EXPECT_TRUE(text.starts_with("{ LockingChainDoor = ")); + EXPECT_TRUE(text.ends_with(" }")); + EXPECT_LT(text.find("LockingChainIssue"), text.find("IssuingChainDoor")); + EXPECT_LT(text.find("IssuingChainDoor"), text.find("IssuingChainIssue")); +} diff --git a/src/xrpld/app/misc/Transaction.h b/src/xrpld/app/misc/Transaction.h index b6b6d1a8d5..61951fbb59 100644 --- a/src/xrpld/app/misc/Transaction.h +++ b/src/xrpld/app/misc/Transaction.h @@ -15,6 +15,10 @@ #include #include +// boost::optional (not std::optional) appears in the declarations below, +// because SOCI's into()/use() bindings only support boost::optional. +#include + #include #include #include diff --git a/src/xrpld/app/misc/detail/WorkSSL.cpp b/src/xrpld/app/misc/detail/WorkSSL.cpp index e8d24b55d6..48231b147e 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.cpp +++ b/src/xrpld/app/misc/detail/WorkSSL.cpp @@ -10,8 +10,8 @@ #include #include #include -#include +#include #include #include @@ -38,7 +38,7 @@ WorkSSL::WorkSSL( { auto ec = context_.preConnectVerify(stream_, host_); if (ec) - Throw(boost::str(boost::format("preConnectVerify: %s") % ec.message())); + Throw(std::format("preConnectVerify: {}", ec.message())); } void diff --git a/src/xrpld/app/misc/detail/WorkSSL.h b/src/xrpld/app/misc/detail/WorkSSL.h index d4b3b9ff25..e4b7586054 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.h +++ b/src/xrpld/app/misc/detail/WorkSSL.h @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/src/xrpld/app/rdb/backend/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp index ff57087ec5..be4c5d29e5 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -40,7 +40,6 @@ #include #include -#include #include // IWYU pragma: keep #include @@ -58,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -109,18 +109,16 @@ makeLedgerDBs( // ledger database auto lgr{std::make_unique( setup, kLgrDbName, setup.lgrPragma, kLgrDbInit, checkpointerSetup, j)}; - lgr->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::LgrDbCache))); + lgr->getSession() << std::format( + "PRAGMA cache_size=-{};", kilobytes(config.getValueFor(SizedItem::LgrDbCache))); if (config.useTxTables()) { // transaction database auto tx{std::make_unique( setup, kTxDbName, setup.txPragma, kTxDbInit, checkpointerSetup, j)}; - tx->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::TxnDbCache))); + tx->getSession() << std::format( + "PRAGMA cache_size=-{};", kilobytes(config.getValueFor(SizedItem::TxnDbCache))); if (!setup.standAlone || setup.startUp == StartUpType::Load || setup.startUp == StartUpType::LoadFile || setup.startUp == StartUpType::Replay) @@ -280,15 +278,17 @@ saveValidatedLedger( } { - static boost::format kDeleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;"); - static boost::format kDeleteTranS1("DELETE FROM Transactions WHERE LedgerSeq = %u;"); - static boost::format kDeleteTranS2("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;"); - static boost::format kDeleteAcctTrans( - "DELETE FROM AccountTransactions WHERE TransID = '%s';"); + static constexpr char const* kDeleteLedger = "DELETE FROM Ledgers WHERE LedgerSeq = {};"; + static constexpr char const* kDeleteTranS1 = + "DELETE FROM Transactions WHERE LedgerSeq = {};"; + static constexpr char const* kDeleteTranS2 = + "DELETE FROM AccountTransactions WHERE LedgerSeq = {};"; + static constexpr char const* kDeleteAcctTrans = + "DELETE FROM AccountTransactions WHERE TransID = '{}';"; { auto db = ldgDB.checkoutDb(); - *db << boost::str(kDeleteLedger % seq); + *db << std::format(kDeleteLedger, seq); } if (app.config().useTxTables()) @@ -305,19 +305,19 @@ saveValidatedLedger( soci::transaction tr(*db); - *db << boost::str(kDeleteTranS1 % seq); - *db << boost::str(kDeleteTranS2 % seq); + *db << std::format(kDeleteTranS1, seq); + *db << std::format(kDeleteTranS2, seq); std::string const ledgerSeq(std::to_string(seq)); for (auto const& acceptedLedgerTx : *aLedger) { - uint256 transactionID = acceptedLedgerTx->getTransactionID(); + uint256 const transactionID = acceptedLedgerTx->getTransactionID(); std::string const txnId(to_string(transactionID)); std::string const txnSeq(std::to_string(acceptedLedgerTx->getTxnSeq())); - *db << boost::str(kDeleteAcctTrans % transactionID); + *db << std::format(kDeleteAcctTrans, txnId); auto const& accts = acceptedLedgerTx->getAffected(); @@ -629,11 +629,11 @@ getHashesByIndex(soci::session& session, LedgerIndex minSeq, LedgerIndex maxSeq, std::pair>, int> getTxHistory(soci::session& session, Application& app, LedgerIndex startIndex, int quantity) { - std::string const sql = boost::str( - boost::format( - "SELECT LedgerSeq, Status, RawTxn " - "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") % - startIndex % quantity); + std::string const sql = std::format( + "SELECT LedgerSeq, Status, RawTxn " + "FROM Transactions ORDER BY LedgerSeq DESC LIMIT {},{};", + startIndex, + quantity); std::vector> txs; int total = 0; @@ -730,41 +730,50 @@ transactionsSQL( if (options.ledgerRange.max != 0u) { - maxClause = boost::str( - boost::format("AND AccountTransactions.LedgerSeq <= '%u'") % options.ledgerRange.max); + maxClause = + std::format("AND AccountTransactions.LedgerSeq <= '{}'", options.ledgerRange.max); } if (options.ledgerRange.min != 0u) { - minClause = boost::str( - boost::format("AND AccountTransactions.LedgerSeq >= '%u'") % options.ledgerRange.min); + minClause = + std::format("AND AccountTransactions.LedgerSeq >= '{}'", options.ledgerRange.min); } std::string sql; if (count) { - sql = boost::str( - boost::format( - "SELECT %s FROM AccountTransactions " - "WHERE Account = '%s' %s %s LIMIT %u, %u;") % - selection % toBase58(options.account) % maxClause % minClause % options.offset % + sql = std::format( + "SELECT {} FROM AccountTransactions " + "WHERE Account = '{}' {} {} LIMIT {}, {};", + selection, + toBase58(options.account), + maxClause, + minClause, + options.offset, numberOfResults); } else { - sql = boost::str( - boost::format( - "SELECT %s FROM " - "AccountTransactions INNER JOIN Transactions " - "ON Transactions.TransID = AccountTransactions.TransID " - "WHERE Account = '%s' %s %s " - "ORDER BY AccountTransactions.LedgerSeq %s, " - "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s " - "LIMIT %u, %u;") % - selection % toBase58(options.account) % maxClause % minClause % - (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") % - (descending ? "DESC" : "ASC") % options.offset % numberOfResults); + char const* const order = descending ? "DESC" : "ASC"; + sql = std::format( + "SELECT {} FROM " + "AccountTransactions INNER JOIN Transactions " + "ON Transactions.TransID = AccountTransactions.TransID " + "WHERE Account = '{}' {} {} " + "ORDER BY AccountTransactions.LedgerSeq {}, " + "AccountTransactions.TxnSeq {}, AccountTransactions.TransID {} " + "LIMIT {}, {};", + selection, + toBase58(options.account), + maxClause, + minClause, + order, + order, + order, + options.offset, + numberOfResults); } JLOG(j.trace()) << "txSQL query: " << sql; return sql; @@ -1105,14 +1114,6 @@ accountTxPage( std::optional newmarker; - static std::string const kPrefix( - R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq, - Status,RawTxn,TxnMeta - FROM AccountTransactions INNER JOIN Transactions - ON Transactions.TransID = AccountTransactions.TransID - AND AccountTransactions.Account = '%s' WHERE - )"); - std::string sql; // SQL's BETWEEN uses a closed interval ([a,b]) @@ -1121,13 +1122,22 @@ accountTxPage( if (findLedger == 0) { - sql = boost::str( - boost::format(kPrefix + R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u - ORDER BY AccountTransactions.LedgerSeq %s, - AccountTransactions.TxnSeq %s - LIMIT %u;)") % - toBase58(options.account) % options.ledgerRange.min % options.ledgerRange.max % order % - order % queryLimit); + sql = std::format( + R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq, + Status,RawTxn,TxnMeta + FROM AccountTransactions INNER JOIN Transactions + ON Transactions.TransID = AccountTransactions.TransID + AND AccountTransactions.Account = '{}' WHERE + AccountTransactions.LedgerSeq BETWEEN {} AND {} + ORDER BY AccountTransactions.LedgerSeq {}, + AccountTransactions.TxnSeq {} + LIMIT {};)", + toBase58(options.account), + options.ledgerRange.min, + options.ledgerRange.max, + order, + order, + queryLimit); } else { @@ -1136,27 +1146,34 @@ accountTxPage( std::uint32_t const maxLedger = forward ? options.ledgerRange.max : findLedger - 1; auto b58acct = toBase58(options.account); - sql = boost::str( - boost::format( - R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq, + sql = std::format( + R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq, Status,RawTxn,TxnMeta FROM AccountTransactions, Transactions WHERE (AccountTransactions.TransID = Transactions.TransID AND - AccountTransactions.Account = '%s' AND - AccountTransactions.LedgerSeq BETWEEN %u AND %u) + AccountTransactions.Account = '{}' AND + AccountTransactions.LedgerSeq BETWEEN {} AND {}) UNION SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta FROM AccountTransactions, Transactions WHERE (AccountTransactions.TransID = Transactions.TransID AND - AccountTransactions.Account = '%s' AND - AccountTransactions.LedgerSeq = %u AND - AccountTransactions.TxnSeq %s %u) - ORDER BY AccountTransactions.LedgerSeq %s, - AccountTransactions.TxnSeq %s - LIMIT %u; - )") % - b58acct % minLedger % maxLedger % b58acct % findLedger % compare % findSeq % order % - order % queryLimit); + AccountTransactions.Account = '{}' AND + AccountTransactions.LedgerSeq = {} AND + AccountTransactions.TxnSeq {} {}) + ORDER BY AccountTransactions.LedgerSeq {}, + AccountTransactions.TxnSeq {} + LIMIT {}; + )", + b58acct, + minLedger, + maxLedger, + b58acct, + findLedger, + compare, + findSeq, + order, + order, + queryLimit); } { diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index efe4ab1cc9..3ff62c9b64 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include // IWYU pragma: keep @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -400,7 +400,7 @@ Config::setup(std::string const& strConf, bool bQuiet, bool bSilent, bool bStand std::filesystem::create_directories(dataDir, ec); if (ec) - Throw(boost::str(boost::format("Can not create %s") % dataDir)); + Throw(std::format("Can not create {}", dataDir.string())); legacy(Sections::kDatabasePath, std::filesystem::absolute(dataDir).string()); } @@ -1315,8 +1315,7 @@ setupDatabaseCon(Config const& c, std::optional j) boost::iequals(journalMode, "truncate") || boost::iequals(journalMode, "persist") || boost::iequals(journalMode, "wal")) { - result->emplace_back( - boost::str(boost::format(kCommonDbPragmaJournal) % journalMode)); + result->emplace_back(commonDbPragmaJournal(journalMode)); } else { @@ -1337,7 +1336,7 @@ setupDatabaseCon(Config const& c, std::optional j) if (higherRisk || boost::iequals(synchronous, "normal") || boost::iequals(synchronous, "full") || boost::iequals(synchronous, "extra")) { - result->emplace_back(boost::str(boost::format(kCommonDbPragmaSync) % synchronous)); + result->emplace_back(commonDbPragmaSync(synchronous)); } else { @@ -1358,7 +1357,7 @@ setupDatabaseCon(Config const& c, std::optional j) if (higherRisk || boost::iequals(tempStore, "default") || boost::iequals(tempStore, "file")) { - result->emplace_back(boost::str(boost::format(kCommonDbPragmaTemp) % tempStore)); + result->emplace_back(commonDbPragmaTemp(tempStore)); } else { diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 4fa0fab6f7..321f8f5a3c 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -424,7 +425,7 @@ parseSubUnsubJson( if (jv.isMember(jss::mpt_issuance_id) && (jv.isMember(jss::currency) || jv.isMember(jss::issuer))) { - JLOG(j.info()) << boost::format("Bad %s currency or MPT.") % name.cStr(); + JLOG(j.info()) << std::format("Bad {} currency or MPT.", name.cStr()); return RpcInvalidParams; } @@ -435,7 +436,7 @@ parseSubUnsubJson( if (!jv.isMember(jss::currency) || !toCurrency(issue.currency, jv[jss::currency].asString())) { - JLOG(j.info()) << boost::format("Bad %s currency.") % name.cStr(); + JLOG(j.info()) << std::format("Bad {} currency.", name.cStr()); return assetError; } @@ -445,7 +446,7 @@ parseSubUnsubJson( // Don't allow illegal issuers. || (!issue.currency != !issue.account) || noAccount() == issue.account) { - JLOG(j.info()) << boost::format("Bad %s issuer.") % name.cStr(); + JLOG(j.info()) << std::format("Bad {} issuer.", name.cStr()); return issuerError; } asset = issue; @@ -459,7 +460,7 @@ parseSubUnsubJson( } else { - JLOG(j.info()) << boost::format("Neither %s currency or MPT is present.") % name.cStr(); + JLOG(j.info()) << std::format("Neither {} currency or MPT is present.", name.cStr()); return assetError; } diff --git a/src/xrpld/rpc/handlers/account/AccountInfo.cpp b/src/xrpld/rpc/handlers/account/AccountInfo.cpp index eed4e4cfe3..6b244af1a9 100644 --- a/src/xrpld/rpc/handlers/account/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/account/AccountInfo.cpp @@ -23,10 +23,9 @@ #include #include -#include - #include #include +#include #include #include #include @@ -60,7 +59,7 @@ injectSLE(json::Value& jv, SLE const& sle) md5 = toLower(md5); // VFALCO TODO Give a name to this constant and move it // to a more visible location. - jv[jss::urlgravatar] = str(boost::format("https://www.gravatar.com/avatar/%s") % md5); + jv[jss::urlgravatar] = std::format("https://www.gravatar.com/avatar/{}", md5); } } diff --git a/src/xrpld/rpc/handlers/orderbook/BookOffers.cpp b/src/xrpld/rpc/handlers/orderbook/BookOffers.cpp index ae539a59f3..219c29d53a 100644 --- a/src/xrpld/rpc/handlers/orderbook/BookOffers.cpp +++ b/src/xrpld/rpc/handlers/orderbook/BookOffers.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -32,7 +33,7 @@ validateTakerJSON(json::Value const& taker, json::StaticString const& name) { if (!taker.isMember(jss::currency) && !taker.isMember(jss::mpt_issuance_id)) { - return rpc::missingFieldError((boost::format("%s.currency") % name.cStr()).str()); + return rpc::missingFieldError(std::format("{}.currency", name.cStr())); } if (taker.isMember(jss::mpt_issuance_id) && @@ -44,8 +45,7 @@ validateTakerJSON(json::Value const& taker, json::StaticString const& name) if ((taker.isMember(jss::currency) && !taker[jss::currency].isString()) || (taker.isMember(jss::mpt_issuance_id) && !taker[jss::mpt_issuance_id].isString())) { - return rpc::expectedFieldError( - (boost::format("%s.currency") % name.cStr()).str(), "string"); + return rpc::expectedFieldError(std::format("{}.currency", name.cStr()), "string"); } return std::nullopt; @@ -70,10 +70,9 @@ parseTakerAssetJSON( if (!toCurrency(issue.currency, taker[jss::currency].asString())) { - JLOG(j.info()) << boost::format("Bad %s currency.") % name.cStr(); + JLOG(j.info()) << std::format("Bad {} currency.", name.cStr()); return rpc::makeError( - assetError, - (boost::format("Invalid field '%s.currency', bad currency.") % name.cStr()).str()); + assetError, std::format("Invalid field '{}.currency', bad currency.", name.cStr())); } asset = issue; } @@ -83,8 +82,7 @@ parseTakerAssetJSON( if (!mptid.parseHex(taker[jss::mpt_issuance_id].asString())) { return rpc::makeError( - assetError, - (boost::format("Invalid field '%s.mpt_issuance_id'") % name.cStr()).str()); + assetError, std::format("Invalid field '{}.mpt_issuance_id'", name.cStr())); } asset = mptid; } @@ -113,24 +111,21 @@ parseTakerIssuerJSON( { if (!taker[jss::issuer].isString()) { - return rpc::expectedFieldError( - (boost::format("%s.issuer") % name.cStr()).str(), "string"); + return rpc::expectedFieldError(std::format("{}.issuer", name.cStr()), "string"); } if (!toIssuer(issue.account, taker[jss::issuer].asString())) { return rpc::makeError( issuerError, - (boost::format("Invalid field '%s.issuer', bad issuer.") % name.cStr()).str()); + std::format("Invalid field '{}.issuer', bad issuer.", name.cStr())); } if (issue.account == noAccount()) { return rpc::makeError( issuerError, - (boost::format("Invalid field '%s.issuer', bad issuer account one.") % - name.cStr()) - .str()); + std::format("Invalid field '{}.issuer', bad issuer account one.", name.cStr())); } } else @@ -142,19 +137,17 @@ parseTakerIssuerJSON( { return rpc::makeError( issuerError, - (boost::format( - "Unneeded field '%s.issuer' for XRP currency " - "specification.") % - name.cStr()) - .str()); + std::format( + "Unneeded field '{}.issuer' for XRP currency " + "specification.", + name.cStr())); } if (!isXRP(issue.currency) && isXRP(issue.account)) { return rpc::makeError( issuerError, - (boost::format("Invalid field '%s.issuer', expected non-XRP issuer.") % name.cStr()) - .str()); + std::format("Invalid field '{}.issuer', expected non-XRP issuer.", name.cStr())); } }